solid_queue 1.1.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +239 -41
- data/Rakefile +27 -5
- data/app/models/solid_queue/blocked_execution.rb +1 -1
- data/app/models/solid_queue/claimed_execution.rb +10 -3
- data/app/models/solid_queue/job/clearable.rb +2 -1
- data/app/models/solid_queue/job/concurrency_controls.rb +12 -0
- data/app/models/solid_queue/job/executable.rb +1 -1
- data/app/models/solid_queue/job.rb +3 -2
- data/app/models/solid_queue/recurring_task.rb +14 -1
- data/app/models/solid_queue/scheduled_execution.rb +1 -1
- data/lib/active_job/concurrency_controls.rb +4 -1
- data/lib/active_job/queue_adapters/solid_queue_adapter.rb +4 -1
- data/lib/generators/solid_queue/install/templates/config/recurring.yml +7 -2
- data/lib/solid_queue/app_executor.rb +1 -1
- data/lib/solid_queue/cli.rb +2 -1
- data/lib/solid_queue/configuration.rb +57 -7
- data/lib/solid_queue/dispatcher.rb +10 -11
- data/lib/solid_queue/lifecycle_hooks.rb +11 -2
- data/lib/solid_queue/log_subscriber.rb +2 -1
- data/lib/solid_queue/pool.rb +3 -7
- data/lib/solid_queue/processes/base.rb +2 -1
- data/lib/solid_queue/processes/interruptible.rb +21 -10
- data/lib/solid_queue/processes/poller.rb +4 -4
- data/lib/solid_queue/processes/process_pruned_error.rb +1 -1
- data/lib/solid_queue/processes/registrable.rb +1 -2
- data/lib/solid_queue/scheduler.rb +5 -1
- data/lib/solid_queue/supervisor.rb +8 -3
- data/lib/solid_queue/version.rb +1 -1
- data/lib/solid_queue/worker.rb +6 -3
- data/lib/solid_queue.rb +12 -6
- metadata +35 -14
@@ -5,6 +5,7 @@ module ActiveJob
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
DEFAULT_CONCURRENCY_GROUP = ->(*) { self.class.name }
|
8
|
+
CONCURRENCY_ON_CONFLICT_BEHAVIOUR = %i[ block discard ]
|
8
9
|
|
9
10
|
included do
|
10
11
|
class_attribute :concurrency_key, instance_accessor: false
|
@@ -12,14 +13,16 @@ module ActiveJob
|
|
12
13
|
|
13
14
|
class_attribute :concurrency_limit
|
14
15
|
class_attribute :concurrency_duration, default: SolidQueue.default_concurrency_control_period
|
16
|
+
class_attribute :concurrency_on_conflict, default: :block
|
15
17
|
end
|
16
18
|
|
17
19
|
class_methods do
|
18
|
-
def limits_concurrency(key:, to: 1, group: DEFAULT_CONCURRENCY_GROUP, duration: SolidQueue.default_concurrency_control_period)
|
20
|
+
def limits_concurrency(key:, to: 1, group: DEFAULT_CONCURRENCY_GROUP, duration: SolidQueue.default_concurrency_control_period, on_conflict: :block)
|
19
21
|
self.concurrency_key = key
|
20
22
|
self.concurrency_limit = to
|
21
23
|
self.concurrency_group = group
|
22
24
|
self.concurrency_duration = duration
|
25
|
+
self.concurrency_on_conflict = on_conflict.presence_in(CONCURRENCY_ON_CONFLICT_BEHAVIOUR) || :block
|
23
26
|
end
|
24
27
|
end
|
25
28
|
|
@@ -7,7 +7,10 @@ module ActiveJob
|
|
7
7
|
# To use it set the queue_adapter config to +:solid_queue+.
|
8
8
|
#
|
9
9
|
# Rails.application.config.active_job.queue_adapter = :solid_queue
|
10
|
-
class SolidQueueAdapter
|
10
|
+
class SolidQueueAdapter < (Rails::VERSION::MAJOR == 7 && Rails::VERSION::MINOR == 1 ? Object : AbstractAdapter)
|
11
|
+
class_attribute :stopping, default: false, instance_writer: false
|
12
|
+
SolidQueue.on_worker_stop { self.stopping = true }
|
13
|
+
|
11
14
|
def enqueue_after_transaction_commit?
|
12
15
|
true
|
13
16
|
end
|
@@ -1,10 +1,15 @@
|
|
1
|
-
#
|
1
|
+
# examples:
|
2
2
|
# periodic_cleanup:
|
3
3
|
# class: CleanSoftDeletedRecordsJob
|
4
4
|
# queue: background
|
5
5
|
# args: [ 1000, { batch_size: 500 } ]
|
6
6
|
# schedule: every hour
|
7
|
-
#
|
7
|
+
# periodic_cleanup_with_command:
|
8
8
|
# command: "SoftDeletedRecord.due.delete_all"
|
9
9
|
# priority: 2
|
10
10
|
# schedule: at 5am every day
|
11
|
+
|
12
|
+
production:
|
13
|
+
clear_solid_queue_finished_jobs:
|
14
|
+
command: "SolidQueue::Job.clear_finished_in_batches(sleep_between_batches: 0.3)"
|
15
|
+
schedule: every hour at minute 12
|
data/lib/solid_queue/cli.rb
CHANGED
@@ -13,7 +13,8 @@ module SolidQueue
|
|
13
13
|
banner: "SOLID_QUEUE_RECURRING_SCHEDULE"
|
14
14
|
|
15
15
|
class_option :skip_recurring, type: :boolean, default: false,
|
16
|
-
desc: "Whether to skip recurring tasks scheduling"
|
16
|
+
desc: "Whether to skip recurring tasks scheduling",
|
17
|
+
banner: "SOLID_QUEUE_SKIP_RECURRING"
|
17
18
|
|
18
19
|
def self.exit_on_failure?
|
19
20
|
true
|
@@ -2,6 +2,12 @@
|
|
2
2
|
|
3
3
|
module SolidQueue
|
4
4
|
class Configuration
|
5
|
+
include ActiveModel::Model
|
6
|
+
|
7
|
+
validate :ensure_configured_processes
|
8
|
+
validate :ensure_valid_recurring_tasks
|
9
|
+
validate :ensure_correctly_sized_thread_pool
|
10
|
+
|
5
11
|
class Process < Struct.new(:kind, :attributes)
|
6
12
|
def instantiate
|
7
13
|
"SolidQueue::#{kind.to_s.titleize}".safe_constantize.new(**attributes)
|
@@ -36,24 +42,60 @@ module SolidQueue
|
|
36
42
|
end
|
37
43
|
end
|
38
44
|
|
39
|
-
def
|
40
|
-
|
41
|
-
|
45
|
+
def error_messages
|
46
|
+
if configured_processes.none?
|
47
|
+
"No workers or processed configured. Exiting..."
|
48
|
+
else
|
49
|
+
error_messages = invalid_tasks.map do |task|
|
50
|
+
all_messages = task.errors.full_messages.map { |msg| "\t#{msg}" }.join("\n")
|
51
|
+
"#{task.key}:\n#{all_messages}"
|
52
|
+
end
|
53
|
+
.join("\n")
|
54
|
+
|
55
|
+
"Invalid processes configured:\n#{error_messages}"
|
56
|
+
end
|
42
57
|
end
|
43
58
|
|
44
59
|
private
|
45
60
|
attr_reader :options
|
46
61
|
|
62
|
+
def ensure_configured_processes
|
63
|
+
unless configured_processes.any?
|
64
|
+
errors.add(:base, "No processes configured")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def ensure_valid_recurring_tasks
|
69
|
+
unless skip_recurring_tasks? || invalid_tasks.none?
|
70
|
+
error_messages = invalid_tasks.map do |task|
|
71
|
+
"- #{task.key}: #{task.errors.full_messages.join(", ")}"
|
72
|
+
end
|
73
|
+
|
74
|
+
errors.add(:base, "Invalid recurring tasks:\n#{error_messages.join("\n")}")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def ensure_correctly_sized_thread_pool
|
79
|
+
if (db_pool_size = SolidQueue::Record.connection_pool&.size) && db_pool_size < estimated_number_of_threads
|
80
|
+
errors.add(:base, "Solid Queue is configured to use #{estimated_number_of_threads} threads but the " +
|
81
|
+
"database connection pool is #{db_pool_size}. Increase it in `config/database.yml`")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
47
85
|
def default_options
|
48
86
|
{
|
49
87
|
config_file: Rails.root.join(ENV["SOLID_QUEUE_CONFIG"] || DEFAULT_CONFIG_FILE_PATH),
|
50
88
|
recurring_schedule_file: Rails.root.join(ENV["SOLID_QUEUE_RECURRING_SCHEDULE"] || DEFAULT_RECURRING_SCHEDULE_FILE_PATH),
|
51
89
|
only_work: false,
|
52
90
|
only_dispatch: false,
|
53
|
-
skip_recurring:
|
91
|
+
skip_recurring: ActiveModel::Type::Boolean.new.cast(ENV["SOLID_QUEUE_SKIP_RECURRING"])
|
54
92
|
}
|
55
93
|
end
|
56
94
|
|
95
|
+
def invalid_tasks
|
96
|
+
recurring_tasks.select(&:invalid?)
|
97
|
+
end
|
98
|
+
|
57
99
|
def only_work?
|
58
100
|
options[:only_work]
|
59
101
|
end
|
@@ -99,8 +141,8 @@ module SolidQueue
|
|
99
141
|
|
100
142
|
def recurring_tasks
|
101
143
|
@recurring_tasks ||= recurring_tasks_config.map do |id, options|
|
102
|
-
RecurringTask.from_configuration(id, **options)
|
103
|
-
end.
|
144
|
+
RecurringTask.from_configuration(id, **options) if options&.has_key?(:schedule)
|
145
|
+
end.compact
|
104
146
|
end
|
105
147
|
|
106
148
|
def processes_config
|
@@ -111,7 +153,9 @@ module SolidQueue
|
|
111
153
|
end
|
112
154
|
|
113
155
|
def recurring_tasks_config
|
114
|
-
@recurring_tasks_config ||=
|
156
|
+
@recurring_tasks_config ||= begin
|
157
|
+
config_from options[:recurring_schedule_file]
|
158
|
+
end
|
115
159
|
end
|
116
160
|
|
117
161
|
|
@@ -147,5 +191,11 @@ module SolidQueue
|
|
147
191
|
{}
|
148
192
|
end
|
149
193
|
end
|
194
|
+
|
195
|
+
def estimated_number_of_threads
|
196
|
+
# At most "threads" in each worker + 1 thread for the worker + 1 thread for the heartbeat task
|
197
|
+
thread_count = workers_options.map { |options| options.fetch(:threads, WORKER_DEFAULTS[:threads]) }.max
|
198
|
+
(thread_count || 1) + 2
|
199
|
+
end
|
150
200
|
end
|
151
201
|
end
|
@@ -2,10 +2,14 @@
|
|
2
2
|
|
3
3
|
module SolidQueue
|
4
4
|
class Dispatcher < Processes::Poller
|
5
|
-
|
5
|
+
include LifecycleHooks
|
6
|
+
attr_reader :batch_size
|
6
7
|
|
8
|
+
after_boot :run_start_hooks
|
7
9
|
after_boot :start_concurrency_maintenance
|
8
10
|
before_shutdown :stop_concurrency_maintenance
|
11
|
+
before_shutdown :run_stop_hooks
|
12
|
+
after_shutdown :run_exit_hooks
|
9
13
|
|
10
14
|
def initialize(**options)
|
11
15
|
options = options.dup.with_defaults(SolidQueue::Configuration::DISPATCHER_DEFAULTS)
|
@@ -22,9 +26,12 @@ module SolidQueue
|
|
22
26
|
end
|
23
27
|
|
24
28
|
private
|
29
|
+
attr_reader :concurrency_maintenance
|
30
|
+
|
25
31
|
def poll
|
26
32
|
batch = dispatch_next_batch
|
27
|
-
|
33
|
+
|
34
|
+
batch.zero? ? polling_interval : 0.seconds
|
28
35
|
end
|
29
36
|
|
30
37
|
def dispatch_next_batch
|
@@ -37,20 +44,12 @@ module SolidQueue
|
|
37
44
|
concurrency_maintenance&.start
|
38
45
|
end
|
39
46
|
|
40
|
-
def schedule_recurring_tasks
|
41
|
-
recurring_schedule.schedule_tasks
|
42
|
-
end
|
43
|
-
|
44
47
|
def stop_concurrency_maintenance
|
45
48
|
concurrency_maintenance&.stop
|
46
49
|
end
|
47
50
|
|
48
|
-
def unschedule_recurring_tasks
|
49
|
-
recurring_schedule.unschedule_tasks
|
50
|
-
end
|
51
|
-
|
52
51
|
def all_work_completed?
|
53
|
-
SolidQueue::ScheduledExecution.none?
|
52
|
+
SolidQueue::ScheduledExecution.none?
|
54
53
|
end
|
55
54
|
|
56
55
|
def set_procline
|
@@ -5,7 +5,7 @@ module SolidQueue
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
included do
|
8
|
-
mattr_reader :lifecycle_hooks, default: { start: [], stop: [] }
|
8
|
+
mattr_reader :lifecycle_hooks, default: { start: [], stop: [], exit: [] }
|
9
9
|
end
|
10
10
|
|
11
11
|
class_methods do
|
@@ -17,7 +17,12 @@ module SolidQueue
|
|
17
17
|
self.lifecycle_hooks[:stop] << block
|
18
18
|
end
|
19
19
|
|
20
|
+
def on_exit(&block)
|
21
|
+
self.lifecycle_hooks[:exit] << block
|
22
|
+
end
|
23
|
+
|
20
24
|
def clear_hooks
|
25
|
+
self.lifecycle_hooks[:exit] = []
|
21
26
|
self.lifecycle_hooks[:start] = []
|
22
27
|
self.lifecycle_hooks[:stop] = []
|
23
28
|
end
|
@@ -32,9 +37,13 @@ module SolidQueue
|
|
32
37
|
run_hooks_for :stop
|
33
38
|
end
|
34
39
|
|
40
|
+
def run_exit_hooks
|
41
|
+
run_hooks_for :exit
|
42
|
+
end
|
43
|
+
|
35
44
|
def run_hooks_for(event)
|
36
45
|
self.class.lifecycle_hooks.fetch(event, []).each do |block|
|
37
|
-
|
46
|
+
block.call(self)
|
38
47
|
rescue Exception => exception
|
39
48
|
handle_thread_error(exception)
|
40
49
|
end
|
@@ -145,6 +145,7 @@ class SolidQueue::LogSubscriber < ActiveSupport::LogSubscriber
|
|
145
145
|
end
|
146
146
|
|
147
147
|
def replace_fork(event)
|
148
|
+
supervisor_pid = event.payload[:supervisor_pid]
|
148
149
|
status = event.payload[:status]
|
149
150
|
attributes = event.payload.slice(:pid).merge \
|
150
151
|
status: (status.exitstatus || "no exit status set"),
|
@@ -155,7 +156,7 @@ class SolidQueue::LogSubscriber < ActiveSupport::LogSubscriber
|
|
155
156
|
|
156
157
|
if replaced_fork = event.payload[:fork]
|
157
158
|
info formatted_event(event, action: "Replaced terminated #{replaced_fork.kind}", **attributes.merge(hostname: replaced_fork.hostname, name: replaced_fork.name))
|
158
|
-
|
159
|
+
elsif supervisor_pid != 1 # Running Docker, possibly having some processes that have been reparented
|
159
160
|
warn formatted_event(event, action: "Tried to replace forked process but it had already died", **attributes)
|
160
161
|
end
|
161
162
|
end
|
data/lib/solid_queue/pool.rb
CHANGED
@@ -18,20 +18,16 @@ module SolidQueue
|
|
18
18
|
def post(execution)
|
19
19
|
available_threads.decrement
|
20
20
|
|
21
|
-
|
21
|
+
Concurrent::Promises.future_on(executor, execution) do |thread_execution|
|
22
22
|
wrap_in_app_executor do
|
23
23
|
thread_execution.perform
|
24
24
|
ensure
|
25
25
|
available_threads.increment
|
26
26
|
mutex.synchronize { on_idle.try(:call) if idle? }
|
27
27
|
end
|
28
|
+
end.on_rejection! do |e|
|
29
|
+
handle_thread_error(e)
|
28
30
|
end
|
29
|
-
|
30
|
-
future.add_observer do |_, _, error|
|
31
|
-
handle_thread_error(error) if error
|
32
|
-
end
|
33
|
-
|
34
|
-
future.execute
|
35
31
|
end
|
36
32
|
|
37
33
|
def idle_threads
|
@@ -4,7 +4,8 @@ module SolidQueue
|
|
4
4
|
module Processes
|
5
5
|
class Base
|
6
6
|
include Callbacks # Defines callbacks needed by other concerns
|
7
|
-
include AppExecutor, Registrable,
|
7
|
+
include AppExecutor, Registrable, Procline
|
8
|
+
prepend Interruptible
|
8
9
|
|
9
10
|
attr_reader :name
|
10
11
|
|
@@ -2,28 +2,39 @@
|
|
2
2
|
|
3
3
|
module SolidQueue::Processes
|
4
4
|
module Interruptible
|
5
|
+
def initialize(...)
|
6
|
+
super
|
7
|
+
@self_pipe = create_self_pipe
|
8
|
+
end
|
9
|
+
|
5
10
|
def wake_up
|
6
11
|
interrupt
|
7
12
|
end
|
8
13
|
|
9
14
|
private
|
15
|
+
SELF_PIPE_BLOCK_SIZE = 11
|
16
|
+
|
17
|
+
attr_reader :self_pipe
|
10
18
|
|
11
19
|
def interrupt
|
12
|
-
|
20
|
+
self_pipe[:writer].write_nonblock(".")
|
21
|
+
rescue Errno::EAGAIN, Errno::EINTR
|
22
|
+
# Ignore writes that would block and retry
|
23
|
+
# if another signal arrived while writing
|
24
|
+
retry
|
13
25
|
end
|
14
26
|
|
15
27
|
def interruptible_sleep(time)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
queue.clear
|
21
|
-
end
|
22
|
-
end.value
|
28
|
+
if time > 0 && self_pipe[:reader].wait_readable(time)
|
29
|
+
loop { self_pipe[:reader].read_nonblock(SELF_PIPE_BLOCK_SIZE) }
|
30
|
+
end
|
31
|
+
rescue Errno::EAGAIN, Errno::EINTR, IO::EWOULDBLOCKWaitReadable
|
23
32
|
end
|
24
33
|
|
25
|
-
|
26
|
-
|
34
|
+
# Self-pipe for signal-handling (http://cr.yp.to/docs/selfpipe.html)
|
35
|
+
def create_self_pipe
|
36
|
+
reader, writer = IO.pipe
|
37
|
+
{ reader: reader, writer: writer }
|
27
38
|
end
|
28
39
|
end
|
29
40
|
end
|
@@ -25,11 +25,11 @@ module SolidQueue::Processes
|
|
25
25
|
loop do
|
26
26
|
break if shutting_down?
|
27
27
|
|
28
|
-
wrap_in_app_executor do
|
29
|
-
|
30
|
-
interruptible_sleep(polling_interval)
|
31
|
-
end
|
28
|
+
delay = wrap_in_app_executor do
|
29
|
+
poll
|
32
30
|
end
|
31
|
+
|
32
|
+
interruptible_sleep(delay)
|
33
33
|
end
|
34
34
|
ensure
|
35
35
|
SolidQueue.instrument(:shutdown_process, process: self) do
|
@@ -4,7 +4,7 @@ module SolidQueue
|
|
4
4
|
module Processes
|
5
5
|
class ProcessPrunedError < RuntimeError
|
6
6
|
def initialize(last_heartbeat_at)
|
7
|
-
super("Process was found dead and pruned (last heartbeat at: #{last_heartbeat_at}")
|
7
|
+
super("Process was found dead and pruned (last heartbeat at: #{last_heartbeat_at})")
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
@@ -3,11 +3,15 @@
|
|
3
3
|
module SolidQueue
|
4
4
|
class Scheduler < Processes::Base
|
5
5
|
include Processes::Runnable
|
6
|
+
include LifecycleHooks
|
6
7
|
|
7
|
-
|
8
|
+
attr_reader :recurring_schedule
|
8
9
|
|
10
|
+
after_boot :run_start_hooks
|
9
11
|
after_boot :schedule_recurring_tasks
|
10
12
|
before_shutdown :unschedule_recurring_tasks
|
13
|
+
before_shutdown :run_stop_hooks
|
14
|
+
after_shutdown :run_exit_hooks
|
11
15
|
|
12
16
|
def initialize(recurring_tasks:, **options)
|
13
17
|
@recurring_schedule = RecurringSchedule.new(recurring_tasks)
|
@@ -5,15 +5,17 @@ module SolidQueue
|
|
5
5
|
include LifecycleHooks
|
6
6
|
include Maintenance, Signals, Pidfiled
|
7
7
|
|
8
|
+
after_shutdown :run_exit_hooks
|
9
|
+
|
8
10
|
class << self
|
9
11
|
def start(**options)
|
10
12
|
SolidQueue.supervisor = true
|
11
13
|
configuration = Configuration.new(**options)
|
12
14
|
|
13
|
-
if configuration.
|
15
|
+
if configuration.valid?
|
14
16
|
new(configuration).tap(&:start)
|
15
17
|
else
|
16
|
-
abort "
|
18
|
+
abort configuration.errors.full_messages.join("\n") + "\nExiting..."
|
17
19
|
end
|
18
20
|
end
|
19
21
|
end
|
@@ -170,8 +172,11 @@ module SolidQueue
|
|
170
172
|
end
|
171
173
|
end
|
172
174
|
|
175
|
+
# When a supervised fork crashes or exits we need to mark all the
|
176
|
+
# executions it had claimed as failed so that they can be retried
|
177
|
+
# by some other worker.
|
173
178
|
def handle_claimed_jobs_by(terminated_fork, status)
|
174
|
-
if registered_process =
|
179
|
+
if registered_process = SolidQueue::Process.find_by(name: terminated_fork.name)
|
175
180
|
error = Processes::ProcessExitError.new(status)
|
176
181
|
registered_process.fail_all_claimed_executions_with(error)
|
177
182
|
end
|
data/lib/solid_queue/version.rb
CHANGED
data/lib/solid_queue/worker.rb
CHANGED
@@ -6,13 +6,16 @@ module SolidQueue
|
|
6
6
|
|
7
7
|
after_boot :run_start_hooks
|
8
8
|
before_shutdown :run_stop_hooks
|
9
|
+
after_shutdown :run_exit_hooks
|
9
10
|
|
10
|
-
|
11
|
+
attr_reader :queues, :pool
|
11
12
|
|
12
13
|
def initialize(**options)
|
13
14
|
options = options.dup.with_defaults(SolidQueue::Configuration::WORKER_DEFAULTS)
|
14
15
|
|
15
|
-
|
16
|
+
# Ensure that the queues array is deep frozen to prevent accidental modification
|
17
|
+
@queues = Array(options[:queues]).map(&:freeze).freeze
|
18
|
+
|
16
19
|
@pool = Pool.new(options[:threads], on_idle: -> { wake_up })
|
17
20
|
|
18
21
|
super(**options)
|
@@ -29,7 +32,7 @@ module SolidQueue
|
|
29
32
|
pool.post(execution)
|
30
33
|
end
|
31
34
|
|
32
|
-
|
35
|
+
pool.idle? ? polling_interval : 10.minutes
|
33
36
|
end
|
34
37
|
end
|
35
38
|
|
data/lib/solid_queue.rb
CHANGED
@@ -41,14 +41,20 @@ module SolidQueue
|
|
41
41
|
mattr_accessor :clear_finished_jobs_after, default: 1.day
|
42
42
|
mattr_accessor :default_concurrency_control_period, default: 3.minutes
|
43
43
|
|
44
|
-
delegate :on_start, :on_stop, to: Supervisor
|
44
|
+
delegate :on_start, :on_stop, :on_exit, to: Supervisor
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
[ Dispatcher, Scheduler, Worker ].each do |process|
|
47
|
+
define_singleton_method(:"on_#{process.name.demodulize.downcase}_start") do |&block|
|
48
|
+
process.on_start(&block)
|
49
|
+
end
|
50
|
+
|
51
|
+
define_singleton_method(:"on_#{process.name.demodulize.downcase}_stop") do |&block|
|
52
|
+
process.on_stop(&block)
|
53
|
+
end
|
49
54
|
|
50
|
-
|
51
|
-
|
55
|
+
define_singleton_method(:"on_#{process.name.demodulize.downcase}_exit") do |&block|
|
56
|
+
process.on_exit(&block)
|
57
|
+
end
|
52
58
|
end
|
53
59
|
|
54
60
|
def supervisor?
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: solid_queue
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rosa Gutierrez
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-07-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -84,16 +84,30 @@ dependencies:
|
|
84
84
|
name: thor
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - "
|
87
|
+
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: 1.3.1
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - "
|
94
|
+
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: 1.3.1
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: appraisal
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
112
|
name: debug
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -220,6 +234,20 @@ dependencies:
|
|
220
234
|
- - ">="
|
221
235
|
- !ruby/object:Gem::Version
|
222
236
|
version: '0'
|
237
|
+
- !ruby/object:Gem::Dependency
|
238
|
+
name: zeitwerk
|
239
|
+
requirement: !ruby/object:Gem::Requirement
|
240
|
+
requirements:
|
241
|
+
- - '='
|
242
|
+
- !ruby/object:Gem::Version
|
243
|
+
version: 2.6.0
|
244
|
+
type: :development
|
245
|
+
prerelease: false
|
246
|
+
version_requirements: !ruby/object:Gem::Requirement
|
247
|
+
requirements:
|
248
|
+
- - '='
|
249
|
+
- !ruby/object:Gem::Version
|
250
|
+
version: 2.6.0
|
223
251
|
description: Database-backed Active Job backend.
|
224
252
|
email:
|
225
253
|
- rosa@37signals.com
|
@@ -307,15 +335,8 @@ metadata:
|
|
307
335
|
homepage_uri: https://github.com/rails/solid_queue
|
308
336
|
source_code_uri: https://github.com/rails/solid_queue
|
309
337
|
post_install_message: |
|
310
|
-
Upgrading
|
311
|
-
|
312
|
-
Upgrading to Solid Queue 0.8.0 from < 0.6.0? You need to upgrade to 0.6.0 first.
|
313
|
-
|
314
|
-
Upgrading to Solid Queue 0.4.x, 0.5.x, 0.6.x or 0.7.x? There are some breaking changes about how Solid Queue is started,
|
315
|
-
configuration and new migrations.
|
316
|
-
|
317
|
-
--> Check https://github.com/rails/solid_queue/blob/main/UPGRADING.md
|
318
|
-
for upgrade instructions.
|
338
|
+
Upgrading from Solid Queue < 1.0? Check details on breaking changes and upgrade instructions
|
339
|
+
--> https://github.com/rails/solid_queue/blob/main/UPGRADING.md
|
319
340
|
rdoc_options: []
|
320
341
|
require_paths:
|
321
342
|
- lib
|
@@ -323,7 +344,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
323
344
|
requirements:
|
324
345
|
- - ">="
|
325
346
|
- !ruby/object:Gem::Version
|
326
|
-
version: '
|
347
|
+
version: '3.1'
|
327
348
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
328
349
|
requirements:
|
329
350
|
- - ">="
|