1
0
Fork 0
mirror of https://github.com/mperham/sidekiq.git synced 2022-11-09 13:52:34 -05:00
mperham--sidekiq/lib/sidekiq/server.rb

124 lines
2.6 KiB
Ruby
Raw Normal View History

2012-01-22 16:01:46 -08:00
require 'celluloid'
require 'redis'
require 'multi_json'
require 'sidekiq/util'
2012-01-22 16:01:46 -08:00
require 'sidekiq/worker'
2012-01-16 16:14:47 -08:00
module Sidekiq
##
2012-01-22 11:32:38 -08:00
# This is the main router in the system. This
# manages the worker state and fetches messages
# from Redis to be dispatched to ready workers.
2012-01-16 16:14:47 -08:00
#
class Server
2012-01-22 11:32:38 -08:00
include Util
2012-01-16 20:02:58 -08:00
include Celluloid
2012-01-16 16:18:36 -08:00
2012-01-22 11:32:38 -08:00
trap_exit :worker_died
2012-01-16 20:02:58 -08:00
def initialize(location, options={})
2012-01-23 22:08:38 -08:00
log "Booting sidekiq #{Sidekiq::VERSION} with Redis at #{location}"
2012-01-22 16:01:46 -08:00
verbose options.inspect
2012-01-22 11:32:38 -08:00
@count = options[:worker_count]
@queues = options[:queues]
@queue_idx = 0
@queues_size = @queues.size
@redis = Redis.connect(:url => location)
2012-01-22 11:32:38 -08:00
2012-01-22 16:01:46 -08:00
@done = false
@busy = []
@ready = []
@count.times do
2012-01-23 22:08:38 -08:00
@ready << Worker.new_link(current_actor)
2012-01-22 16:01:46 -08:00
end
2012-01-22 11:32:38 -08:00
end
def stop
@done = true
@ready.each(&:terminate)
@ready.clear
after(5) do
signal(:shutdown)
2012-01-22 11:32:38 -08:00
end
end
def start
2012-01-23 22:08:38 -08:00
dispatch(true)
2012-01-22 11:32:38 -08:00
end
2012-01-16 16:18:36 -08:00
2012-01-22 11:32:38 -08:00
def worker_done(worker)
2012-01-22 16:01:46 -08:00
@busy.delete(worker)
2012-01-22 11:32:38 -08:00
if stopped?
worker.terminate
else
@ready << worker
2012-01-16 20:02:58 -08:00
end
2012-01-22 11:32:38 -08:00
dispatch
2012-01-16 16:18:36 -08:00
end
2012-01-16 20:02:58 -08:00
2012-01-22 11:32:38 -08:00
def worker_died(worker, reason)
2012-01-22 16:01:46 -08:00
@busy.delete(worker)
if reason
log "Worker death: #{reason}"
log reason.backtrace.join("\n")
end
2012-01-22 16:01:46 -08:00
unless stopped?
2012-01-23 22:08:38 -08:00
@ready << Worker.new_link(current_actor)
2012-01-22 16:01:46 -08:00
dispatch
end
2012-01-22 11:32:38 -08:00
end
2012-01-22 16:01:46 -08:00
private
2012-01-23 22:08:38 -08:00
def find_work(queue_idx)
current_queue = @queues[queue_idx]
msg = @redis.lpop("queue:#{current_queue}")
if msg
worker = @ready.pop
@busy << worker
worker.process! MultiJson.decode(msg)
end
msg
end
def dispatch(schedule = false)
2012-01-22 11:32:38 -08:00
watchdog("Fatal error in sidekiq, dispatch loop died") do
return if stopped?
# Our dispatch loop
2012-01-23 22:08:38 -08:00
# Loop through the queues, looking for a message in each.
2012-01-22 11:32:38 -08:00
queue_idx = 0
2012-01-23 22:08:38 -08:00
found = false
2012-01-22 11:32:38 -08:00
loop do
2012-01-22 16:01:46 -08:00
# return so that we don't dispatch again until worker_done
2012-01-23 22:08:38 -08:00
break verbose('no workers') if @ready.size == 0
2012-01-22 11:32:38 -08:00
2012-01-23 22:08:38 -08:00
found ||= find_work(queue_idx)
2012-01-22 11:32:38 -08:00
queue_idx += 1
# if we find no messages in any of the queues, we can break
# out of the loop. Otherwise we loop again.
2012-01-22 16:01:46 -08:00
lastq = (queue_idx % @queues.size == 0)
2012-01-23 22:08:38 -08:00
if lastq && !found
verbose('nothing to process'); break
2012-01-22 16:01:46 -08:00
elsif lastq
2012-01-22 11:32:38 -08:00
queue_idx = 0
2012-01-23 22:08:38 -08:00
found = false
2012-01-22 11:32:38 -08:00
end
end
2012-01-23 22:08:38 -08:00
after(1) { verbose('ping'); dispatch(schedule) } if schedule
2012-01-22 11:32:38 -08:00
end
end
def stopped?
@done
end
2012-01-16 16:14:47 -08:00
end
end