Description
I have noticed that a race condition exists with dynamic namespaces. Consider the following setup
// Server side
import { Server } from 'socket.io';
const io = new Server(3000, {});
io.of(async (nsp, auth, next) => {
let exists = !!await queryDatabaseForResource({});
next(null, exists);
});
If the query to the database takes some time and a lot of clients are trying to connect to the same namespace in a short period of time, the namespace will be created multiple times. This will result in sockets being connected to a namespace that is overridden by another one, and hence they will no longer be receiving events.
Looking at Server.prototype._checkNamespace
, I think this can be solved as follows:
Server.prototype._checkNamespace = function(name, auth, fn) {
if (this.parentNsps.size === 0) return fn(false);
const keysIterator = this.parentNsps.keys();
const run = () => {
const nextFn = keysIterator.next();
if (nextFn.done) return fn(false);
nextFn.value(name, auth, (err, allow) => {
if (err || !allow) {
run();
} else if (this._nsps.has(name)) {
// If the namespace has been created in the meantime, do not create it again.
return fn(this._nsps.get(name));
} else {
const namespace = this.parentNsps
.get(nextFn.value)
.createChild(name);
this.sockets.emitReserved('new_namespace', namespace);
fn(namespace);
}
});
};
run();
};
I will file a PR to solve this.
Context
The odds of this race condition happening are obviously rather low, but I experienced them on a website of mine where I organize tournaments. If the tournament starts, people are all sent to a socket.io namespace where their match is hosted. These namespaces are created dynamically, and so it happens that a large amount of people tries to connect at the same moment.