Search code examples
sinatraunicorn

How do I run a function in only one thread in a multi-threaded Unicorn Sinatra server?


I put my cron task in a module, and then in my Sinatra server.

module Cron
  scheduler = Rufus::Scheduler.new

  scheduler.every "30m", :first => :now do
    run_cmd('git pull')
    puts "pulled the repo!!!"
  end
end

class MyServer < Sinatra::Base
  include Cron
end

The entry point for the app is unicorn (unicorn config/config.ru -p 9393 -c config/unicorn.rb), and in unicorn.rb, there's this line

worker_processes 7

Because of this, git pull is running seven times every 30 minutes, and pulled the repo!!! is printed seven times.

Is there a way I can run this task only in one thread? I tried putting it in unicorn.rb above worker_processes 7 line but I'm not sure if that's the best place for this code to live in.


Solution

  • Unicorn is a multi-process (not multi-threaded) Rack server. There's no native support for executing a specific code path only in one of the worker processes.

    However, you can work around that by saving the worker number after fork into an environment variable and then checking its value in your application code.

    In config/unicorn.rb use

    after_worker_ready do |server, worker|
      ENV["WORKER_NR"] = worker.nr.to_s
    end
    

    In your Sinatra app do:

    if unicorn_worker_nr == "0"
      scheduler.every "30m", :first => :now do
        ...
      end
    end
    
    def unicorn_worker_nr
      ENV["WORKER_NR"]
    end