I'm writing a nodejs/socket.io application that uses cluster and Redis in AWS Elasticache as the RedisStore backend. The app works heavily around rooms, and i'm having a really hard time understanding why only Mobile Safari (iPad mini retina iOS7 ) cannot leave rooms it subscribes to after it emits a request to do so. Even closing the connection from the client side leaves the socket humming along on the server, and the subscription to the room intact, but other browsers can exit without a problem.
- NodeJS v0.10.25
- Socket.io v0.9.16
- Redis v2.8.6 (AWS Elasticache)
- Ubuntu 14.04 LTS (EC2 behind loadbalancer in TCP mode)
Now, in my code, i've been using the io.sockets.manager.roomClients
object to iterate through and see what rooms are actually in service. This is because io.sockets.clients()
reports completely inaccurate data once connections are opened and closed for a period of time.
My code is really too long to put here, and also fairly private, but here's essentially what i've got:
Server:
if (cluster.isMaster) {
function heartbeat(){
// io.sockets.clients() doesn't splice dropped connections off the array
// so we have to use io.sockets.manager.roomClients to see active rooms
for( var i in io.sockets.manager.roomClients ) {
console.log("Client:", i, io.sockets.manager.roomClients[i] );
}
setTimeout(heartbeat,5000);
}
heartbeat();
} else {
io.sockets.on('connection', function (socket) {
socket.on('subscribe', function (room) {
console.log("Starting:",room);
socket.join(room);
});
socket.on('unsubscribe', function (room) {
console.log("Leaving:",room);
socket.leave(room);
});
socket.on('disconnect', function () {
console.log("Close Shop");
});
});
}
The Client:
socket.emit('subscribe', 'some-room');
Server Log
Starting: some-room
And then i get a Client
log with each timeout tick:
Client: lhZsH1oL2vV7BML9QkSW { '': true, '/some-room': true }
Client: lhZsH1oL2vV7BML9QkSW { '': true, '/some-room': true }
Client: lhZsH1oL2vV7BML9QkSW { '': true, '/some-room': true }
Client: lhZsH1oL2vV7BML9QkSW { '': true, '/some-room': true }
Client: lhZsH1oL2vV7BML9QkSW { '': true, '/some-room': true }
Now, the issue is here. If i unsubscribe or disconnect from a desktop browser:
socket.emit('unsubscribe', 'some-room');
Leaving: some-room
Or
socket.disconnect();
Close Shop
The ticks look like this:
Client: lhZsH1oL2vV7BML9QkSW { '': true }
Which i expect, because as we know, socket.io sucks at connection cleanup, but at least the room subscriptions are gone. However, on my tablet, after unsubscribe or disconnect, the room subscription remains in the io.sockets.manager.roomClients
object:
Client: lhZsH1oL2vV7BML9QkSW { '': true, '/some-room': true }
I'm fairly new at socket programming, so I'm sure i'm missing something obvious, but has anyone had similar issues with Mobile websockets?