active_job_status 1.1.0 → 1.2.0

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
  SHA1:
3
- metadata.gz: d6b9ef8fd6afc49dd42ddff3b89715f7f0bc3c24
4
- data.tar.gz: d577c498e486282b0d39346925321696632c2a63
3
+ metadata.gz: 5431b8cc6fed8a99592123c01fc9357cf4a46192
4
+ data.tar.gz: bd92db0a996e02e8ac1cabdb1af6d9e8092de953
5
5
  SHA512:
6
- metadata.gz: 296968828f08cbc8aea202ee67cd135337ad2722ddd7f6c8c9eb69aa2bc23f6dcac85ccb273daa299f1165e6d88db70a857ad9727637a44a8952ff7e73c6ce18
7
- data.tar.gz: 6dc29bb46f45a5e91a839a595c05687fd18a01dbecd626d6c194116c7a5f1b4a9159ba94ce3833f18585b606f5e5b30e9398a0b84bcd5264ace27b2fe799a7e7
6
+ metadata.gz: 1e081751d977356a0315b686321c526e02ddc881b5e8624c59434a187bb40625aa452ca31188a6d7905550eadb93dd0c2f8c03d02390c3c3913f61e4da730480
7
+ data.tar.gz: 88df222fab4619634fe7073fc024b691c649bbd22df91c5261a9f304e3eaff9117f35ab2a05ff903e6c303a002650f5baa86884c8fd74758f51868a85daefb0f
data/.gitignore CHANGED
@@ -15,3 +15,4 @@
15
15
  mkmf.log
16
16
  .DS_Store
17
17
  *.swp
18
+ *.gem
data/.travis.yml CHANGED
@@ -1,7 +1,7 @@
1
1
  language: ruby
2
2
  cache: bundler
3
3
  rvm:
4
- - 2.2.0
4
+ - 2.3.1
5
5
  script: bundle exec rake
6
6
  services:
7
7
  - redis
data/CHANGELOG.md CHANGED
@@ -1,4 +1,8 @@
1
1
  # ActiveJobStatus
2
+ ## 1.2.0
3
+ - Add support for Rails 5
4
+ - Adds many small improvements (see https://github.com/cdale77/active_job_status/pull/15)
5
+
2
6
  ## 1.1.0
3
7
  - Add support for Redis via the Readthis gem
4
8
 
data/README.md CHANGED
@@ -46,6 +46,8 @@ ActiveJob status will detect Redis and use some nice optimizations.
46
46
 
47
47
  # config/initializers/active_job_status.rb
48
48
  ActiveJobStatus.store = ActiveSupport::Cache::RedisStore.new
49
+ # or if you are using https://github.com/sorentwo/readthis
50
+ ActiveJobStatus.store = ActiveSupport::Cache::ReadthisStore.new
49
51
 
50
52
  ## Usage
51
53
 
@@ -58,6 +60,24 @@ upgrading from versions < 1.0, you may need to update your code.*
58
60
  class MyJob < ActiveJobStatus::TrackableJob
59
61
  end
60
62
 
63
+ Or you can just include ActiveJobStatus::Hooks into your job if you are using
64
+ version 1.2 or greater. You might want to use this approach if you are using an
65
+ `ApplicationJob` and do not want all your jobs to be trackable.
66
+
67
+ class MyJob < ActiveJob::Base
68
+ include ActiveJobStatus::Hooks
69
+ end
70
+
71
+ or
72
+
73
+ class MyJob < ApplicationJob
74
+ include ActiveJobStatus::Hooks
75
+ end
76
+
77
+ class ApplicationJob < ActiveJob::Base
78
+ end
79
+
80
+
61
81
  ### Job Status
62
82
 
63
83
  Check the status of a job using the ActiveJob job_id. Status of a job will only
@@ -65,8 +85,12 @@ be available for 72 hours after the job is queued. For right now you can't
65
85
  change that.
66
86
 
67
87
  my_job = MyJob.perform_later
68
- ActiveJobStatus::JobStatus.get_status(job_id: my_job.job_id)
69
- # => :queued, :working, :complete
88
+ job_status = ActiveJobStatus.fetch(my_job.job_id)
89
+ job_status.queued?
90
+ job_status.working?
91
+ job_status.completed?
92
+ job_status.status
93
+ # => :queued, :working, :completed, nil
70
94
 
71
95
  ### Job Batches
72
96
  For job batches you an use any key you want (for example, you might use a
@@ -106,7 +130,8 @@ You can ask the batch for other bits of information:
106
130
  You can also search for batches:
107
131
  ActiveJobStatus::JobBatch.find(batch_id: my_key)
108
132
 
109
- This method will return nil no associated job ids can be found, otherwise it will
133
+ This method will return nil if no associated job ids can be found, otherwise it will
134
+ This method will return nil no associated job ids can be found, otherwise it will
110
135
  return an ActiveJobStatus::JobBatch object.
111
136
 
112
137
  ## Contributing
@@ -23,8 +23,8 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "rspec", "~> 3.0"
24
24
  spec.add_development_dependency "codeclimate-test-reporter", "~> 0.4"
25
25
 
26
- spec.add_runtime_dependency "activejob", "~>4.2"
27
- spec.add_runtime_dependency "activesupport", "~>4.2"
26
+ spec.add_runtime_dependency "activejob", "> 4.2"
27
+ spec.add_runtime_dependency "activesupport", "> 4.2"
28
28
 
29
29
  spec.post_install_message = "If updating from a version below 1.0, please note " \
30
30
  "TrackabeJob is now namespaced inside of ActiveJob. " \
@@ -1,3 +1,4 @@
1
+ require "active_job_status/hooks"
1
2
  require "active_job_status/trackable_job"
2
3
  require "active_job_status/job_tracker"
3
4
  require "active_job_status/job_status"
@@ -7,7 +8,15 @@ require "active_job_status/configure_redis" if defined? Rails
7
8
 
8
9
  module ActiveJobStatus
9
10
  class << self
10
- attr_accessor :store
11
+ attr_accessor :store, :expiration
12
+
13
+ def get_status(job_id)
14
+ fetch(job_id).status
15
+ end
16
+
17
+ def fetch(job_id)
18
+ status = store.fetch(job_id)
19
+ JobStatus.new(status)
20
+ end
11
21
  end
12
22
  end
13
-
@@ -1,7 +1,7 @@
1
1
  require 'rails'
2
2
  class ConfigureRedis < Rails::Railtie
3
3
  initializer "configure_redis.configure_rails_initializers" do
4
- if defined? ActiveSupport::Cache::RedisStore
4
+ if defined? ActiveSupport::Cache::RedisStore || defined? ActiveSupport::Cache::ReadthisStore
5
5
  require "active_job_status/redis"
6
6
  end
7
7
  end
@@ -0,0 +1,19 @@
1
+ module ActiveJobStatus
2
+ module Hooks
3
+ def self.included(base)
4
+ base.class_eval do
5
+ before_enqueue { job_tracker.enqueued }
6
+
7
+ before_perform { job_tracker.performing }
8
+
9
+ after_perform { job_tracker.completed }
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def job_tracker
16
+ @job_tracker ||= ActiveJobStatus::JobTracker.new(job_id: job_id)
17
+ end
18
+ end
19
+ end
@@ -14,7 +14,7 @@ module ActiveJobStatus
14
14
 
15
15
  def store_data(expire_in:)
16
16
  ActiveJobStatus.store.delete(@batch_id) # delete any old batches
17
- if ActiveJobStatus.store.class.to_s == "ActiveSupport::Cache::RedisStore"
17
+ if ["ActiveSupport::Cache::RedisStore", "ActiveSupport::Cache::ReadthisStore"].include? ActiveJobStatus.store.class.to_s
18
18
  ActiveJobStatus.store.sadd(@batch_id, @job_ids)
19
19
  ActiveJobStatus.store.expire(@batch_id, expire_in)
20
20
  else
@@ -24,7 +24,7 @@ module ActiveJobStatus
24
24
 
25
25
  def add_jobs(job_ids:)
26
26
  @job_ids = @job_ids + job_ids
27
- if ActiveJobStatus.store.class.to_s == "ActiveSupport::Cache::RedisStore"
27
+ if ["ActiveSupport::Cache::RedisStore", "ActiveSupport::Cache::ReadthisStore"].include? ActiveJobStatus.store.class.to_s
28
28
  # Save an extra redis query and perform atomic operation
29
29
  ActiveJobStatus.store.sadd(@batch_id, job_ids)
30
30
  else
@@ -34,15 +34,14 @@ module ActiveJobStatus
34
34
  end
35
35
 
36
36
  def completed?
37
- job_statuses = []
38
- @job_ids.each do |job_id|
39
- job_statuses << ActiveJobStatus::JobStatus.get_status(job_id: job_id)
40
- end
41
- !job_statuses.any?
37
+ @job_ids.map do |job_id|
38
+ job_status = ActiveJobStatus.get_status(job_id)
39
+ job_status == nil || job_status == :completed
40
+ end.any?
42
41
  end
43
42
 
44
43
  def self.find(batch_id:)
45
- if ActiveJobStatus.store.class.to_s == "ActiveSupport::Cache::RedisStore"
44
+ if ["ActiveSupport::Cache::RedisStore", "ActiveSupport::Cache::ReadthisStore"].include? ActiveJobStatus.store.class.to_s
46
45
  job_ids = ActiveJobStatus.store.smembers(batch_id)
47
46
  else
48
47
  job_ids = ActiveJobStatus.store.fetch(batch_id).to_a
@@ -62,4 +61,3 @@ module ActiveJobStatus
62
61
  end
63
62
  end
64
63
  end
65
-
@@ -1,11 +1,29 @@
1
1
  module ActiveJobStatus
2
- module JobStatus
3
- # Provides a way to check on the status of a given job
2
+ class JobStatus
3
+ ENQUEUED = :queued
4
+ WORKING = :working
5
+ COMPLETED = :completed
4
6
 
5
- def self.get_status(job_id:)
6
- status = ActiveJobStatus.store.fetch(job_id)
7
- status ? status.to_sym : nil
7
+ attr_reader :status
8
+
9
+ def initialize(status)
10
+ @status = status && status.to_sym
11
+ end
12
+
13
+ def queued?
14
+ status == ENQUEUED
15
+ end
16
+
17
+ def working?
18
+ status == WORKING
19
+ end
20
+
21
+ def completed?
22
+ status == COMPLETED
23
+ end
24
+
25
+ def empty?
26
+ status.nil?
8
27
  end
9
28
  end
10
29
  end
11
-
@@ -1,17 +1,41 @@
1
1
  module ActiveJobStatus
2
- module JobTracker
3
- # Provides methods to CRUD job status records in Redis
2
+ class JobTracker
3
+ DEFAULT_EXPIRATION = 72.hours.freeze
4
4
 
5
- def self.enqueue(job_id:)
6
- ActiveJobStatus.store.write(job_id, "queued", expires_in: 259200)
5
+ def initialize(job_id:, store: ActiveJobStatus.store, expiration: ActiveJobStatus.expiration)
6
+ @job_id = job_id
7
+ @store = store
8
+ @expiration = expiration
7
9
  end
8
10
 
9
- def self.update(job_id:, status:)
10
- ActiveJobStatus.store.write(job_id, status.to_s)
11
+ def enqueued
12
+ store.write(
13
+ job_id,
14
+ JobStatus::ENQUEUED.to_s,
15
+ expires_in: expiration || DEFAULT_EXPIRATION
16
+ )
11
17
  end
12
18
 
13
- def self.remove(job_id:)
14
- ActiveJobStatus.store.delete(job_id)
19
+ def performing
20
+ store.write(
21
+ job_id,
22
+ JobStatus::WORKING.to_s
23
+ )
15
24
  end
25
+
26
+ def completed
27
+ store.write(
28
+ job_id,
29
+ JobStatus::COMPLETED.to_s
30
+ )
31
+ end
32
+
33
+ def deleted
34
+ store.delete(job_id)
35
+ end
36
+
37
+ private
38
+
39
+ attr_reader :job_id, :store, :expiration
16
40
  end
17
41
  end
@@ -14,7 +14,12 @@ module ActiveJobStatus
14
14
  end
15
15
  end
16
16
 
17
- ActiveSupport::Cache::RedisStore.include(
18
- ActiveJobStatus::Redis
19
- )
20
-
17
+ if defined? ActiveSupport::Cache::RedisStore
18
+ ActiveSupport::Cache::RedisStore.include(
19
+ ActiveJobStatus::Redis
20
+ )
21
+ elsif defined? ActiveSupport::Cache::ReadthisStore
22
+ ActiveSupport::Cache::ReadthisStore.include(
23
+ ActiveJobStatus::Redis
24
+ )
25
+ end
@@ -1,11 +1,8 @@
1
1
  require "active_job"
2
+ require "active_job_status/hooks"
3
+
2
4
  module ActiveJobStatus
3
5
  class TrackableJob < ActiveJob::Base
4
-
5
- before_enqueue { ActiveJobStatus::JobTracker.enqueue(job_id: @job_id) }
6
-
7
- before_perform { ActiveJobStatus::JobTracker.update(job_id: @job_id, status: :working) }
8
-
9
- after_perform { ActiveJobStatus::JobTracker.remove(job_id: @job_id) }
6
+ include ActiveJobStatus::Hooks
10
7
  end
11
8
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveJobStatus
2
- VERSION = "1.1.0"
2
+ VERSION = "1.2.0"
3
3
  end
@@ -57,7 +57,11 @@ describe ActiveJobStatus::JobBatch do
57
57
  update_store(id_array: total_jobs, job_status: :working)
58
58
  expect(batch.completed?).to be_falsey
59
59
  end
60
- it "should be true when jobs are completed" do
60
+ it "should be true when jobs are all completed" do
61
+ update_store(id_array: total_jobs, job_status: :completed)
62
+ expect(batch.completed?).to be_truthy
63
+ end
64
+ it "should be true when jobs are not in the store" do
61
65
  clear_store(id_array: total_jobs)
62
66
  expect(batch.completed?).to be_truthy
63
67
  end
@@ -1,26 +1,53 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe ActiveJobStatus::JobStatus do
4
+ let(:job_status) { described_class.new(status) }
4
5
 
5
- describe "::get_status" do
6
+ context 'when queued' do
7
+ let(:status) { 'queued' }
6
8
 
7
- describe "for a queued job" do
8
- let(:job) { ActiveJobStatus::TrackableJob.new.enqueue }
9
+ it 'returns the correct state' do
10
+ expect(job_status.queued?).to eq true
11
+ expect(job_status.working?).to eq false
12
+ expect(job_status.completed?).to eq false
13
+ expect(job_status.empty?).to eq false
14
+ expect(job_status.status).to eq :queued
15
+ end
16
+ end
17
+
18
+ context 'when working' do
19
+ let(:status) { 'working' }
9
20
 
10
- it "should return :queued" do
11
- expect(ActiveJobStatus::JobStatus.get_status(job_id: job.job_id)).to eq :queued
12
- end
21
+ it 'returns the correct state' do
22
+ expect(job_status.queued?).to eq false
23
+ expect(job_status.working?).to eq true
24
+ expect(job_status.completed?).to eq false
25
+ expect(job_status.empty?).to eq false
26
+ expect(job_status.status).to eq :working
13
27
  end
28
+ end
14
29
 
15
- describe "for a complete job" do
30
+ context 'when completed' do
31
+ let(:status) { 'completed' }
16
32
 
17
- let!(:job) { ActiveJobStatus::TrackableJob.perform_later }
18
- sleep(10)
19
- #clear_performed_jobs
20
- it "should return :complete", pending: true do
21
- expect(ActiveJobStatus::JobStatus.get_status(job_id: job.job_id)).to be_nil
22
- end
33
+ it 'returns the correct state' do
34
+ expect(job_status.queued?).to eq false
35
+ expect(job_status.working?).to eq false
36
+ expect(job_status.completed?).to eq true
37
+ expect(job_status.empty?).to eq false
38
+ expect(job_status.status).to eq :completed
23
39
  end
24
40
  end
25
- end
26
41
 
42
+ context 'when nil' do
43
+ let(:status) { nil }
44
+
45
+ it 'returns the correct state' do
46
+ expect(job_status.queued?).to eq false
47
+ expect(job_status.working?).to eq false
48
+ expect(job_status.completed?).to eq false
49
+ expect(job_status.empty?).to eq true
50
+ expect(job_status.status).to eq nil
51
+ end
52
+ end
53
+ end
@@ -1,29 +1,53 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe ActiveJobStatus::JobTracker do
4
-
5
4
  let!(:store) { ActiveJobStatus.store = new_store }
6
- let(:job) { ActiveJobStatus::TrackableJob.new.enqueue }
5
+ let(:job_id) { 'j0b-1d' }
6
+ let(:tracker) { described_class.new(job_id: job_id) }
7
+
8
+ describe "#enqueued" do
9
+ it "starts tracking the job" do
10
+ tracker.enqueued
11
+ expect(store.fetch(job_id)).to eq "queued"
12
+ end
7
13
 
8
- describe "::enqueue" do
9
- it "should enqueue a job" do
10
- ActiveJobStatus::JobTracker.enqueue(job_id: job.job_id)
11
- expect(store.fetch(job.job_id)).to eq "queued"
14
+ context 'with default expiration period' do
15
+ before { ActiveJobStatus.expiration = nil }
16
+
17
+ it 'expires in 72 hours' do
18
+ expect(store).to receive(:write).with(job_id, "queued", expires_in: 72.hours)
19
+ tracker.enqueued
20
+ end
21
+ end
22
+
23
+ context 'with default expiration period' do
24
+ before { ActiveJobStatus.expiration = 10.seconds }
25
+
26
+ it 'expires in the given period' do
27
+ expect(store).to receive(:write).with(job_id, "queued", expires_in: 10.seconds)
28
+ tracker.enqueued
29
+ end
12
30
  end
13
31
  end
14
32
 
15
- describe "::update" do
16
- it "should update a job status" do
17
- ActiveJobStatus::JobTracker.update(job_id: job.job_id, status: :working)
18
- expect(store.fetch(job.job_id)).to eq "working"
33
+ describe "#performing" do
34
+ it "updates the job status" do
35
+ tracker.performing
36
+ expect(store.fetch(job_id)).to eq "working"
19
37
  end
20
38
  end
21
39
 
22
- describe "::remove" do
23
- it "should remove the job from the cache store" do
24
- ActiveJobStatus::JobTracker.remove(job_id: job.job_id)
25
- expect(store.fetch(job.job_id)).to eq nil
40
+ describe "#completed" do
41
+ it "updates the job status" do
42
+ tracker.completed
43
+ expect(store.fetch(job_id)).to eq "completed"
26
44
  end
27
45
  end
28
- end
29
46
 
47
+ describe "#deleted" do
48
+ it "removes the job from the store" do
49
+ tracker.deleted
50
+ expect(store.fetch(job_id)).to eq nil
51
+ end
52
+ end
53
+ end
data/spec/spec_helper.rb CHANGED
@@ -13,6 +13,6 @@ RSpec.configure do |c|
13
13
  c.include Helpers
14
14
  end
15
15
 
16
- if defined? ActiveSupport::Cache::RedisStore
16
+ if defined? ActiveSupport::Cache::RedisStore || defined? ActiveSupport::Cache::ReadthisStore
17
17
  require "active_job_status/redis"
18
18
  end
@@ -3,6 +3,9 @@ module Helpers
3
3
  if defined? ActiveSupport::Cache::RedisStore
4
4
  puts "Using RedisStore"
5
5
  ActiveSupport::Cache::RedisStore.new
6
+ elsif defined? ActiveSupport::Cache::ReadthisStore
7
+ puts "Using ReadthisStore"
8
+ ActiveSupport::Cache::ReadthisStore.new
6
9
  else
7
10
  puts "Using MemoryStore"
8
11
  ActiveSupport::Cache::MemoryStore.new
@@ -1,4 +1,4 @@
1
- if defined? ActiveSupport::Cache::RedisStore
1
+ if defined? ActiveSupport::Cache::RedisStore || defined? ActiveSupport::Cache::ReadthisStore
2
2
  # For redis we need to sleep to test
3
3
  def travel(interval)
4
4
  sleep interval
@@ -1,21 +1,40 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe ActiveJobStatus::TrackableJob do
4
+ class DummyJob < ActiveJobStatus::TrackableJob
5
+ def perform; end;
6
+ end
4
7
 
5
- describe "#initialize" do
6
-
7
- let(:trackable_job) { ActiveJobStatus::TrackableJob.new }
8
+ let(:job) { DummyJob.new }
8
9
 
9
- it "should create an object" do
10
- expect(trackable_job).to be_an_instance_of ActiveJobStatus::TrackableJob
10
+ describe 'queueing' do
11
+ it "should have a job id" do
12
+ expect(job.job_id).to_not be_blank
11
13
  end
12
14
  end
13
15
 
14
- describe 'queueing' do
15
- let(:trackable_job) { ActiveJobStatus::TrackableJob.new.enqueue }
16
+ describe 'tracking hooks' do
17
+ let(:job_tracker) { instance_double(ActiveJobStatus::JobTracker) }
16
18
 
17
- it "should have a job id" do
18
- expect(trackable_job.job_id).to_not be_blank
19
+ before do
20
+ allow(job).to receive(:job_id) { 'j0b-1d' }
21
+ end
22
+
23
+ describe 'before enqueue' do
24
+ it 'starts to track the job with JobTracker' do
25
+ expect(ActiveJobStatus::JobTracker).to receive(:new).with(job_id: 'j0b-1d') { job_tracker }
26
+ expect(job_tracker).to receive(:enqueued)
27
+ job.enqueue
28
+ end
29
+ end
30
+
31
+ describe 'before/after perform' do
32
+ it 'updates the job status with JobTracker and then remove it' do
33
+ expect(ActiveJobStatus::JobTracker).to receive(:new).with(job_id: 'j0b-1d') { job_tracker }
34
+ expect(job_tracker).to receive(:performing)
35
+ expect(job_tracker).to receive(:completed)
36
+ job.perform_now
37
+ end
19
38
  end
20
39
  end
21
40
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_job_status
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brad Johnson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-09 00:00:00.000000000 Z
11
+ date: 2016-10-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -70,28 +70,28 @@ dependencies:
70
70
  name: activejob
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ">"
74
74
  - !ruby/object:Gem::Version
75
75
  version: '4.2'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - ">"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '4.2'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: activesupport
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
87
+ - - ">"
88
88
  - !ruby/object:Gem::Version
89
89
  version: '4.2'
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: '4.2'
97
97
  description: Job status and batches for ActiveJob. Create trackable jobs, check their
@@ -114,6 +114,7 @@ files:
114
114
  - gemfiles/redis-activesupport.gemfile
115
115
  - lib/active_job_status.rb
116
116
  - lib/active_job_status/configure_redis.rb
117
+ - lib/active_job_status/hooks.rb
117
118
  - lib/active_job_status/job_batch.rb
118
119
  - lib/active_job_status/job_status.rb
119
120
  - lib/active_job_status/job_tracker.rb