Skip to content

Instantly share code, notes, and snippets.

@dnagir
Created November 12, 2012 00:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dnagir/4056879 to your computer and use it in GitHub Desktop.
Save dnagir/4056879 to your computer and use it in GitHub Desktop.
Scheduler as worker
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
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
#!/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!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment