solid_queue 0.5.0 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 952d693063dae16e88a88acb2f8d77f396472cb29811e7ab2c47c06fc400cf10
4
- data.tar.gz: 338ad6a0057939a54997cdef138fa5e62e974112625c43fd65240354a0ba760a
3
+ metadata.gz: c2734f6cbcc795345207dc0cf221bd2744f2f98449da8b0edfc8175f3bbd7869
4
+ data.tar.gz: c4b4c2eca7dcb93e86a2f69d220ba1b9f8817c1d52a7cd1ff137ed5ec84e50f8
5
5
  SHA512:
6
- metadata.gz: b0bddd34b216770c9e0658bb620ae8801ab500074692417aeb0907c1f22f4f9e40a6233266aa69c1aa2b015dc294864d529659f0ee4adbdfdbef647d03fb4d35
7
- data.tar.gz: f2323054f8fdc5ee686f738d2a8359b23fe88f00b1b376cc18e99588bacc9df3be2e3a8bb660ce31db854f0fcca91560ad4d703a737b1d05c3a1dea7817c10a2
6
+ metadata.gz: 9d09b58e43c4bc19ad2ab89d10072b36b53a449e9602f5c5a8fc7b637e91d8472eb70f417148657e6b146e5cd1034025afdbe6d39fa2b9fc82ce6bba3997e57f
7
+ data.tar.gz: 27168fd2216fbca4e9b19677a7885b23663012d8aed7bf54c25be8335bd528a733b55790e662a30815b9ba24d824390372eff24ed0b9f72947b6ff4feeec17c5
@@ -29,8 +29,21 @@ class SolidQueue::ClaimedExecution < SolidQueue::Execution
29
29
  def release_all
30
30
  SolidQueue.instrument(:release_many_claimed) do |payload|
31
31
  includes(:job).tap do |executions|
32
- payload[:size] = executions.size
33
32
  executions.each(&:release)
33
+
34
+ payload[:size] = executions.size
35
+ end
36
+ end
37
+ end
38
+
39
+ def fail_all_with(error)
40
+ SolidQueue.instrument(:fail_many_claimed) do |payload|
41
+ includes(:job).tap do |executions|
42
+ executions.each { |execution| execution.failed_with(error) }
43
+
44
+ payload[:process_ids] = executions.map(&:process_id).uniq
45
+ payload[:job_ids] = executions.map(&:job_id).uniq
46
+ payload[:size] = executions.size
34
47
  end
35
48
  end
36
49
  end
@@ -69,6 +82,13 @@ class SolidQueue::ClaimedExecution < SolidQueue::Execution
69
82
  raise UndiscardableError, "Can't discard a job in progress"
70
83
  end
71
84
 
85
+ def failed_with(error)
86
+ transaction do
87
+ job.failed_with(error)
88
+ destroy!
89
+ end
90
+ end
91
+
72
92
  private
73
93
  def execute
74
94
  ActiveJob::Base.execute(job.arguments)
@@ -83,11 +103,4 @@ class SolidQueue::ClaimedExecution < SolidQueue::Execution
83
103
  destroy!
84
104
  end
85
105
  end
86
-
87
- def failed_with(error)
88
- transaction do
89
- job.failed_with(error)
90
- destroy!
91
- end
92
- end
93
106
  end
@@ -8,7 +8,19 @@ module SolidQueue
8
8
  included do
9
9
  has_many :claimed_executions
10
10
 
11
- after_destroy -> { claimed_executions.release_all }, if: :claims_executions?
11
+ after_destroy :release_all_claimed_executions
12
+ end
13
+
14
+ def fail_all_claimed_executions_with(error)
15
+ if claims_executions?
16
+ claimed_executions.fail_all_with(error)
17
+ end
18
+ end
19
+
20
+ def release_all_claimed_executions
21
+ if claims_executions?
22
+ claimed_executions.release_all
23
+ end
12
24
  end
13
25
 
14
26
  private
@@ -15,11 +15,18 @@ module SolidQueue
15
15
  prunable.non_blocking_lock.find_in_batches(batch_size: 50) do |batch|
16
16
  payload[:size] += batch.size
17
17
 
18
- batch.each { |process| process.deregister(pruned: true) }
18
+ batch.each(&:prune)
19
19
  end
20
20
  end
21
21
  end
22
22
  end
23
+
24
+ def prune
25
+ error = Processes::ProcessPrunedError.new(last_heartbeat_at)
26
+ fail_all_claimed_executions_with(error)
27
+
28
+ deregister(pruned: true)
29
+ end
23
30
  end
24
31
  end
25
32
  end
@@ -4,7 +4,7 @@ class SolidQueue::Process < SolidQueue::Record
4
4
  include Executor, Prunable
5
5
 
6
6
  belongs_to :supervisor, class_name: "SolidQueue::Process", optional: true, inverse_of: :supervisees
7
- has_many :supervisees, class_name: "SolidQueue::Process", inverse_of: :supervisor, foreign_key: :supervisor_id, dependent: :destroy
7
+ has_many :supervisees, class_name: "SolidQueue::Process", inverse_of: :supervisor, foreign_key: :supervisor_id
8
8
 
9
9
  store :metadata, coder: JSON
10
10
 
@@ -13,10 +13,10 @@ class SolidQueue::Process < SolidQueue::Record
13
13
  create!(attributes.merge(last_heartbeat_at: Time.current)).tap do |process|
14
14
  payload[:process_id] = process.id
15
15
  end
16
+ rescue Exception => error
17
+ payload[:error] = error
18
+ raise
16
19
  end
17
- rescue Exception => error
18
- SolidQueue.instrument :register_process, **attributes.merge(error: error)
19
- raise
20
20
  end
21
21
 
22
22
  def heartbeat
@@ -25,12 +25,19 @@ class SolidQueue::Process < SolidQueue::Record
25
25
 
26
26
  def deregister(pruned: false)
27
27
  SolidQueue.instrument :deregister_process, process: self, pruned: pruned do |payload|
28
- payload[:claimed_size] = claimed_executions.size if claims_executions?
29
-
30
28
  destroy!
29
+
30
+ unless supervised? || pruned
31
+ supervisees.each(&:deregister)
32
+ end
31
33
  rescue Exception => error
32
34
  payload[:error] = error
33
35
  raise
34
36
  end
35
37
  end
38
+
39
+ private
40
+ def supervised?
41
+ supervisor_id.present?
42
+ end
36
43
  end
@@ -25,7 +25,7 @@ module SolidQueue
25
25
  def record(task_key, run_at, &block)
26
26
  transaction do
27
27
  block.call.tap do |active_job|
28
- if active_job
28
+ if active_job && active_job.successfully_enqueued?
29
29
  create_or_insert!(job_id: active_job.provider_job_id, task_key: task_key, run_at: run_at)
30
30
  end
31
31
  end
@@ -43,7 +43,7 @@ module SolidQueue
43
43
  def enqueue(at:)
44
44
  SolidQueue.instrument(:enqueue_recurring_task, task: key, at: at) do |payload|
45
45
  active_job = if using_solid_queue_adapter?
46
- perform_later_and_record(run_at: at)
46
+ enqueue_and_record(run_at: at)
47
47
  else
48
48
  payload[:other_adapter] = true
49
49
 
@@ -87,8 +87,15 @@ module SolidQueue
87
87
  job_class.queue_adapter_name.inquiry.solid_queue?
88
88
  end
89
89
 
90
- def perform_later_and_record(run_at:)
91
- RecurringExecution.record(key, run_at) { perform_later }
90
+ def enqueue_and_record(run_at:)
91
+ RecurringExecution.record(key, run_at) do
92
+ job_class.new(*arguments_with_kwargs).tap do |active_job|
93
+ active_job.run_callbacks(:enqueue) do
94
+ Job.enqueue(active_job)
95
+ end
96
+ active_job.successfully_enqueued = true
97
+ end
98
+ end
92
99
  end
93
100
 
94
101
  def perform_later(&block)
@@ -0,0 +1,5 @@
1
+ class AddNameToProcesses < ActiveRecord::Migration[7.1]
2
+ def change
3
+ add_column :solid_queue_processes, :name, :string
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ class MakeNameNotNull < ActiveRecord::Migration[7.1]
2
+ def up
3
+ SolidQueue::Process.where(name: nil).find_each do |process|
4
+ process.name ||= [ process.kind.downcase, SecureRandom.hex(10) ].join("-")
5
+ process.save!
6
+ end
7
+
8
+ change_column :solid_queue_processes, :name, :string, null: false
9
+ add_index :solid_queue_processes, [ :name, :supervisor_id ], unique: true
10
+ end
11
+
12
+ def down
13
+ remove_index :solid_queue_processes, [ :name, :supervisor_id ]
14
+ change_column :solid_queue_processes, :name, :string, null: true
15
+ end
16
+ end
@@ -0,0 +1,5 @@
1
+ class ChangeSolidQueueRecurringTasksStaticToNotNull < ActiveRecord::Migration[7.1]
2
+ def change
3
+ change_column_null :solid_queue_recurring_tasks, :static, false, true
4
+ end
5
+ end
@@ -2,6 +2,12 @@
2
2
 
3
3
  module SolidQueue
4
4
  class Configuration
5
+ class Process < Struct.new(:kind, :attributes)
6
+ def instantiate
7
+ "SolidQueue::#{kind.to_s.titleize}".safe_constantize.new(**attributes)
8
+ end
9
+ end
10
+
5
11
  WORKER_DEFAULTS = {
6
12
  queues: "*",
7
13
  threads: 3,
@@ -17,33 +23,20 @@ module SolidQueue
17
23
  recurring_tasks: []
18
24
  }
19
25
 
26
+ DEFAULT_CONFIG = {
27
+ workers: [ WORKER_DEFAULTS ],
28
+ dispatchers: [ DISPATCHER_DEFAULTS ]
29
+ }
30
+
20
31
  def initialize(mode: :fork, load_from: nil)
21
32
  @mode = mode.to_s.inquiry
22
33
  @raw_config = config_from(load_from)
23
34
  end
24
35
 
25
- def processes
36
+ def configured_processes
26
37
  dispatchers + workers
27
38
  end
28
39
 
29
- def workers
30
- workers_options.flat_map do |worker_options|
31
- processes = if mode.fork?
32
- worker_options.fetch(:processes, WORKER_DEFAULTS[:processes])
33
- else
34
- WORKER_DEFAULTS[:processes]
35
- end
36
- processes.times.map { Worker.new(**worker_options.with_defaults(WORKER_DEFAULTS)) }
37
- end
38
- end
39
-
40
- def dispatchers
41
- dispatchers_options.map do |dispatcher_options|
42
- recurring_tasks = parse_recurring_tasks dispatcher_options[:recurring_tasks]
43
- Dispatcher.new **dispatcher_options.merge(recurring_tasks: recurring_tasks).with_defaults(DISPATCHER_DEFAULTS)
44
- end
45
- end
46
-
47
40
  def max_number_of_threads
48
41
  # At most "threads" in each worker + 1 thread for the worker + 1 thread for the heartbeat task
49
42
  workers_options.map { |options| options[:threads] }.max + 2
@@ -54,23 +47,46 @@ module SolidQueue
54
47
 
55
48
  DEFAULT_CONFIG_FILE_PATH = "config/solid_queue.yml"
56
49
 
50
+ def workers
51
+ workers_options.flat_map do |worker_options|
52
+ processes = if mode.fork?
53
+ worker_options.fetch(:processes, WORKER_DEFAULTS[:processes])
54
+ else
55
+ WORKER_DEFAULTS[:processes]
56
+ end
57
+ processes.times.map { Process.new(:worker, worker_options.with_defaults(WORKER_DEFAULTS)) }
58
+ end
59
+ end
60
+
61
+ def dispatchers
62
+ dispatchers_options.map do |dispatcher_options|
63
+ recurring_tasks = parse_recurring_tasks dispatcher_options[:recurring_tasks]
64
+ Process.new :dispatcher, dispatcher_options.merge(recurring_tasks: recurring_tasks).with_defaults(DISPATCHER_DEFAULTS)
65
+ end
66
+ end
67
+
57
68
  def config_from(file_or_hash, env: Rails.env)
58
- config = load_config_from(file_or_hash)
59
- config[env.to_sym] ? config[env.to_sym] : config
69
+ load_config_from(file_or_hash).then do |config|
70
+ config = config[env.to_sym] ? config[env.to_sym] : config
71
+ if (config.keys & DEFAULT_CONFIG.keys).any? then config
72
+ else
73
+ DEFAULT_CONFIG
74
+ end
75
+ end
60
76
  end
61
77
 
62
78
  def workers_options
63
- @workers_options ||= options_from_raw_config(:workers, WORKER_DEFAULTS)
79
+ @workers_options ||= options_from_raw_config(:workers)
64
80
  .map { |options| options.dup.symbolize_keys }
65
81
  end
66
82
 
67
83
  def dispatchers_options
68
- @dispatchers_options ||= options_from_raw_config(:dispatchers, DISPATCHER_DEFAULTS)
84
+ @dispatchers_options ||= options_from_raw_config(:dispatchers)
69
85
  .map { |options| options.dup.symbolize_keys }
70
86
  end
71
87
 
72
- def options_from_raw_config(key, defaults)
73
- raw_config.empty? ? [ defaults ] : Array(raw_config[key])
88
+ def options_from_raw_config(key)
89
+ Array(raw_config[key])
74
90
  end
75
91
 
76
92
  def parse_recurring_tasks(tasks)
@@ -12,11 +12,15 @@ class SolidQueue::LogSubscriber < ActiveSupport::LogSubscriber
12
12
  end
13
13
 
14
14
  def release_many_claimed(event)
15
- debug formatted_event(event, action: "Release claimed jobs", **event.payload.slice(:size))
15
+ info formatted_event(event, action: "Release claimed jobs", **event.payload.slice(:size))
16
+ end
17
+
18
+ def fail_many_claimed(event)
19
+ warn formatted_event(event, action: "Fail claimed jobs", **event.payload.slice(:job_ids, :process_ids))
16
20
  end
17
21
 
18
22
  def release_claimed(event)
19
- debug formatted_event(event, action: "Release claimed job", **event.payload.slice(:job_id, :process_id))
23
+ info formatted_event(event, action: "Release claimed job", **event.payload.slice(:job_id, :process_id))
20
24
  end
21
25
 
22
26
  def retry_all(event)
@@ -63,7 +67,8 @@ class SolidQueue::LogSubscriber < ActiveSupport::LogSubscriber
63
67
  attributes = {
64
68
  pid: process.pid,
65
69
  hostname: process.hostname,
66
- process_id: process.process_id
70
+ process_id: process.process_id,
71
+ name: process.name
67
72
  }.merge(process.metadata)
68
73
 
69
74
  info formatted_event(event, action: "Started #{process.kind}", **attributes)
@@ -75,7 +80,8 @@ class SolidQueue::LogSubscriber < ActiveSupport::LogSubscriber
75
80
  attributes = {
76
81
  pid: process.pid,
77
82
  hostname: process.hostname,
78
- process_id: process.process_id
83
+ process_id: process.process_id,
84
+ name: process.name
79
85
  }.merge(process.metadata)
80
86
 
81
87
  info formatted_event(event, action: "Shutdown #{process.kind}", **attributes)
@@ -83,7 +89,7 @@ class SolidQueue::LogSubscriber < ActiveSupport::LogSubscriber
83
89
 
84
90
  def register_process(event)
85
91
  process_kind = event.payload[:kind]
86
- attributes = event.payload.slice(:pid, :hostname, :process_id)
92
+ attributes = event.payload.slice(:pid, :hostname, :process_id, :name)
87
93
 
88
94
  if error = event.payload[:error]
89
95
  warn formatted_event(event, action: "Error registering #{process_kind}", **attributes.merge(error: formatted_error(error)))
@@ -99,6 +105,7 @@ class SolidQueue::LogSubscriber < ActiveSupport::LogSubscriber
99
105
  process_id: process.id,
100
106
  pid: process.pid,
101
107
  hostname: process.hostname,
108
+ name: process.name,
102
109
  last_heartbeat_at: process.last_heartbeat_at.iso8601,
103
110
  claimed_size: event.payload[:claimed_size],
104
111
  pruned: event.payload[:pruned]
@@ -147,7 +154,7 @@ class SolidQueue::LogSubscriber < ActiveSupport::LogSubscriber
147
154
  termsig: status.termsig
148
155
 
149
156
  if replaced_fork = event.payload[:fork]
150
- info formatted_event(event, action: "Replaced terminated #{replaced_fork.kind}", **attributes.merge(hostname: replaced_fork.hostname))
157
+ info formatted_event(event, action: "Replaced terminated #{replaced_fork.kind}", **attributes.merge(hostname: replaced_fork.hostname, name: replaced_fork.name))
151
158
  else
152
159
  warn formatted_event(event, action: "Tried to replace forked process but it had already died", **attributes)
153
160
  end
@@ -6,6 +6,12 @@ module SolidQueue
6
6
  include Callbacks # Defines callbacks needed by other concerns
7
7
  include AppExecutor, Registrable, Interruptible, Procline
8
8
 
9
+ attr_reader :name
10
+
11
+ def initialize(*)
12
+ @name = generate_name
13
+ end
14
+
9
15
  def kind
10
16
  self.class.name.demodulize
11
17
  end
@@ -21,6 +27,11 @@ module SolidQueue
21
27
  def metadata
22
28
  {}
23
29
  end
30
+
31
+ private
32
+ def generate_name
33
+ [ kind.downcase, SecureRandom.hex(10) ].join("-")
34
+ end
24
35
  end
25
36
  end
26
37
  end
@@ -8,6 +8,8 @@ module SolidQueue::Processes
8
8
 
9
9
  def initialize(polling_interval:, **options)
10
10
  @polling_interval = polling_interval
11
+
12
+ super(**options)
11
13
  end
12
14
 
13
15
  def metadata
@@ -43,10 +45,12 @@ module SolidQueue::Processes
43
45
  end
44
46
 
45
47
  def with_polling_volume
46
- if SolidQueue.silence_polling? && ActiveRecord::Base.logger
47
- ActiveRecord::Base.logger.silence { yield }
48
- else
49
- yield
48
+ SolidQueue.instrument(:polling) do
49
+ if SolidQueue.silence_polling? && ActiveRecord::Base.logger
50
+ ActiveRecord::Base.logger.silence { yield }
51
+ else
52
+ yield
53
+ end
50
54
  end
51
55
  end
52
56
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidQueue
4
+ module Processes
5
+ class ProcessExitError < RuntimeError
6
+ def initialize(status)
7
+ message = case
8
+ when status.exitstatus.present? then "Process pid=#{status.pid} exited with status #{status. exitstatus}"
9
+ when status.signaled? then "Process pid=#{status.pid} received unhandled signal #{status. termsig}"
10
+ else "Process pid=#{status.pid} exited unexpectedly"
11
+ end
12
+
13
+ super(message)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ module SolidQueue
2
+ module Processes
3
+ class ProcessMissingError < RuntimeError
4
+ def initialize
5
+ super("The process that was running this job no longer exists")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidQueue
4
+ module Processes
5
+ class ProcessPrunedError < RuntimeError
6
+ def initialize(last_heartbeat_at)
7
+ super("Process was found dead and pruned (last heartbeat at: #{last_heartbeat_at}")
8
+ end
9
+ end
10
+ end
11
+ end
@@ -21,6 +21,7 @@ module SolidQueue::Processes
21
21
  def register
22
22
  @process = SolidQueue::Process.register \
23
23
  kind: kind,
24
+ name: name,
24
25
  pid: pid,
25
26
  hostname: hostname,
26
27
  supervisor: try(:supervisor),
@@ -25,10 +25,6 @@ module SolidQueue::Processes
25
25
  @thread&.join
26
26
  end
27
27
 
28
- def name
29
- @name ||= [ kind.downcase, SecureRandom.hex(6) ].join("-")
30
- end
31
-
32
28
  def alive?
33
29
  !running_async? || @thread.alive?
34
30
  end
@@ -23,10 +23,13 @@ module SolidQueue
23
23
  attr_reader :threads
24
24
 
25
25
  def start_process(configured_process)
26
- configured_process.supervised_by process
27
- configured_process.start
26
+ process_instance = configured_process.instantiate.tap do |instance|
27
+ instance.supervised_by process
28
+ end
29
+
30
+ process_instance.start
28
31
 
29
- threads[configured_process.name] = configured_process
32
+ threads[process_instance.name] = process_instance
30
33
  end
31
34
 
32
35
  def stop_threads
@@ -6,7 +6,9 @@ module SolidQueue
6
6
 
7
7
  def initialize(*)
8
8
  super
9
+
9
10
  @forks = {}
11
+ @configured_processes = {}
10
12
  end
11
13
 
12
14
  def kind
@@ -14,7 +16,7 @@ module SolidQueue
14
16
  end
15
17
 
16
18
  private
17
- attr_reader :forks
19
+ attr_reader :forks, :configured_processes
18
20
 
19
21
  def supervise
20
22
  loop do
@@ -33,14 +35,17 @@ module SolidQueue
33
35
  end
34
36
 
35
37
  def start_process(configured_process)
36
- configured_process.supervised_by process
37
- configured_process.mode = :fork
38
+ process_instance = configured_process.instantiate.tap do |instance|
39
+ instance.supervised_by process
40
+ instance.mode = :fork
41
+ end
38
42
 
39
43
  pid = fork do
40
- configured_process.start
44
+ process_instance.start
41
45
  end
42
46
 
43
- forks[pid] = configured_process
47
+ configured_processes[pid] = configured_process
48
+ forks[pid] = process_instance
44
49
  end
45
50
 
46
51
  def terminate_gracefully
@@ -86,7 +91,11 @@ module SolidQueue
86
91
  pid, status = ::Process.waitpid2(-1, ::Process::WNOHANG)
87
92
  break unless pid
88
93
 
89
- forks.delete(pid)
94
+ if (terminated_fork = forks.delete(pid)) && !status.exited? || status.exitstatus > 0
95
+ handle_claimed_jobs_by(terminated_fork, status)
96
+ end
97
+
98
+ configured_processes.delete(pid)
90
99
  end
91
100
  rescue SystemCallError
92
101
  # All children already reaped
@@ -94,13 +103,22 @@ module SolidQueue
94
103
 
95
104
  def replace_fork(pid, status)
96
105
  SolidQueue.instrument(:replace_fork, supervisor_pid: ::Process.pid, pid: pid, status: status) do |payload|
97
- if supervised_fork = forks.delete(pid)
98
- payload[:fork] = supervised_fork
99
- start_process(supervised_fork)
106
+ if terminated_fork = forks.delete(pid)
107
+ payload[:fork] = terminated_fork
108
+ handle_claimed_jobs_by(terminated_fork, status)
109
+
110
+ start_process(configured_processes.delete(pid))
100
111
  end
101
112
  end
102
113
  end
103
114
 
115
+ def handle_claimed_jobs_by(terminated_fork, status)
116
+ if registered_process = process.supervisees.find_by(name: terminated_fork.name)
117
+ error = Processes::ProcessExitError.new(status)
118
+ registered_process.fail_all_claimed_executions_with(error)
119
+ end
120
+ end
121
+
104
122
  def all_forks_terminated?
105
123
  forks.empty?
106
124
  end
@@ -3,7 +3,7 @@ module SolidQueue
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- after_boot :release_orphaned_executions
6
+ after_boot :fail_orphaned_executions
7
7
  end
8
8
 
9
9
  private
@@ -27,8 +27,10 @@ module SolidQueue
27
27
  wrap_in_app_executor { SolidQueue::Process.prune }
28
28
  end
29
29
 
30
- def release_orphaned_executions
31
- wrap_in_app_executor { SolidQueue::ClaimedExecution.orphaned.release_all }
30
+ def fail_orphaned_executions
31
+ wrap_in_app_executor do
32
+ ClaimedExecution.orphaned.fail_all_with(Processes::ProcessMissingError.new)
33
+ end
32
34
  end
33
35
  end
34
36
  end
@@ -9,13 +9,18 @@ module SolidQueue
9
9
  SolidQueue.supervisor = true
10
10
  configuration = Configuration.new(mode: mode, load_from: load_configuration_from)
11
11
 
12
- klass = mode == :fork ? ForkSupervisor : AsyncSupervisor
13
- klass.new(configuration).tap(&:start)
12
+ if configuration.configured_processes.any?
13
+ klass = mode == :fork ? ForkSupervisor : AsyncSupervisor
14
+ klass.new(configuration).tap(&:start)
15
+ else
16
+ abort "No workers or processed configured. Exiting..."
17
+ end
14
18
  end
15
19
  end
16
20
 
17
21
  def initialize(configuration)
18
22
  @configuration = configuration
23
+ super
19
24
  end
20
25
 
21
26
  def start
@@ -44,7 +49,7 @@ module SolidQueue
44
49
  end
45
50
 
46
51
  def start_processes
47
- configuration.processes.each { |configured_process| start_process(configured_process) }
52
+ configuration.configured_processes.each { |configured_process| start_process(configured_process) }
48
53
  end
49
54
 
50
55
  def stopped?
@@ -1,3 +1,3 @@
1
1
  module SolidQueue
2
- VERSION = "0.5.0"
2
+ VERSION = "0.6.1"
3
3
  end
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: 0.5.0
4
+ version: 0.6.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: 2024-08-14 00:00:00.000000000 Z
11
+ date: 2024-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -220,6 +220,9 @@ files:
220
220
  - db/migrate/20240110143450_add_missing_index_to_blocked_executions.rb
221
221
  - db/migrate/20240218110712_create_recurring_executions.rb
222
222
  - db/migrate/20240719134516_create_recurring_tasks.rb
223
+ - db/migrate/20240811173327_add_name_to_processes.rb
224
+ - db/migrate/20240813160053_make_name_not_null.rb
225
+ - db/migrate/20240819165045_change_solid_queue_recurring_tasks_static_to_not_null.rb
223
226
  - lib/active_job/concurrency_controls.rb
224
227
  - lib/active_job/queue_adapters/solid_queue_adapter.rb
225
228
  - lib/generators/solid_queue/install/USAGE
@@ -239,6 +242,9 @@ files:
239
242
  - lib/solid_queue/processes/callbacks.rb
240
243
  - lib/solid_queue/processes/interruptible.rb
241
244
  - lib/solid_queue/processes/poller.rb
245
+ - lib/solid_queue/processes/process_exit_error.rb
246
+ - lib/solid_queue/processes/process_missing_error.rb
247
+ - lib/solid_queue/processes/process_pruned_error.rb
242
248
  - lib/solid_queue/processes/procline.rb
243
249
  - lib/solid_queue/processes/registrable.rb
244
250
  - lib/solid_queue/processes/runnable.rb