faye / faye-websocket-ruby

Standards-compliant WebSocket client and server
Other
1.03k stars 97 forks source link

Create multiple connections in separate threads (for multiple users) #126

Open martinbarilik opened 4 years ago

martinbarilik commented 4 years ago

Another problem we are facing is to create multiple websocket connections for separate users.

Every user has its own settings and has to be able to connect to its own websocket server with client.

What is the problem is the fact user's first thread is merged into second.

ws_logger.info "User##{user.id} started initialization"
threads << Thread.new {
  begin
    EM.run {
      ws = Faye::WebSocket::Client.new('wss://www.bitmex.com/realtime')
      ws.on :open do
        # ... some code
        ws_logger.info "Socket started in ##{Thread.current.object_id}"
      end
      ws.on :message ...
      ws.on :close

      # ...
    }
  ensure
    ws_logger.info "ensured close thread##{Thread.current.object_id}"
  end
}

threads.each do |thread|
  foo.thread_id = thread.object_id
  foo.save!
end

So far so good, output:

User#1 started initialization
Socket started in #76800

And foo.thread_id of user#1 is 76800. But if another user runs the method:

User#2 started initialization
ensured close thread#74500
Socket started in #76800

and user#2 foo.thread_id is 74500. Now both are running in the same thread and if terminate #76800, ws is closed for both users. What is the right way to do it? I even tried EM.defer, but it does the same.

Also, we experience this: https://github.com/faye/faye-websocket-ruby/issues/89 with passenger and nginx + postgresql.

jcoglan commented 4 years ago

By setting up threads yourself, you're working against how EM is supposed to be used. It's a single-threaded reactor, just like JavaScript in the browser, and all I/O is asynchronous. So, if you want to start sockets for a set of users you should do something like this:

EM.run {
  users.each do |user|
    ws_logger.info "User##{user.id} started initialization"

    ws = Faye::WebSocket::Client.new('wss://www.bitmex.com/realtime')

    ws.on :open do
      # ... some code
      ws_logger.info "Socket started in ##{Thread.current.object_id}"
    end

    ws.on :message # ...
    ws.on :close # ...
  end
}