public
Created

Scheduler as worker

  • Download Gist
background_worker_starter.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
class BackgroundWorkerStarter
attr_reader :env
 
def initialize(env)
@env = env
end
 
def start!
write_pid!(pid_file) if pid_file
 
# This is supposed to be executed from the bash script directly, so do the heavy-lifting of loading env lazily
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
require_relative "./scheduler"
 
# The very first worker also becomes a scheduler
Scheduler.start! if worker_number == 0
 
# 0, 1 etc
case worker_number
when 1 then run(queues: ['default', 'slow']) # worker #1 takes 'slow' queue
else
run(queues: ['default']) # Exclude 'slow' queue to have enough capacity if that one is very busy
end
end
 
private
 
def write_pid!(file)
File.open(file, 'w') { |f| f << Process.pid }
end
 
def run(options={})
# From https://github.com/collectiveidea/delayed_job/blob/master/lib/delayed/command.rb#L93
Dir.chdir(Rails.root)
Delayed::Worker.logger = Logger.new(File.join(Rails.root, 'log', 'delayed_job.log'))
 
worker = Delayed::Worker.new(options)
worker.name = worker_identifier
worker.say "Worker with options is about to start: #{options.inspect}"
worker.start
rescue => e
Rails.logger.fatal e
STDERR.puts e.message
exit 1
end
 
def pid_file
env['PIDFILE']
end
 
def worker_identifier
# /path/to/worker-1.pid => worker-1
matching = pid_file.to_s.match(/([^\/]+)\.pid$/)
matching ? matching[1] : 'not-available-0'
end
 
def worker_number
worker_identifier.gsub(/\D/, '').to_i
end
end
scheduler.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
class Scheduler
def initialize
require 'rufus/scheduler'
 
regularly do
Jobs::RetireOverdueReservations.delay.run
Jobs::NewReservationNotification.delay.run
Jobs::CancelledReservationNotification.delay.run
end
 
nightly do
Jobs::CleanupImports.delay.run
Jobs::CleanupReports.delay.run
end
end
 
def self.start!
new.tap { |s| s.scheduler.start }
end
 
def scheduler
@scheduler ||= Rufus::Scheduler::PlainScheduler.new(frequency: 0.5)
end
 
private
 
def with_resources(&block)
block.call
ensure
# The scheduler runs in a separate Thread thus AR opens a new connection.
# So we need to make sure it gets closed at the end.
ActiveRecord::Base.connection.close
end
 
def regularly(&block)
# every 10 mins
scheduler.every('10m') { with_resources(&block) }
end
 
def nightly(&block)
# daily, 3am
scheduler.cron("0 3 * * *") { with_resources(&block) }
end
end
script-slash-worker
Ruby
1 2 3 4 5 6 7 8
#!/usr/bin/env ruby
# encoding: utf-8
 
# For now, just preserving the ability to use monit from
# chef/custom_cookbooks/background_server/templates.default/monit.conf.erb
 
require_relative './../lib/background_worker_starter'
BackgroundWorkerStarter.new(ENV).start!

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.