solid_queue 0.2.0 → 0.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/MIT-LICENSE +1 -1
- data/README.md +1 -1
- data/app/models/solid_queue/claimed_execution.rb +13 -1
- data/app/models/solid_queue/execution/dispatching.rb +20 -0
- data/app/models/solid_queue/execution/job_attributes.rb +4 -4
- data/app/models/solid_queue/execution.rb +44 -2
- data/app/models/solid_queue/failed_execution.rb +26 -16
- data/app/models/solid_queue/job/clearable.rb +4 -1
- data/app/models/solid_queue/job/concurrency_controls.rb +17 -1
- data/app/models/solid_queue/job/executable.rb +20 -9
- data/app/models/solid_queue/job/schedulable.rb +9 -1
- data/app/models/solid_queue/job.rb +3 -0
- data/app/models/solid_queue/queue.rb +1 -1
- data/app/models/solid_queue/ready_execution.rb +10 -0
- data/app/models/solid_queue/scheduled_execution.rb +3 -11
- data/app/models/solid_queue/semaphore.rb +75 -46
- data/db/migrate/20240110143450_add_missing_index_to_blocked_executions.rb +5 -0
- data/lib/active_job/uniqueness.rb +41 -0
- data/lib/generators/solid_queue/install/USAGE +2 -2
- data/lib/generators/solid_queue/install/templates/config.yml +1 -1
- data/lib/solid_queue/dispatcher/scheduled_executions_dispatcher.rb +6 -0
- data/lib/solid_queue/processes/runnable.rb +2 -2
- data/lib/solid_queue/version.rb +1 -1
- data/lib/solid_queue/worker.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0eb31439e2768af5f5d3fb9289ac51056570c762ad140bc54aba81ee770d5a12
|
4
|
+
data.tar.gz: 4d3e4c2608b0a3ed2de82c7712c8a524e8745bc4e2ddf6907de8b3723560ab04
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0f4271aaf7b55b86d81f97bf19bbfa2b76de1ff994a6b71bb097b89ab9585212f28c0fdbd4fbb86b74c18b49cf229e7913eaa724784b3a62f000d60c2ade3263
|
7
|
+
data.tar.gz: a84d91b13db4a3ec96d1afa5fb5f39abc9ea0bf4bc216c14e20f4bf7e1bf2ff414e08f78166377950351b8170cbd734aa69322feb9076a67a3f9939ebacf6573
|
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
@@ -31,7 +31,7 @@ $ bin/rails generate solid_queue:install
|
|
31
31
|
|
32
32
|
This will set `solid_queue` as the Active Job's adapter in production, and will copy the required migration over to your app.
|
33
33
|
|
34
|
-
Alternatively, you can add
|
34
|
+
Alternatively, you can add only the migration to your app:
|
35
35
|
```bash
|
36
36
|
$ bin/rails solid_queue:install:migrations
|
37
37
|
```
|
@@ -23,6 +23,14 @@ class SolidQueue::ClaimedExecution < SolidQueue::Execution
|
|
23
23
|
def release_all
|
24
24
|
includes(:job).each(&:release)
|
25
25
|
end
|
26
|
+
|
27
|
+
def discard_all_in_batches(*)
|
28
|
+
raise UndiscardableError, "Can't discard jobs in progress"
|
29
|
+
end
|
30
|
+
|
31
|
+
def discard_all_from_jobs(*)
|
32
|
+
raise UndiscardableError, "Can't discard jobs in progress"
|
33
|
+
end
|
26
34
|
end
|
27
35
|
|
28
36
|
def perform
|
@@ -39,11 +47,15 @@ class SolidQueue::ClaimedExecution < SolidQueue::Execution
|
|
39
47
|
|
40
48
|
def release
|
41
49
|
transaction do
|
42
|
-
job.
|
50
|
+
job.dispatch_bypassing_concurrency_limits
|
43
51
|
destroy!
|
44
52
|
end
|
45
53
|
end
|
46
54
|
|
55
|
+
def discard
|
56
|
+
raise UndiscardableError, "Can't discard a job in progress"
|
57
|
+
end
|
58
|
+
|
47
59
|
private
|
48
60
|
def execute
|
49
61
|
ActiveJob::Base.execute(job.arguments)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidQueue
|
4
|
+
class Execution
|
5
|
+
module Dispatching
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
class_methods do
|
9
|
+
def dispatch_jobs(job_ids)
|
10
|
+
jobs = Job.where(id: job_ids)
|
11
|
+
|
12
|
+
Job.dispatch_all(jobs).map(&:id).tap do |dispatched_job_ids|
|
13
|
+
where(job_id: dispatched_job_ids).delete_all
|
14
|
+
SolidQueue.logger.info("[SolidQueue] Dispatched #{dispatched_job_ids.size} jobs")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -6,23 +6,23 @@ module SolidQueue
|
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
included do
|
9
|
-
class_attribute :
|
9
|
+
class_attribute :assumable_attributes_from_job, instance_accessor: false, default: %i[ queue_name priority ]
|
10
10
|
end
|
11
11
|
|
12
12
|
class_methods do
|
13
13
|
def assumes_attributes_from_job(*attribute_names)
|
14
|
-
self.
|
14
|
+
self.assumable_attributes_from_job |= attribute_names
|
15
15
|
before_create -> { assume_attributes_from_job }
|
16
16
|
end
|
17
17
|
|
18
18
|
def attributes_from_job(job)
|
19
|
-
job.attributes.symbolize_keys.slice(*
|
19
|
+
job.attributes.symbolize_keys.slice(*assumable_attributes_from_job)
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
23
|
private
|
24
24
|
def assume_attributes_from_job
|
25
|
-
self.class.
|
25
|
+
self.class.assumable_attributes_from_job.each do |attribute|
|
26
26
|
send("#{attribute}=", job.send(attribute))
|
27
27
|
end
|
28
28
|
end
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
module SolidQueue
|
4
4
|
class Execution < Record
|
5
|
+
class UndiscardableError < StandardError; end
|
6
|
+
|
5
7
|
include JobAttributes
|
6
8
|
|
7
9
|
self.abstract_class = true
|
@@ -10,8 +12,6 @@ module SolidQueue
|
|
10
12
|
|
11
13
|
belongs_to :job
|
12
14
|
|
13
|
-
alias_method :discard, :destroy
|
14
|
-
|
15
15
|
class << self
|
16
16
|
def create_all_from_jobs(jobs)
|
17
17
|
insert_all execution_data_from_jobs(jobs)
|
@@ -22,6 +22,48 @@ module SolidQueue
|
|
22
22
|
attributes_from_job(job).merge(job_id: job.id)
|
23
23
|
end
|
24
24
|
end
|
25
|
+
|
26
|
+
def discard_all_in_batches(batch_size: 500)
|
27
|
+
pending = count
|
28
|
+
discarded = 0
|
29
|
+
|
30
|
+
loop do
|
31
|
+
transaction do
|
32
|
+
job_ids = limit(batch_size).order(:job_id).lock.pluck(:job_id)
|
33
|
+
|
34
|
+
discard_jobs job_ids
|
35
|
+
discarded = where(job_id: job_ids).delete_all
|
36
|
+
pending -= discarded
|
37
|
+
end
|
38
|
+
|
39
|
+
break if pending <= 0 || discarded == 0
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def discard_all_from_jobs(jobs)
|
44
|
+
transaction do
|
45
|
+
job_ids = lock_all_from_jobs(jobs)
|
46
|
+
|
47
|
+
discard_jobs job_ids
|
48
|
+
where(job_id: job_ids).delete_all
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
def lock_all_from_jobs(jobs)
|
54
|
+
where(job_id: jobs.map(&:id)).order(:job_id).lock.pluck(:job_id)
|
55
|
+
end
|
56
|
+
|
57
|
+
def discard_jobs(job_ids)
|
58
|
+
Job.where(id: job_ids).delete_all
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def discard
|
63
|
+
with_lock do
|
64
|
+
job.destroy
|
65
|
+
destroy
|
66
|
+
end
|
25
67
|
end
|
26
68
|
end
|
27
69
|
end
|
@@ -1,27 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
module SolidQueue
|
4
|
+
class FailedExecution < Execution
|
5
|
+
include Dispatching
|
5
6
|
|
6
|
-
|
7
|
+
serialize :error, coder: JSON
|
7
8
|
|
8
|
-
|
9
|
+
before_create :expand_error_details_from_exception
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
attr_accessor :exception
|
12
|
+
|
13
|
+
def self.retry_all(jobs)
|
14
|
+
transaction do
|
15
|
+
dispatch_jobs lock_all_from_jobs(jobs)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def retry
|
20
|
+
with_lock do
|
21
|
+
job.prepare_for_execution
|
22
|
+
destroy!
|
23
|
+
end
|
14
24
|
end
|
15
|
-
end
|
16
25
|
|
17
|
-
|
18
|
-
|
19
|
-
|
26
|
+
%i[ exception_class message backtrace ].each do |attribute|
|
27
|
+
define_method(attribute) { error.with_indifferent_access[attribute] }
|
28
|
+
end
|
20
29
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
30
|
+
private
|
31
|
+
def expand_error_details_from_exception
|
32
|
+
if exception
|
33
|
+
self.error = { exception_class: exception.class.name, message: exception.message, backtrace: exception.backtrace }
|
34
|
+
end
|
25
35
|
end
|
26
36
|
end
|
27
37
|
end
|
@@ -11,7 +11,10 @@ module SolidQueue
|
|
11
11
|
|
12
12
|
class_methods do
|
13
13
|
def clear_finished_in_batches(batch_size: 500, finished_before: SolidQueue.clear_finished_jobs_after.ago)
|
14
|
-
|
14
|
+
loop do
|
15
|
+
records_deleted = clearable(finished_before: finished_before).limit(batch_size).delete_all
|
16
|
+
break if records_deleted == 0
|
17
|
+
end
|
15
18
|
end
|
16
19
|
end
|
17
20
|
end
|
@@ -6,9 +6,17 @@ module SolidQueue
|
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
included do
|
9
|
-
has_one :blocked_execution
|
9
|
+
has_one :blocked_execution
|
10
10
|
|
11
11
|
delegate :concurrency_limit, :concurrency_duration, to: :job_class
|
12
|
+
|
13
|
+
before_destroy :unblock_next_blocked_job, if: -> { concurrency_limited? && ready? }
|
14
|
+
end
|
15
|
+
|
16
|
+
class_methods do
|
17
|
+
def release_all_concurrency_locks(jobs)
|
18
|
+
Semaphore.signal_all(jobs.select(&:concurrency_limited?))
|
19
|
+
end
|
12
20
|
end
|
13
21
|
|
14
22
|
def unblock_next_blocked_job
|
@@ -21,6 +29,10 @@ module SolidQueue
|
|
21
29
|
concurrency_key.present?
|
22
30
|
end
|
23
31
|
|
32
|
+
def blocked?
|
33
|
+
blocked_execution.present?
|
34
|
+
end
|
35
|
+
|
24
36
|
private
|
25
37
|
def acquire_concurrency_lock
|
26
38
|
return true unless concurrency_limited?
|
@@ -45,6 +57,10 @@ module SolidQueue
|
|
45
57
|
def job_class
|
46
58
|
@job_class ||= class_name.safe_constantize
|
47
59
|
end
|
60
|
+
|
61
|
+
def execution
|
62
|
+
super || blocked_execution
|
63
|
+
end
|
48
64
|
end
|
49
65
|
end
|
50
66
|
end
|
@@ -8,9 +8,9 @@ module SolidQueue
|
|
8
8
|
included do
|
9
9
|
include Clearable, ConcurrencyControls, Schedulable
|
10
10
|
|
11
|
-
has_one :ready_execution
|
12
|
-
has_one :claimed_execution
|
13
|
-
has_one :failed_execution
|
11
|
+
has_one :ready_execution
|
12
|
+
has_one :claimed_execution
|
13
|
+
has_one :failed_execution
|
14
14
|
|
15
15
|
after_create :prepare_for_execution
|
16
16
|
|
@@ -73,6 +73,10 @@ module SolidQueue
|
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
|
+
def dispatch_bypassing_concurrency_limits
|
77
|
+
ready
|
78
|
+
end
|
79
|
+
|
76
80
|
def finished!
|
77
81
|
if preserve_finished_jobs?
|
78
82
|
touch(:finished_at)
|
@@ -85,18 +89,22 @@ module SolidQueue
|
|
85
89
|
finished_at.present?
|
86
90
|
end
|
87
91
|
|
88
|
-
def
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
92
|
+
def status
|
93
|
+
if finished?
|
94
|
+
:finished
|
95
|
+
elsif execution.present?
|
96
|
+
execution.model_name.element.sub("_execution", "").to_sym
|
97
|
+
end
|
94
98
|
end
|
95
99
|
|
96
100
|
def retry
|
97
101
|
failed_execution&.retry
|
98
102
|
end
|
99
103
|
|
104
|
+
def discard
|
105
|
+
execution&.discard
|
106
|
+
end
|
107
|
+
|
100
108
|
def failed_with(exception)
|
101
109
|
FailedExecution.create_or_find_by!(job_id: id, exception: exception)
|
102
110
|
end
|
@@ -106,6 +114,9 @@ module SolidQueue
|
|
106
114
|
ReadyExecution.create_or_find_by!(job_id: id)
|
107
115
|
end
|
108
116
|
|
117
|
+
def execution
|
118
|
+
%w[ ready claimed failed ].reduce(nil) { |acc, status| acc || public_send("#{status}_execution") }
|
119
|
+
end
|
109
120
|
|
110
121
|
def preserve_finished_jobs?
|
111
122
|
SolidQueue.preserve_finished_jobs
|
@@ -6,7 +6,7 @@ module SolidQueue
|
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
included do
|
9
|
-
has_one :scheduled_execution
|
9
|
+
has_one :scheduled_execution
|
10
10
|
|
11
11
|
scope :scheduled, -> { where.not(finished_at: nil) }
|
12
12
|
end
|
@@ -31,10 +31,18 @@ module SolidQueue
|
|
31
31
|
scheduled_at.nil? || scheduled_at <= Time.current
|
32
32
|
end
|
33
33
|
|
34
|
+
def scheduled?
|
35
|
+
scheduled_execution.present?
|
36
|
+
end
|
37
|
+
|
34
38
|
private
|
35
39
|
def schedule
|
36
40
|
ScheduledExecution.create_or_find_by!(job_id: id)
|
37
41
|
end
|
42
|
+
|
43
|
+
def execution
|
44
|
+
super || scheduled_execution
|
45
|
+
end
|
38
46
|
end
|
39
47
|
end
|
40
48
|
end
|
@@ -15,9 +15,12 @@ module SolidQueue
|
|
15
15
|
prepare_all_for_execution(jobs).tap do |enqueued_jobs|
|
16
16
|
enqueued_jobs.each do |enqueued_job|
|
17
17
|
active_jobs_by_job_id[enqueued_job.active_job_id].provider_job_id = enqueued_job.id
|
18
|
+
active_jobs_by_job_id[enqueued_job.active_job_id].successfully_enqueued = true
|
18
19
|
end
|
19
20
|
end
|
20
21
|
end
|
22
|
+
|
23
|
+
active_jobs.count(&:successfully_enqueued?)
|
21
24
|
end
|
22
25
|
|
23
26
|
def enqueue(active_job, scheduled_at: Time.current)
|
@@ -15,6 +15,10 @@ module SolidQueue
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
+
def aggregated_count_across(queue_list)
|
19
|
+
QueueSelector.new(queue_list, self).scoped_relations.map(&:count).sum
|
20
|
+
end
|
21
|
+
|
18
22
|
private
|
19
23
|
def select_and_lock(queue_relation, process_id, limit)
|
20
24
|
return [] if limit <= 0
|
@@ -36,6 +40,12 @@ module SolidQueue
|
|
36
40
|
where(job_id: claimed.pluck(:job_id)).delete_all
|
37
41
|
end
|
38
42
|
end
|
43
|
+
|
44
|
+
|
45
|
+
def discard_jobs(job_ids)
|
46
|
+
Job.release_all_concurrency_locks Job.where(id: job_ids)
|
47
|
+
super
|
48
|
+
end
|
39
49
|
end
|
40
50
|
end
|
41
51
|
end
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
module SolidQueue
|
4
4
|
class ScheduledExecution < Execution
|
5
|
+
include Dispatching
|
6
|
+
|
5
7
|
scope :due, -> { where(scheduled_at: ..Time.current) }
|
6
8
|
scope :ordered, -> { order(scheduled_at: :asc, priority: :asc) }
|
7
9
|
scope :next_batch, ->(batch_size) { due.ordered.limit(batch_size) }
|
@@ -14,20 +16,10 @@ module SolidQueue
|
|
14
16
|
job_ids = next_batch(batch_size).non_blocking_lock.pluck(:job_id)
|
15
17
|
if job_ids.empty? then []
|
16
18
|
else
|
17
|
-
|
19
|
+
dispatch_jobs(job_ids)
|
18
20
|
end
|
19
21
|
end
|
20
22
|
end
|
21
|
-
|
22
|
-
private
|
23
|
-
def dispatch_batch(job_ids)
|
24
|
-
jobs = Job.where(id: job_ids)
|
25
|
-
|
26
|
-
Job.dispatch_all(jobs).map(&:id).tap do |dispatched_job_ids|
|
27
|
-
where(job_id: dispatched_job_ids).delete_all
|
28
|
-
SolidQueue.logger.info("[SolidQueue] Dispatched scheduled batch with #{dispatched_job_ids.size} jobs")
|
29
|
-
end
|
30
|
-
end
|
31
23
|
end
|
32
24
|
end
|
33
25
|
end
|
@@ -1,65 +1,94 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
module SolidQueue
|
4
|
+
class Semaphore < Record
|
5
|
+
scope :available, -> { where("value > 0") }
|
6
|
+
scope :expired, -> { where(expires_at: ...Time.current) }
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
def signal(job)
|
13
|
-
Proxy.new(job, self).signal
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
class Proxy
|
18
|
-
def initialize(job, proxied_class)
|
19
|
-
@job = job
|
20
|
-
@proxied_class = proxied_class
|
21
|
-
end
|
8
|
+
class << self
|
9
|
+
def wait(job)
|
10
|
+
Proxy.new(job).wait
|
11
|
+
end
|
22
12
|
|
23
|
-
|
24
|
-
|
25
|
-
semaphore.value > 0 && attempt_decrement
|
26
|
-
else
|
27
|
-
attempt_creation
|
13
|
+
def signal(job)
|
14
|
+
Proxy.new(job).signal
|
28
15
|
end
|
29
|
-
end
|
30
16
|
|
31
|
-
|
32
|
-
|
17
|
+
def signal_all(jobs)
|
18
|
+
Proxy.signal_all(jobs)
|
19
|
+
end
|
33
20
|
end
|
34
21
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
def attempt_creation
|
39
|
-
proxied_class.create!(key: key, value: limit - 1, expires_at: expires_at)
|
40
|
-
true
|
41
|
-
rescue ActiveRecord::RecordNotUnique
|
42
|
-
attempt_decrement
|
22
|
+
class Proxy
|
23
|
+
def self.signal_all(jobs)
|
24
|
+
Semaphore.where(key: jobs.map(&:concurrency_key)).update_all("value = value + 1")
|
43
25
|
end
|
44
26
|
|
45
|
-
def
|
46
|
-
|
27
|
+
def initialize(job)
|
28
|
+
@job = job
|
29
|
+
@retries = 0
|
47
30
|
end
|
48
31
|
|
49
|
-
def
|
50
|
-
|
32
|
+
def wait
|
33
|
+
if semaphore = Semaphore.find_by(key: key)
|
34
|
+
semaphore.value > 0 && attempt_decrement
|
35
|
+
else
|
36
|
+
attempt_creation
|
37
|
+
end
|
51
38
|
end
|
52
39
|
|
53
|
-
def
|
54
|
-
|
40
|
+
def signal
|
41
|
+
attempt_increment
|
55
42
|
end
|
56
43
|
|
57
|
-
|
58
|
-
job
|
59
|
-
end
|
44
|
+
private
|
45
|
+
attr_accessor :job, :retries
|
60
46
|
|
61
|
-
|
62
|
-
|
63
|
-
|
47
|
+
def attempt_creation
|
48
|
+
Semaphore.create!(key: key, value: limit - 1, expires_at: expires_at)
|
49
|
+
true
|
50
|
+
rescue ActiveRecord::RecordNotUnique
|
51
|
+
attempt_decrement
|
52
|
+
end
|
53
|
+
|
54
|
+
def attempt_decrement
|
55
|
+
Semaphore.available.where(key: key).update_all([ "value = value - 1, expires_at = ?", expires_at ]) > 0
|
56
|
+
rescue ActiveRecord::Deadlocked
|
57
|
+
if retriable? then attempt_retry
|
58
|
+
else
|
59
|
+
raise
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def attempt_increment
|
64
|
+
Semaphore.where(key: key, value: ...limit).update_all([ "value = value + 1, expires_at = ?", expires_at ]) > 0
|
65
|
+
end
|
66
|
+
|
67
|
+
def attempt_retry
|
68
|
+
self.retries += 1
|
69
|
+
|
70
|
+
if semaphore = Semaphore.find_by(key: key)
|
71
|
+
semaphore.value > 0 && attempt_decrement
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
MAX_RETRIES = 1
|
76
|
+
|
77
|
+
def retriable?
|
78
|
+
retries < MAX_RETRIES
|
79
|
+
end
|
80
|
+
|
81
|
+
def key
|
82
|
+
job.concurrency_key
|
83
|
+
end
|
84
|
+
|
85
|
+
def expires_at
|
86
|
+
job.concurrency_duration.from_now
|
87
|
+
end
|
88
|
+
|
89
|
+
def limit
|
90
|
+
job.concurrency_limit
|
91
|
+
end
|
92
|
+
end
|
64
93
|
end
|
65
94
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveJob
|
4
|
+
module Uniqueness
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
DEFAULT_UNIQUENESS_GROUP = ->(*) { self.class.name }
|
8
|
+
|
9
|
+
included do
|
10
|
+
class_attribute :uniqueness_key, instance_accessor: false
|
11
|
+
class_attribute :uniqueness_group, default: DEFAULT_UNIQUENESS_GROUP, instance_accessor: false
|
12
|
+
|
13
|
+
class_attribute :uniqueness_duration
|
14
|
+
end
|
15
|
+
|
16
|
+
class_methods do
|
17
|
+
def enqueued_uniquely_by(key:, group: DEFAULT_UNIQUENESS_GROUP, duration: SolidQueue.default_uniqueness_period)
|
18
|
+
self.uniqueness_key = key
|
19
|
+
self.uniqueness_group = group
|
20
|
+
self.uniqueness_duration = duration
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def uniqueness_key
|
25
|
+
if self.class.uniqueness_key
|
26
|
+
param = compute_concurrency_parameter(self.class.concurrency_key)
|
27
|
+
|
28
|
+
case param
|
29
|
+
when ActiveRecord::Base
|
30
|
+
[ concurrency_group, param.class.name, param.id ]
|
31
|
+
else
|
32
|
+
[ concurrency_group, param ]
|
33
|
+
end.compact.join("/")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def enqueued_uniquely?
|
38
|
+
uniqueness_key.present?
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -4,6 +4,6 @@ Description:
|
|
4
4
|
Example:
|
5
5
|
bin/rails generate solid_queue:install
|
6
6
|
|
7
|
-
This will
|
7
|
+
This will perform the following:
|
8
8
|
Installs solid_queue migrations
|
9
|
-
Replaces Active Job's adapter in
|
9
|
+
Replaces Active Job's adapter in environment configuration
|
@@ -4,6 +4,8 @@ module SolidQueue::Processes
|
|
4
4
|
module Runnable
|
5
5
|
include Supervised
|
6
6
|
|
7
|
+
attr_writer :mode
|
8
|
+
|
7
9
|
def start
|
8
10
|
@stopping = false
|
9
11
|
|
@@ -19,8 +21,6 @@ module SolidQueue::Processes
|
|
19
21
|
end
|
20
22
|
|
21
23
|
private
|
22
|
-
attr_writer :mode
|
23
|
-
|
24
24
|
DEFAULT_MODE = :async
|
25
25
|
|
26
26
|
def mode
|
data/lib/solid_queue/version.rb
CHANGED
data/lib/solid_queue/worker.rb
CHANGED
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.2.
|
4
|
+
version: 0.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: 2024-01-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -79,6 +79,7 @@ files:
|
|
79
79
|
- app/models/solid_queue/blocked_execution.rb
|
80
80
|
- app/models/solid_queue/claimed_execution.rb
|
81
81
|
- app/models/solid_queue/execution.rb
|
82
|
+
- app/models/solid_queue/execution/dispatching.rb
|
82
83
|
- app/models/solid_queue/execution/job_attributes.rb
|
83
84
|
- app/models/solid_queue/failed_execution.rb
|
84
85
|
- app/models/solid_queue/job.rb
|
@@ -97,8 +98,10 @@ files:
|
|
97
98
|
- app/models/solid_queue/semaphore.rb
|
98
99
|
- config/routes.rb
|
99
100
|
- db/migrate/20231211200639_create_solid_queue_tables.rb
|
101
|
+
- db/migrate/20240110143450_add_missing_index_to_blocked_executions.rb
|
100
102
|
- lib/active_job/concurrency_controls.rb
|
101
103
|
- lib/active_job/queue_adapters/solid_queue_adapter.rb
|
104
|
+
- lib/active_job/uniqueness.rb
|
102
105
|
- lib/generators/solid_queue/install/USAGE
|
103
106
|
- lib/generators/solid_queue/install/install_generator.rb
|
104
107
|
- lib/generators/solid_queue/install/templates/config.yml
|
@@ -107,6 +110,7 @@ files:
|
|
107
110
|
- lib/solid_queue/app_executor.rb
|
108
111
|
- lib/solid_queue/configuration.rb
|
109
112
|
- lib/solid_queue/dispatcher.rb
|
113
|
+
- lib/solid_queue/dispatcher/scheduled_executions_dispatcher.rb
|
110
114
|
- lib/solid_queue/engine.rb
|
111
115
|
- lib/solid_queue/pool.rb
|
112
116
|
- lib/solid_queue/processes/base.rb
|