Search code examples
ruby-on-railswebserversidekiq

When to hand off work from web server to worker


I'm trying to solidify my understanding of what blocking means in terms of requests to a web server and when it's smart to hand off requests to a separate worker (i.e. sidekiq).

Consider the following examples:

  1. Login with Facebook

    def sign_in
        response = Faraday.get("https://graph.facebook.com/me?fields=id,email&access_token=#{some_token}")
        user_info = JSON.parse(response.body)
        @user = User.find_by(uid: user_info["id"])
        ...
    end
    
  2. Send push notification through Google Firebase

    def send_push_notification
      ...
      fcm = FCM.new(FCM_KEY)
      registration_ids = [recipient_token]
      resp = fcm.send(registration_ids, data: {body: notification_params[:body]})
      ...
    end
    

In both examples, the web requests to a 3rd-party service are synchronous and possibly costly. Intuitively, I would try to handle these cases with a separate worker because they block the main application. But, I am not 100% sure what blocking means. Does it mean that when there are 100 users trying to sign_in and each Faraday.get call takes 1 second, it will take 100 seconds for all the users to sign in?


Solution

  • Does it mean that when there are 100 users trying to sign_in and each Faraday.get call takes 1 second, it will take 100 seconds for all the users to sign in?

    Simplistic answer: yes.

    In a very simple scenario, the 1st user will wait 1 second, the 2nd user will wait 2 seconds and so on.

    If your application/web server doesn't abort the user request, the 100th user will wait for 100 seconds.

    A bit more detailed: depends.

    Today, modern web applications (like Puma) have more than 1 process worker running in your machine. This means that your application is able to handle more than 1 request concurrently.

    For example: if you have Puma configured to use 2 workers, your application will handle the requests of 2 users at same time.

    Thus, the 1st and 2nd users will wait 1 second, the 3rd and 4th users will wait 2 seconds and the 99th and 100th users will wait 50 seconds.

    As each Puma process consumes a considerable amount of CPU and memory, you cannot have infinite workers. That's why is very interesting have a background process to send these push notifications.

    In Sidekiq (for example) the cost to delegate a job to a worker is extremely slow and thus the users of your website won't be penalized.