Skip to content

Commit c9b90d3

Browse files
committed
Implement job batches
1 parent 98b8c35 commit c9b90d3

File tree

4 files changed

+94
-0
lines changed

4 files changed

+94
-0
lines changed

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,24 @@ class MyJob < ActiveJob::Base
324324
end
325325
```
326326

327+
### Grouping jobs into batches
328+
329+
```ruby
330+
job = MyJob.perform_later
331+
other_job = OtherJob.perform_later
332+
333+
batch = ActiveJob::Status::Batch.new(job, other_job)
334+
batch.status
335+
# "queued"
336+
```
337+
338+
The batch status can be `queued`, `failed`, `completed` or `working`.
339+
340+
1. The batch is considered `queued` if **all** of the jobs are `queued`
341+
2. The batch is considered `failed` if **one** of the jobs is `failed`
342+
3. The batch is considered `completed` if **all** of the jobs are `completed`
343+
4. The batch is considered `working` in all other circumstances
344+
327345
## ActiveJob::Status and exceptions
328346

329347
Internally, ActiveJob::Status uses `ActiveSupport#rescue_from` to catch every `Exception` to apply the `failed` status

lib/activejob-status.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
require "activejob-status/status"
99
require "activejob-status/progress"
1010
require "activejob-status/throttle"
11+
require "activejob-status/batch"
1112

1213
module ActiveJob
1314
module Status

lib/activejob-status/batch.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# frozen_string_literal: true
2+
3+
module ActiveJob
4+
module Status
5+
class Batch
6+
def initialize(*jobs)
7+
@statuses = jobs.map { |job| ActiveJob::Status.get(job) }
8+
end
9+
10+
def status
11+
if @statuses.all? { |status| status[:status] == :queued }
12+
:queued
13+
elsif @statuses.any? { |status| status[:status] == :failed }
14+
:failed
15+
elsif @statuses.all? { |status| status[:status] == :completed }
16+
:completed
17+
else
18+
:working
19+
end
20+
end
21+
end
22+
end
23+
end
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# frozen_string_literal: true
2+
3+
require_relative "../../../spec_helper"
4+
require_relative "../../../jobs/test_jobs"
5+
6+
RSpec.describe ActiveJob::Status::Batch do
7+
describe "#status" do
8+
it "returns queued when all jobs are queued" do
9+
first_job = BaseJob.perform_later
10+
second_job = BaseJob.perform_later
11+
batch = described_class.new(first_job, second_job)
12+
13+
ActiveJob::Status.get(first_job).update(status: :queued)
14+
ActiveJob::Status.get(second_job).update(status: :queued)
15+
16+
expect(batch.status).to eq(:queued)
17+
end
18+
19+
it "returns failed when one job is failed" do
20+
first_job = BaseJob.perform_later
21+
second_job = BaseJob.perform_later
22+
batch = described_class.new(first_job, second_job)
23+
24+
ActiveJob::Status.get(first_job).update(status: :failed)
25+
ActiveJob::Status.get(second_job).update(status: :completed)
26+
27+
expect(batch.status).to eq(:failed)
28+
end
29+
30+
it "returns completed when all jobs are completed" do
31+
first_job = BaseJob.perform_later
32+
second_job = BaseJob.perform_later
33+
batch = described_class.new(first_job, second_job)
34+
35+
ActiveJob::Status.get(first_job).update(status: :completed)
36+
ActiveJob::Status.get(second_job).update(status: :completed)
37+
38+
expect(batch.status).to eq(:completed)
39+
end
40+
41+
it "returns working in other cases" do
42+
first_job = BaseJob.perform_later
43+
second_job = BaseJob.perform_later
44+
batch = described_class.new(first_job, second_job)
45+
46+
ActiveJob::Status.get(first_job).update(status: :queued)
47+
ActiveJob::Status.get(second_job).update(status: :working)
48+
49+
expect(batch.status).to eq(:working)
50+
end
51+
end
52+
end

0 commit comments

Comments
 (0)