DelayedJobMaster

A simple delayed_job master process to control multiple workers.

Features

  • Preload application and fork workers fastly.
  • Monitor workers and fork new workers if necessary.
  • Restart workers with memory limitation.
  • Trap USR1 signal to reopen log files.
  • Trap USR2 signal to restart master and workers.
  • Auto-scale worker processes.

Dependencies

  • ruby 2.3+
  • delayed_job 4.1

Supported delayed_job backends

  • delayed_job_active_record 4.1
  • delayed_job_mongoid 2.3

Installation

Add this line to your application's Gemfile:

gem 'delayed_job_master', require: false

And then execute:

$ bundle

Create config files:

$ rails generate delayed_job_master:config

This command creates bin/delayed_job_master and config/delayed_job_master.rb.

Configuration

Edit config/delayed_job_master.rb:

# working directory
working_directory Dir.pwd

# monitor wait time in second
monitor_wait 5

# path to pid file
pid_file "#{Dir.pwd}/tmp/pids/delayed_job_master.pid"

# path to log file
log_file "#{Dir.pwd}/log/delayed_job_master.log"

# log level
log_level :info

# worker1
add_worker do |worker|
  # queue name for the worker
  worker.queues %w(queue1)

  # worker control (:static or :dynamic)
  worker.control :static

  # worker count
  worker.count 1

  # max memory in MB
  worker.max_memory 300

  # configs below are same as delayed_job, see https://github.com/collectiveidea/delayed_job
  # worker.sleep_delay 5
  # worker.read_ahead 5
  # worker.max_attempts 25
  # worker.max_run_time 4.hours
  # worker.min_priority 1
  # worker.max_priority 10
end

# worker2
add_worker do |worker|
  worker.queues %w(queue2)
  worker.control :dynamic
  worker.count 2
end

before_fork do |master, worker_info|
  Delayed::Worker.before_fork if defined?(Delayed::Worker)
end

after_fork do |master, worker_info|
  Delayed::Worker.after_fork if defined?(Delayed::Worker)
end

before_monitor do |master|
  ActiveRecord::Base.connection.verify! if defined?(ActiveRecord::Base)
end

after_monitor do |master|
end

Usage

Start master:

$ RAILS_ENV=production bin/delayed_job_master -c config/delayed_job_master.rb -D

Command line options:

  • -c, --config: Specify configuration file.
  • -D, --daemon: Start master as a daemon.

Stop master and workers gracefully:

$ kill -TERM `cat tmp/pids/delayed_job_master.pid`

Stop master and workers forcefully:

$ kill -QUIT `cat tmp/pids/delayed_job_master.pid`

Reopen log files:

$ kill -USR1 `cat tmp/pids/delayed_job_master.pid`

Restart gracefully:

$ kill -USR2 `cat tmp/pids/delayed_job_master.pid`

Workers handle each signal as follows:

  • TERM: Workers stop after finishing current jobs.
  • QUIT: Workers are killed immediately.
  • USR1: Workers reopen log files.
  • USR2: New workers start, old workers stop after finishing current jobs.

Worker status

ps command shows worker status as follows:

$ ps aux
... delayed_job.0 (queue1) [BUSY]  # BUSY process is currently proceeding some jobs

After graceful restart, you may find OLD process.

$ ps aux
... delayed_job.0 (queue1) [BUSY] [OLD]  # OLD process will stop after finishing current jobs.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/kanety/delayed_job_master. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open source under the terms of the MIT License.