Estou tentando criar um site com o django, o apache e o socket.io. Graças a alguns tutoriais e outras perguntas do stackoverflow, consegui fazer tudo funcionar, exceto por um atraso grave, que ocorre quando envio várias mensagens do socket.io dentro de um curto período de tempo.
Estou executando um servidor node.js socket.io atrás de um proxy configurado no Apache. As mensagens enviadas dos clientes socket.io para o servidor socket.io, também serão encaminhadas para o django, onde eu quero registrar o manipulador de eventos. Por exemplo, eu quero disparar um evento, toda vez que um cliente entra em uma determinada sala, para enviar alguns dados iniciais através do socket.io.
O Django também pode enviar pedidos para o servidor socket.io, para acionar eventos socket.io (como emit), para enviar mensagens para todos ou determinados clientes socket.io.
Para enviar e receber mensagens socket.io, eu uso http long polling.
Esta mensagem encaminhando para o django, parece retardar bastante a comunicação do socket.io. Por exemplo, eu implementei um simples echo sever que funciona assim:
client --- send message
- > proxy do apache - > servidor socket.io --- http POST
--- > Django - > manipulador de eventos (para enviar a mensagem de volta ao cliente) --- http POST
--- > servidor socket.io - > proxy do apache - > cliente
Isso funciona bem, se eu enviar apenas uma mensagem. Mas se eu enviar muitas mensagens, dentro de um curto período de tempo, haverá um atraso cada vez maior. Se eu enviar apenas 10 mensagens seguidas, haverá um atraso total de cerca de 5 segundos até que a última mensagem de eco retorne ao cliente. Se eu enviar ainda mais mensagens, recebo o efeito de que sempre 3-4 mensagens de eco serão recebidas consecutivamente. Depois disso, há uma pausa de cerca de 2 segundos até que o próximo crachá chegue.
Isso não acontece, se eu não encaminhar mensagens para o django, mas enviar o eco diretamente para dentro do servidor socket.io.
É claro que é de se esperar que esse componente adicional atrase um pouco as coisas, mas esse atraso parece ser bastante severo.
Então, o que eu fiz de errado? Talvez minha abordagem para encaminhar mensagens para o django seja inerentemente errada? Ou existem algumas configurações que eu possa ajustar para acelerar as coisas? E de onde vem essa defasagem?
Apache 2.4.7
host virtual:
<VirtualHost *:80>
ServerName www.example.com
ProxyRequests off
ProxyPass /socket.io http://localhost:8080/socket.io retry=0
ProxyPassReverse /socket.io http://localhost:8080/socket.io
WSGIDaemonProcess www.example.com processes=1 threads=1 display-name=%{GROUP}
WSGIProcessGroup www.example.com
WSGIScriptAlias / /path/to/wsgi.py
DocumentRoot /var/www/example.com/
</VirtualHost>
Servidor Node.js
server.js
app = express();
server = http.Server(app);
io = require("socket.io")(server);
server.listen(8080);
app.use(express.bodyParser());
// incoming emit from django will emit a message over socket.io
app.post("/emit/", function (req, res) {
var body = req.body,
message = body.message;
io.emit("message", message);
res.send("everything is ok");
});
// forwarding incoming socket.io message to django
function forward(type, data, sessionId) {
var options, req;
data.sessionid = sessionId;
data = JSON.stringify(data);
console.log(data);
options = {
rejectUnauthorized: false,
host: "www.example.com",
port: 80,
path: "/socket/" + type + "/",
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": data.length
}
};
req = http.request(options, function(res){
res.setEncoding("utf8");
});
req.write(data);
req.end();
}
io.sockets.on("connection", function (socket) {
var sessionId = socket.id;
forward("connect", {}, sessionId);
socket.on("disconnect", function () {
forward("disconnect", {}, sessionId);
});
socket.on("message", function(message) {
forward("message", { message: message }, sessionId);
});
socket.on("join", function (room) {
socket.join(room);
forward("join", { room: room }, sessionId);
});
socket.on("leave", function (room) {
socket.leave(room);
forward("leave", { room: room }, sessionId);
});
});
Django
encaminhar mensagem para socket.io
def emit(message):
payload = {"message": message}
headers = {"content-type": "application/json"}
requests.post("http://127.0.0.1:8080/emit/", data=json.dumps(payload, cls=DjangoJSONEncoder), headers=headers, verify=False)
vista para lidar com mensagens socket.io:
class MessageView(View):
def post(self, request, *args, **kwargs):
data = json.loads(request.body)
try:
sessionid = data["sessionid"]
message = data["message"]
//fire function will trigger event handler
fire("message", sessionid, {"message": message})
return HttpResponse("Everything worked :)")
except Exception, e:
return HttpResponseServerError(str(e))
@csrf_exempt
def dispatch(self, *args, **kwargs):
return super(MessageView, self).dispatch(*args, **kwargs)
registre um manipulador de eventos de mensagem:
@on_message
def message_received(sessionid, data):
//emit to all socket.io clients
emit("someone has sent a message")
Cliente
io.js
socket = io.connect(
"http://www.example.com:80",
{
"multiplex": false,
"transports": ["polling", "xhr-polling", "jsonp-polling"]
}
);
O gráfico a seguir também deve ilustrar como pretendi que os componentes individuais se comunicassem entre si.