Skip to content

Race condition with dynamic namespaces #4136

Closed
@sebamarynissen

Description

@sebamarynissen

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions