angry_batch 1.0.0 → 1.0.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/CHANGELOG.md +5 -0
- data/README.md +10 -2
- data/lib/angry_batch/batch.rb +17 -21
- data/lib/angry_batch/batchable.rb +4 -0
- data/lib/angry_batch/builder.rb +28 -15
- data/lib/angry_batch/handle.rb +21 -1
- data/lib/angry_batch/version.rb +1 -1
- metadata +2 -3
- data/sig/angry_batch.rbs +0 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8363c90cc908a4ae3fa64957ebfc422580dd91041dfd32d0d2eb7607e9130a62
|
|
4
|
+
data.tar.gz: b83a95d6938a4ad2e2cc20d3e7fc9edbd0f998e7c1256749d7c2ba6c90f22a04
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1ab00df9aef51980652bb56151d43ce16af63aa58a2e41f31badcb90f50b2687c9e74e119f6d77fa9f3113f6fb88aa441e2e0988275ef732942ab20f8f73f2e0
|
|
7
|
+
data.tar.gz: bba22c7ff6de71cdd1bfe285aeaead5163140536a19e2142e1e163b57dcec50ec0262519b2148a7ebed2db30cc4274d16200c6d0e576372684bf3633568e150a
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# AngryBatch
|
|
2
2
|
|
|
3
3
|

|
|
4
|
+
[](http://badge.fury.io/rb/angry_batch)
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
**AngryBatch** is a lightweight batching utility for [ActiveJob](https://guides.rubyonrails.org/active_job_basics.html) that lets you group multiple jobs into a batch and trigger follow-up jobs when all jobs in the batch are done.
|
|
6
|
+
**AngryBatch** is a batching utility for [ActiveJob](https://guides.rubyonrails.org/active_job_basics.html) that lets you group multiple jobs into a batch and trigger follow-up jobs when all jobs in the batch are done.
|
|
7
7
|
|
|
8
8
|
## Installation
|
|
9
9
|
|
|
@@ -61,6 +61,14 @@ queue.enqueue SomeJob, argument3
|
|
|
61
61
|
in the queue.perform_later
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
+
### Cleaning completed jobs
|
|
65
|
+
|
|
66
|
+
`AngryBatch` stores jobs in the database. You have to run `AngryBatch::CleanupCronJob` in a cron to clean the records.
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
AngryBatch::CleanupCronJob.perform
|
|
70
|
+
```
|
|
71
|
+
|
|
64
72
|
### Example
|
|
65
73
|
|
|
66
74
|
**Example 1**
|
data/lib/angry_batch/batch.rb
CHANGED
|
@@ -32,40 +32,36 @@ class AngryBatch::Batch < ActiveRecord::Base
|
|
|
32
32
|
|
|
33
33
|
class << self
|
|
34
34
|
def expired
|
|
35
|
-
completed
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
completed.or(failed).or(pending)
|
|
35
|
+
completed.where(updated_at: ...2.days.ago)
|
|
36
|
+
.or(failed.where(updated_at: ...4.weeks.ago))
|
|
37
|
+
.or(pending.where(updated_at: ...4.weeks.ago))
|
|
40
38
|
end
|
|
41
39
|
end
|
|
42
40
|
|
|
43
41
|
def check_status_of_jobs
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
self.finished_at = Time.current
|
|
42
|
+
handlers_to_enqueue = with_lock do
|
|
43
|
+
return unless pending?
|
|
44
|
+
return unless jobs_count == jobs.finished.count
|
|
48
45
|
|
|
49
|
-
|
|
50
|
-
update! state: 'completed'
|
|
46
|
+
self.finished_at = Time.current
|
|
51
47
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
48
|
+
if jobs.failed.none?
|
|
49
|
+
update! state: 'completed'
|
|
50
|
+
complete_handlers
|
|
51
|
+
else
|
|
52
|
+
update! state: 'failed'
|
|
53
|
+
failure_handlers
|
|
54
|
+
end
|
|
57
55
|
end
|
|
56
|
+
|
|
57
|
+
enqueue_handlers(handlers_to_enqueue)
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
private
|
|
61
61
|
|
|
62
62
|
def enqueue_handlers(handlers)
|
|
63
63
|
handlers.each do |(job_class, job_arguments)|
|
|
64
|
-
|
|
65
|
-
job_class.constantize.perform_later
|
|
66
|
-
else
|
|
67
|
-
job_class.constantize.perform_later(*ActiveJob::Arguments.deserialize(job_arguments))
|
|
68
|
-
end
|
|
64
|
+
job_class.constantize.perform_later(*ActiveJob::Arguments.deserialize(job_arguments || []))
|
|
69
65
|
end
|
|
70
66
|
end
|
|
71
67
|
end
|
data/lib/angry_batch/builder.rb
CHANGED
|
@@ -9,31 +9,32 @@ class AngryBatch::Builder
|
|
|
9
9
|
failure_handlers: [],
|
|
10
10
|
)
|
|
11
11
|
@jobs = []
|
|
12
|
+
@performed = false
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
def performed?
|
|
15
|
-
@
|
|
16
|
+
@performed
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
delegate :empty?, to: :@jobs
|
|
19
20
|
|
|
20
21
|
def on_complete(job_class, *, **)
|
|
21
22
|
raise AngryBatch::BatchArgumentError, 'Batch is already running' if performed?
|
|
22
|
-
raise AngryBatch::BatchArgumentError, "#{job_class} be a subclass of ActiveJob::Base" unless job_class.is_a?(Class) && job_class < ActiveJob::Base
|
|
23
|
+
raise AngryBatch::BatchArgumentError, "#{job_class} must be a subclass of ActiveJob::Base" unless job_class.is_a?(Class) && job_class < ActiveJob::Base
|
|
23
24
|
|
|
24
25
|
@batch.complete_handlers << [job_class, job_class.new(*, **).serialize['arguments']]
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
def on_failure(job_class, *, **)
|
|
28
29
|
raise AngryBatch::BatchArgumentError, 'Batch is already running' if performed?
|
|
29
|
-
raise AngryBatch::BatchArgumentError, "#{job_class} be a subclass of ActiveJob::Base" unless job_class.is_a?(Class) && job_class < ActiveJob::Base
|
|
30
|
+
raise AngryBatch::BatchArgumentError, "#{job_class} must be a subclass of ActiveJob::Base" unless job_class.is_a?(Class) && job_class < ActiveJob::Base
|
|
30
31
|
|
|
31
32
|
@batch.failure_handlers << [job_class, job_class.new(*, **).serialize['arguments']]
|
|
32
33
|
end
|
|
33
34
|
|
|
34
35
|
def enqueue(job_class, *, **)
|
|
35
|
-
raise AngryBatch::BatchArgumentError, 'Batch is already running'
|
|
36
|
-
raise AngryBatch::BatchArgumentError, "#{job_class} be a subclass of ActiveJob::Base" unless job_class.is_a?(Class) && job_class < ActiveJob::Base
|
|
36
|
+
raise AngryBatch::BatchArgumentError, 'Batch is already running' if performed?
|
|
37
|
+
raise AngryBatch::BatchArgumentError, "#{job_class} must be a subclass of ActiveJob::Base" unless job_class.is_a?(Class) && job_class < ActiveJob::Base
|
|
37
38
|
raise AngryBatch::BatchArgumentError, "#{job_class} must include AngryBatch::Batchable" unless job_class.included_modules.include?(AngryBatch::Batchable)
|
|
38
39
|
|
|
39
40
|
@jobs << job_class.new(*, **)
|
|
@@ -43,20 +44,32 @@ class AngryBatch::Builder
|
|
|
43
44
|
raise AngryBatch::BatchArgumentError, 'Batch is empty' if empty?
|
|
44
45
|
raise AngryBatch::BatchArgumentError, 'Batch is already running' if performed?
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
ActiveRecord::Base.transaction(requires_new: true) do
|
|
48
|
+
@batch.save!
|
|
47
49
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
@jobs.each do |job|
|
|
51
|
+
@batch.jobs.create!(
|
|
52
|
+
active_job_idx: job.job_id,
|
|
53
|
+
active_job_class: job.class.name,
|
|
54
|
+
active_job_arguments: job.serialize['arguments'],
|
|
55
|
+
)
|
|
56
|
+
end
|
|
54
57
|
|
|
55
|
-
|
|
58
|
+
@batch.update!(state: 'pending')
|
|
56
59
|
end
|
|
57
60
|
|
|
58
|
-
@
|
|
59
|
-
@
|
|
61
|
+
@performed = true
|
|
62
|
+
@jobs.each(&:enqueue)
|
|
60
63
|
@batch.check_status_of_jobs
|
|
64
|
+
rescue
|
|
65
|
+
unless @performed
|
|
66
|
+
@batch = AngryBatch::Batch.new(
|
|
67
|
+
label: @batch.label,
|
|
68
|
+
state: 'scheduling',
|
|
69
|
+
complete_handlers: @batch.complete_handlers,
|
|
70
|
+
failure_handlers: @batch.failure_handlers,
|
|
71
|
+
)
|
|
72
|
+
end
|
|
73
|
+
raise
|
|
61
74
|
end
|
|
62
75
|
end
|
data/lib/angry_batch/handle.rb
CHANGED
|
@@ -9,9 +9,29 @@ module AngryBatch::Handle
|
|
|
9
9
|
return if record.blank?
|
|
10
10
|
|
|
11
11
|
record.with_lock do
|
|
12
|
+
return if record.failed?
|
|
13
|
+
|
|
12
14
|
record.update!(state: 'completed')
|
|
13
15
|
end
|
|
14
16
|
|
|
15
|
-
record.batch
|
|
17
|
+
record.batch&.check_status_of_jobs
|
|
18
|
+
rescue ActiveRecord::RecordNotFound
|
|
19
|
+
nil
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def job_failed(job, exception = nil)
|
|
23
|
+
record = AngryBatch::Job.find_by(active_job_idx: job.job_id)
|
|
24
|
+
|
|
25
|
+
return if record.blank?
|
|
26
|
+
|
|
27
|
+
record.with_lock do
|
|
28
|
+
return if record.completed?
|
|
29
|
+
|
|
30
|
+
record.update!(state: 'failed', error_message: exception&.message)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
record.batch&.check_status_of_jobs
|
|
34
|
+
rescue ActiveRecord::RecordNotFound
|
|
35
|
+
nil
|
|
16
36
|
end
|
|
17
37
|
end
|
data/lib/angry_batch/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: angry_batch
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Radoslav Stankov
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-05-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activejob
|
|
@@ -259,7 +259,6 @@ files:
|
|
|
259
259
|
- lib/angry_batch/version.rb
|
|
260
260
|
- lib/generators/angry_batch/install_generator.rb
|
|
261
261
|
- lib/generators/angry_batch/templates/create_angry_batch_tables.rb
|
|
262
|
-
- sig/angry_batch.rbs
|
|
263
262
|
homepage: https://github.com/RStankov/AngryBatch
|
|
264
263
|
licenses:
|
|
265
264
|
- MIT
|
data/sig/angry_batch.rbs
DELETED