Running an extra process inside of sidekiq

Posted on 25 Sep 2014 by Eric Oestrich

For one of my side projects I wanted to have an always on process. I didn't really want to have to set up something like daemon-kit for it as that felt like too much for what this was going to do. I remembered that sidetiq was able to accomplish this and started looking at the source code.

Sidetiq very simply starts running inside the sidekiq process by using celluloid. This was the first time I played with celluloid so it was a good time to start learning about it.

Launching your process inside of sidekiq is easy.

if Sidekiq.server?
  MySupervisor.run!
end

A supervisor simply keeps celluloid actors going if they die. See supervisors for more information. My supervisor looked like:

class MySupervisor < Celluloid::SupervisionGroup
  supervise CelluloidActor, :as => :actor
  supervise OtherCelluloidActor, :as => :other_actor
  supervise Orchestrator, :as => :orchestrator
end

I created an orchestrator actor that does all of the main work for me. It looks at redis and pops messages off a queue as they are entered.

class RemoteOrchestrator
  include Celluloid
  include Celluloid::Logger

  def initialize(redis_pool = AppContainer.redis_connection_pool)
    @redis_pool = redis_pool

    info "Starting orchestrator for remote connections"

    after(1) do
      loop!
    end
  end

  def loop!
    message = connection_pool.with do |redis|
      redis.brpop("requests", :timeout => 5)
    end

    unless message
      async.loop!
      return
    end

    message = JSON.parse(message.last)

    info "Received: #{message.inspect}"

    worker = workers[message["client"]]
    worker.async.process(message["body"])

    async.loop!
  end

  private

  def workers
    @workers ||= {
      "actor" => Celluloid::Actor[:actor],
      "other_actor" => Celluloid::Actor[:other_actor],
    }
  end

  def connection_pool
    @redis_pool
  end
end

The important part about this class is the after(1) call. It queues the block to run in 1 second, which puts it in the background. The actor also loops itself by sending another loop! message async at the end of loop!. This makes sure it will continuing running.

I've run this in my side project for a few months now and I haven't noticed any ill effects.

comments powered by Disqus
Eric Oestrich
I am:
All posts
Creative Commons License
This site's content is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License unless otherwise specified. Code on this site is licensed under the MIT License unless otherwise specified.