     is_running: () =>
         return @_socket?
 
+    # NOTE: There can be many simultaneous init_socket calls at the same time,
+    # if e.g., the socket doesn't exist and there are a bunch of calls to @call
+    # at the same time.
+    # See https://github.com/sagemathinc/cocalc/issues/3506
     init_socket: (cb) =>
         dbg = @dbg('init_socket()')
         dbg()
-        exports.get_sage_socket (err, socket) =>
+        if @_init_socket_cbs?
+            @_init_socket_cbs.push(cb)
+            return
+        @_init_socket_cbs = [cb]
+        get_sage_socket (err, socket) =>
             if err
                 dbg("fail -- #{err}.")
-                cb(err)
+                cbs = @_init_socket_cbs
+                delete @_init_socket_cbs
+                for c in cbs
+                    c(err)
                 return
 
             dbg("successfully opened a sage session")

# Get a new connection to the Sage server.  If the server
# isn't running, e.g., it was killed due to running out of memory,
# attempt to restart it and try to connect.
exports.get_sage_socket = (cb) ->   # cb(err, socket)
    socket = undefined
    try_to_connect = (cb) ->
        _get_sage_socket (err, _socket) ->

                dbg("sage session: received message #{type}")
                @["_handle_mesg_#{type}"]?(mesg)

            @_init_path (err) =>
                cbs = @_init_socket_cbs
                delete @_init_socket_cbs
                for c in cbs
                    c(err)

    _init_path: (cb) =>
        dbg = @dbg("_init_path()")
