code: private void doClose() {
      super.close(); // We must call this or handlers don't get unregistered and we get a leak
      if (heartbeatID != -1) {
        vertx.cancelTimer(heartbeatID);
      }
      if (timeoutTimerID != -1) {
        vertx.cancelTimer(timeoutTimerID);
      }
      if (id != null) {
        // Can be null if websocket session
        sessions.remove(id);
      }
  
      if (!closed) {
        closed = true;
        if (endHandler != null) {
          endHandler.handle(null);
        }
      }
    }
docs: Yes, I know it's weird but that's the way SockJS likes it.