Refactor demonizer in prep for unicorn forking

Upgrade sidekiq
This commit is contained in:
Sam 2014-04-17 15:57:17 +10:00
parent a7c41e6512
commit ead7c52a06
7 changed files with 76 additions and 38 deletions

View File

@ -140,7 +140,10 @@ gem 'rinku'
gem 'sanitize' gem 'sanitize'
gem 'sass' gem 'sass'
gem 'sidekiq' gem 'sidekiq'
gem 'sidekiq-failures'
# https://github.com/mhfs/sidekiq-failures/issues/72
gem 'sidekiq-failures-discourse', require: 'sidekiq-failures'
gem 'sinatra', require: nil gem 'sinatra', require: nil
gem 'slim' # required for sidekiq-web gem 'slim' # required for sidekiq-web

View File

@ -62,7 +62,7 @@ GEM
timers (~> 1.1.0) timers (~> 1.1.0)
certified (0.1.1) certified (0.1.1)
coderay (1.1.0) coderay (1.1.0)
connection_pool (1.2.0) connection_pool (2.0.0)
daemons (1.1.9) daemons (1.1.9)
debug_inspector (0.0.2) debug_inspector (0.0.2)
diff-lcs (1.2.5) diff-lcs (1.2.5)
@ -324,7 +324,7 @@ GEM
json json
redis (>= 3.0.6) redis (>= 3.0.6)
redis-namespace (>= 1.3.1) redis-namespace (>= 1.3.1)
sidekiq-failures (0.3.0) sidekiq-failures-discourse (0.3.0)
sidekiq (>= 2.14.0) sidekiq (>= 2.14.0)
simple-rss (1.3.1) simple-rss (1.3.1)
simplecov (0.8.2) simplecov (0.8.2)
@ -464,7 +464,7 @@ DEPENDENCIES
seed-fu-discourse seed-fu-discourse
shoulda shoulda
sidekiq sidekiq
sidekiq-failures sidekiq-failures-discourse
simple-rss simple-rss
simplecov simplecov
sinatra sinatra

View File

@ -3,7 +3,7 @@ module Demon; end
# intelligent fork based demonizer # intelligent fork based demonizer
class Demon::Base class Demon::Base
def self.start(count) def self.start(count=1)
@demons ||= {} @demons ||= {}
count.times do |i| count.times do |i|
(@demons["#{prefix}_#{i}"] ||= new(i)).start (@demons["#{prefix}_#{i}"] ||= new(i)).start
@ -17,11 +17,17 @@ class Demon::Base
end end
end end
def self.ensure_running
@demons.values.each do |demon|
demon.ensure_running
end
end
def initialize(index) def initialize(index)
@index = index @index = index
@pid = nil @pid = nil
@parent_pid = Process.pid @parent_pid = Process.pid
@monitor = nil @started = false
end end
def pid_file def pid_file
@ -29,29 +35,47 @@ class Demon::Base
end end
def stop def stop
if @monitor @started = false
@monitor.kill
@monitor.join
@monitor = nil
end
if @pid if @pid
Process.kill("HUP",@pid) Process.kill("HUP",@pid)
@pid = nil @pid = nil
end end
end end
def ensure_running
return unless @started
if !@pid
@started = false
start
return
end
dead = Process.waitpid(@pid, Process::WNOHANG) rescue -1
if dead
STDERR.puts "Detected dead worker #{@pid}, restarting..."
@pid = nil
@started = false
start
end
end
def start def start
return if @pid || @started
if existing = already_running? if existing = already_running?
# should not happen ... so kill violently # should not happen ... so kill violently
STDERR.puts "Attempting to kill pid #{existing}"
Process.kill("TERM",existing) Process.kill("TERM",existing)
end end
return if @pid @started = true
run
end
def run
if @pid = fork if @pid = fork
write_pid_file write_pid_file
monitor_child
return return
end end
@ -73,19 +97,6 @@ class Demon::Base
private private
def monitor_child
@monitor ||= Thread.new do
while true
sleep 5
unless alive?(@pid)
STDERR.puts "#{@pid} died, restarting the process"
@pid = nil
start
end
end
end
end
def write_pid_file def write_pid_file
FileUtils.mkdir_p(Rails.root + "tmp/pids") FileUtils.mkdir_p(Rails.root + "tmp/pids")
File.open(pid_file,'w') do |f| File.open(pid_file,'w') do |f|
@ -110,13 +121,21 @@ class Demon::Base
def alive?(pid) def alive?(pid)
begin begin
Process.getpgid(pid) Process.kill(0, pid)
true true
rescue Errno::ESRCH rescue
false false
end end
end end
def suppress_stdout
true
end
def suppress_stderr
true
end
def establish_app def establish_app
Discourse.after_fork Discourse.after_fork
@ -129,8 +148,8 @@ class Demon::Base
end end
# keep stuff simple for now # keep stuff simple for now
$stdout.reopen("/dev/null", "w") $stdout.reopen("/dev/null", "w") if suppress_stdout
$stderr.reopen("/dev/null", "w") $stderr.reopen("/dev/null", "w") if suppress_stderr
end end
def after_fork def after_fork

View File

@ -8,12 +8,21 @@ class Demon::Sidekiq < Demon::Base
private private
def suppress_stdout
false
end
def suppress_stderr
false
end
def after_fork def after_fork
STDERR.puts "Loading Sidekiq in process id #{Process.pid}"
require 'sidekiq/cli' require 'sidekiq/cli'
# Reload initializer cause it needs to run after sidekiq/cli was required
load Rails.root + "config/initializers/sidekiq.rb"
cli = Sidekiq::CLI.instance cli = Sidekiq::CLI.instance
cli.parse([]) cli.parse([])
load Rails.root + "config/initializers/sidekiq.rb"
cli.run cli.run
rescue => e rescue => e
STDERR.puts e.message STDERR.puts e.message

View File

@ -4,6 +4,7 @@ require_dependency 'auth/default_current_user_provider'
module Discourse module Discourse
require 'sidekiq/exception_handler'
class SidekiqExceptionHandler class SidekiqExceptionHandler
extend Sidekiq::ExceptionHandler extend Sidekiq::ExceptionHandler
end end

View File

@ -229,9 +229,17 @@ module Scheduler
def self.discover_schedules def self.discover_schedules
# hack for developemnt reloader is crazytown
# multiple classes with same name can be in
# object space
unique = Set.new
schedules = [] schedules = []
ObjectSpace.each_object(Scheduler::Schedule) do |schedule| ObjectSpace.each_object(Scheduler::Schedule) do |schedule|
schedules << schedule if schedule.scheduled? if schedule.scheduled?
next if unique.include?(schedule.to_s)
schedules << schedule
unique << schedule.to_s
end
end end
schedules schedules
end end

View File

@ -10,7 +10,6 @@ module Scheduler
@klass = klass @klass = klass
@manager = manager @manager = manager
key = Manager.schedule_key(klass)
data = nil data = nil
if data = $redis.get(key) if data = $redis.get(key)
@ -85,7 +84,6 @@ module Scheduler
end end
def write! def write!
key = Manager.schedule_key(@klass)
clear! clear!
redis.set key, { redis.set key, {
next_run: @next_run, next_run: @next_run,
@ -94,6 +92,7 @@ module Scheduler
prev_result: @prev_result, prev_result: @prev_result,
current_owner: @current_owner current_owner: @current_owner
}.to_json }.to_json
redis.zadd Manager.queue_key, @next_run , @klass redis.zadd Manager.queue_key, @next_run , @klass
end end
@ -112,9 +111,8 @@ module Scheduler
private private
def clear! def clear!
key = Manager.schedule_key(@klass)
redis.del key redis.del key
redis.zrem Manager.queue_key, key redis.zrem Manager.queue_key, @klass
end end
end end