Skip to content

Commit

Permalink
Create global GoodJob.configuration object
Browse files Browse the repository at this point in the history
  • Loading branch information
bensheldon committed Jul 26, 2022
1 parent d67d677 commit c7ab74d
Show file tree
Hide file tree
Showing 9 changed files with 43 additions and 28 deletions.
11 changes: 8 additions & 3 deletions lib/good_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ module GoodJob
# @return [Proc, nil]
mattr_accessor :on_thread_error, default: nil

# @!attribute [rw] configuration
# @!scope class
# Global configuration object for GoodJob.
# @return [GoodJob::Configuration, nil]
mattr_accessor :configuration, default: GoodJob::Configuration.new({})

# Called with exception when a GoodJob thread raises an exception
# @param exception [Exception] Exception that was raised
# @return [void]
Expand Down Expand Up @@ -135,10 +141,9 @@ def self._shutdown_all(executables, method_name = :shutdown, timeout: -1)
# @params older_than [nil,Numeric,ActiveSupport::Duration] Jobs older than this will be destroyed (default: +86400+).
# @return [Integer] Number of jobs that were destroyed.
def self.cleanup_preserved_jobs(older_than: nil)
configuration = GoodJob::Configuration.new({})
older_than ||= configuration.cleanup_preserved_jobs_before_seconds_ago
older_than ||= GoodJob.configuration.cleanup_preserved_jobs_before_seconds_ago
timestamp = Time.current - older_than
include_discarded = configuration.cleanup_discarded_jobs?
include_discarded = GoodJob.configuration.cleanup_discarded_jobs?

ActiveSupport::Notifications.instrument("cleanup_preserved_jobs.good_job", { older_than: older_than, timestamp: timestamp }) do |payload|
old_jobs = GoodJob::Job.where('finished_at <= ?', timestamp)
Expand Down
24 changes: 13 additions & 11 deletions lib/good_job/adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class Adapter
# @return [Array<GoodJob::Adapter>, nil]
cattr_reader :instances, default: [], instance_reader: false

attr_reader :execution_mode

# @param execution_mode [Symbol, nil] specifies how and where jobs should be executed. You can also set this with the environment variable +GOOD_JOB_EXECUTION_MODE+.
#
# - +:inline+ executes jobs immediately in whatever process queued them (usually the web server process). This should only be used in test and development environments.
Expand All @@ -25,8 +27,8 @@ class Adapter
# - +production+ and all other environments: +:external+
#
def initialize(execution_mode: nil)
@configuration = GoodJob::Configuration.new({ execution_mode: execution_mode })
@configuration.validate!
@execution_mode = (execution_mode || GoodJob.configuration.execution_mode).to_sym
GoodJob::Configuration.validate_execution_mode(@execution_mode)
self.class.instances << self

start_async if GoodJob.async_ready?
Expand Down Expand Up @@ -82,7 +84,7 @@ def enqueue_at(active_job, timestamp)
# @return [void]
def shutdown(timeout: :default)
timeout = if timeout == :default
@configuration.shutdown_timeout
GoodJob.configuration.shutdown_timeout
else
timeout
end
Expand All @@ -95,21 +97,21 @@ def shutdown(timeout: :default)
# Whether in +:async+ execution mode.
# @return [Boolean]
def execute_async?
@configuration.execution_mode == :async_all ||
(@configuration.execution_mode.in?([:async, :async_server]) && in_server_process?)
execution_mode == :async_all ||
(execution_mode.in?([:async, :async_server]) && in_server_process?)
end

# Whether in +:external+ execution mode.
# @return [Boolean]
def execute_externally?
@configuration.execution_mode == :external ||
(@configuration.execution_mode.in?([:async, :async_server]) && !in_server_process?)
execution_mode == :external ||
(execution_mode.in?([:async, :async_server]) && !in_server_process?)
end

# Whether in +:inline+ execution mode.
# @return [Boolean]
def execute_inline?
@configuration.execution_mode == :inline
execution_mode == :inline
end

# Start async executors
Expand All @@ -118,12 +120,12 @@ def start_async
return unless execute_async?

@notifier = GoodJob::Notifier.new
@poller = GoodJob::Poller.new(poll_interval: @configuration.poll_interval)
@scheduler = GoodJob::Scheduler.from_configuration(@configuration, warm_cache_on_initialize: true)
@poller = GoodJob::Poller.new(poll_interval: GoodJob.configuration.poll_interval)
@scheduler = GoodJob::Scheduler.from_configuration(GoodJob.configuration, warm_cache_on_initialize: true)
@notifier.recipients << [@scheduler, :create_thread]
@poller.recipients << [@scheduler, :create_thread]

@cron_manager = GoodJob::CronManager.new(@configuration.cron_entries, start_on_initialize: true) if @configuration.enable_cron?
@cron_manager = GoodJob::CronManager.new(GoodJob.configuration.cron_entries, start_on_initialize: true) if GoodJob.configuration.enable_cron?

@_async_started = true
end
Expand Down
8 changes: 4 additions & 4 deletions lib/good_job/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ def exit_on_failure?

def start
set_up_application!
configuration = GoodJob::Configuration.new(options)
GoodJob.configuration.options.merge!(options.symbolize_keys)
configuration = GoodJob.configuration

Daemon.new(pidfile: configuration.pidfile).daemonize if configuration.daemonize?

Expand Down Expand Up @@ -142,10 +143,9 @@ def start

def cleanup_preserved_jobs
set_up_application!
GoodJob.configuration.options.merge!(options.symbolize_keys)

configuration = GoodJob::Configuration.new(options)

GoodJob.cleanup_preserved_jobs(older_than: configuration.cleanup_preserved_jobs_before_seconds_ago)
GoodJob.cleanup_preserved_jobs(older_than: GoodJob.configuration.cleanup_preserved_jobs_before_seconds_ago)
end

no_commands do
Expand Down
7 changes: 6 additions & 1 deletion lib/good_job/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ class Configuration
# Default to not running cron
DEFAULT_ENABLE_CRON = false

def self.validate_execution_mode(execution_mode)
raise ArgumentError, "GoodJob execution mode must be one of #{EXECUTION_MODES.join(', ')}. It was '#{execution_mode}' which is not valid." unless execution_mode.in?(EXECUTION_MODES)
end

# The options that were explicitly set when initializing +Configuration+.
# It is safe to modify this hash in place; be sure to symbolize keys.
# @return [Hash]
attr_reader :options

Expand All @@ -47,7 +52,7 @@ def initialize(options, env: ENV)
end

def validate!
raise ArgumentError, "GoodJob execution mode must be one of #{EXECUTION_MODES.join(', ')}. It was '#{execution_mode}' which is not valid." unless execution_mode.in?(EXECUTION_MODES)
self.class.validate_execution_mode(execution_mode)
end

# Specifies how and where jobs should be executed. See {Adapter#initialize}
Expand Down
2 changes: 1 addition & 1 deletion lib/models/good_job/cron_entry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class CronEntry
attr_reader :params

def self.all(configuration: nil)
configuration ||= GoodJob::Configuration.new({})
configuration ||= GoodJob.configuration
configuration.cron_entries
end

Expand Down
2 changes: 1 addition & 1 deletion spec/app/jobs/example_job_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@

describe "SLOW_TYPE" do
it 'sleeps for period' do
expect_any_instance_of(Object).to receive(:sleep)
expect_any_instance_of(described_class).to receive(:sleep)

active_job = described_class.perform_later(described_class::SLOW_TYPE)

Expand Down
6 changes: 6 additions & 0 deletions spec/lib/good_job/adapter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
let(:good_job) { instance_double(GoodJob::Execution, queue_name: 'default', scheduled_at: nil) }

describe '#initialize' do
it 'uses the global configuration value' do
allow(GoodJob.configuration).to receive(:execution_mode).and_return(:external)
adapter = described_class.new
expect(adapter.execution_mode).to eq(:external)
end

it 'guards against improper execution modes' do
expect do
described_class.new(execution_mode: :blarg)
Expand Down
8 changes: 3 additions & 5 deletions spec/lib/good_job/cli_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@

RSpec.describe GoodJob::CLI do
let(:scheduler_mock) { instance_double GoodJob::Scheduler, shutdown?: false, shutdown: nil }
let(:env) { {} }
let(:args) { [] }

before do
stub_const 'GoodJob::CLI::RAILS_ENVIRONMENT_RB', File.expand_path("spec/test_app/config/environment.rb")
allow(GoodJob).to receive(:configuration).and_return(GoodJob::Configuration.new({}))
allow(GoodJob::Scheduler).to receive(:new).and_return scheduler_mock
end

Expand Down Expand Up @@ -38,11 +37,10 @@
describe 'max threads' do
it 'defaults to --max_threads, GOOD_JOB_MAX_THREADS, RAILS_MAX_THREADS, database connection pool size' do
allow(Kernel).to receive(:loop)

cli = described_class.new([], { max_threads: 4 }, {})
stub_const 'ENV', ENV.to_hash.merge({ 'RAILS_MAX_THREADS' => 3, 'GOOD_JOB_MAX_THREADS' => 2 })
allow(GoodJob.configuration).to receive(:env).and_return(ENV.to_h.merge({ 'RAILS_MAX_THREADS' => 3, 'GOOD_JOB_MAX_THREADS' => 2 }))
allow(ActiveRecord::Base.connection_pool).to receive(:size).and_return(1)

cli = described_class.new([], { max_threads: 4 }, {})
cli.start

expect(GoodJob::Scheduler).to have_received(:new).with(
Expand Down
3 changes: 1 addition & 2 deletions spec/lib/good_job_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,7 @@
end

it "respects the cleanup_discarded_jobs? configuration" do
stub_const 'ENV', ENV.to_hash.merge({ 'GOOD_JOB_CLEANUP_DISCARDED_JOBS' => 'false' })

allow(described_class.configuration).to receive(:env).and_return ENV.to_hash.merge({ 'GOOD_JOB_CLEANUP_DISCARDED_JOBS' => 'false' })
destroyed_jobs_count = described_class.cleanup_preserved_jobs

expect(destroyed_jobs_count).to eq 1
Expand Down

0 comments on commit c7ab74d

Please sign in to comment.