jondot/sneakers

Object variables in multithreaded Sneaker works like a global mutable data

Ronaq13 opened this issue · 1 comments

I have a sneaker worker(given below) as a backend of a chatbot.

  class RabbitMQWorker
    include Sneakers::Worker

    from_queue "message"

    def work(options)
      parsed_options = JSON.parse(options)

      # Initializing some object variables
      @question_id = parsed_options[:question_id]
      @answer = parsed_option[:answer]
      @session_id = parsed_option[:session_id]


      ActiveRecord::Base.connection_pool.with_connection do
        # send next question to the session_id based on answer
      end

      ack!
    end
  end

What's happening

The problem I am facing here is that when I run sneaker with more than 1 thread and multiple users are chatting at the same time, then the ampq event which comes slightly later cause to override the @session_id and as a result, the second user gets two questions and the first one gets none. This happens because by the time 1st event is getting process the second event came and override @session_id. Now when it's time to send the next question to the first user by using @session_id, the question get's send to the second user.

My Questions

  1. Do the work method and any instance variables I create in it works like global mutable data for sneaker's threads?
  2. If yes then I am guessing I need to make them as thread-local variables. If I do that, then do I need to make these changes deep down in my Rails logic as well? As this worker works with Rails.

Curiosity question

How does Puma manage these things? It is a multi-threaded app server and we use instance variables in controllers and it manages to serve multiple requests simultaneously. Does it mean that Puma handles this multi-contexting implicitly and Sneakers don't?

What I have done till now

  1. I read the documentation of Sneaker and couldn't found anything regarding this.
  2. I perform load tests to verify the problem and it is the problem as I stated above.
  3. I tried getting my logic clear on how actually multi-threading works but everywhere there is only general stuff. The curiosity question I asked above will help a lot in terms of clearing the concepts, I am searching for an explanation of it for days but couldn't found any.

Any naturally shared mutable state in your consumer/worker code will be shared by Sneakers threads. How to use thread-local variables or other concurrency primitives in Ruby is a great question for the Ruby mailing list, there isn't anything Sneakers-specific about that.