docs: function (msg_in) {
      var self = this;
      if (!self.inQueue) // we have been destroyed.
        return;
  
      // Respond to ping and pong messages immediately without queuing.
      // If the negotiated DDP version is "pre1" which didn't support
      // pings, preserve the "pre1" behavior of responding with a "bad
      // request" for the unknown messages.
      //
      // Fibers are needed because heartbeat uses Meteor.setTimeout, which
      // needs a Fiber. We could actually use regular setTimeout and avoid
      // these new fibers, but it is easier to just make everything use
      // Meteor.setTimeout and not think too hard.
      if (self.version !== 'pre1' && msg_in.msg === 'ping') {
        if (self._respondToPings)
          self.send({msg: "pong", id: msg_in.id});
        if (self.heartbeat)
          Fiber(function () {
            self.heartbeat.pingReceived();
          }).run();
        return;
      }
      if (self.version !== 'pre1' && msg_in.msg === 'pong') {
        if (self.heartbeat)
          Fiber(function () {
            self.heartbeat.pongReceived();
          }).run();
        return;
      }
  
      self.inQueue.push(msg_in);
      if (self.workerRunning)
        return;
      self.workerRunning = true;
  
      var processNext = function () {
        var msg = self.inQueue && self.inQueue.shift();
        if (!msg) {
          self.workerRunning = false;
          return;
        }
  
        Fiber(function () {
          var blocked = true;
  
          var unblock = function () {
            if (!blocked)
              return; // idempotent
            blocked = false;
            processNext();
          };
  
          if (_.has(self.protocol_handlers, msg.msg))
            self.protocol_handlers[msg.msg].call(self, msg, unblock);
          else
            self.sendError('Bad request', msg);
          unblock(); // in case the handler didn't already do it
        }).run();
      };
  
      processNext();
    }