active_job_store 0.2.0 → 0.3.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 +4 -4
- data/README.md +47 -22
- data/lib/active_job_store/store.rb +24 -8
- data/lib/active_job_store/version.rb +1 -1
- data/lib/active_job_store.rb +33 -24
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a9fd49a85e50473450a09a741acaf01d5e6565116cb6f945f314bd6e4dd74f6d
|
4
|
+
data.tar.gz: d5655ec674b4a86d99b267c8a851e2a8d1cd687e188c58c8a292bf5120cffc3b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f9e1a166e181d32afb0265ac062b954930b8d748af36b21e837d2ee6fe28a7d57edc2f9ad590339e49fefbc3256e6b43317d19ab4e9ff1de36e7f2aa67d0dac4
|
7
|
+
data.tar.gz: a407a4446dec032e4bf6f7b5f55536dadd703c0d1d1a75d61cdf37ace3388e09c836c520ffde6c0b31043867bd92c82ad04c57b54d7398ca126baa080715e0a5
|
data/README.md
CHANGED
@@ -7,14 +7,11 @@
|
|
7
7
|
Persist job execution information on a support model `ActiveJobStore::Record`.
|
8
8
|
|
9
9
|
It can be useful to:
|
10
|
-
-
|
11
|
-
- query historical data about job executions;
|
12
|
-
-
|
13
|
-
- track a job's state / set progress value / add custom data to the jobs.
|
10
|
+
- store the job's state / set progress value / add custom data to the jobs;
|
11
|
+
- query historical data about job executions / extract job's statistical data;
|
12
|
+
- improve jobs' logging capabilities.
|
14
13
|
|
15
|
-
|
16
|
-
- set custom data attributes (via `active_job_store_custom_data` accessor);
|
17
|
-
- format the job result to store (overriding `active_job_store_format_result` method).
|
14
|
+
Please ⭐ if you like it.
|
18
15
|
|
19
16
|
## Installation
|
20
17
|
|
@@ -24,6 +21,19 @@ Support some customizations:
|
|
24
21
|
- Add to your job `include ActiveJobStore` (or to your `ApplicationJob` class if you prefer)
|
25
22
|
- Access to the job executions data using the class method `job_executions` on your job (ex. `YourJob.job_executions`)
|
26
23
|
|
24
|
+
## API
|
25
|
+
|
26
|
+
attr_accessor on the jobs:
|
27
|
+
- `active_job_store_custom_data`: to set / manipulate job's custom data
|
28
|
+
|
29
|
+
Instance methods on the jobs:
|
30
|
+
- `active_job_store_format_result(result) => result2`: to format / manipulate / serialize the job result
|
31
|
+
- `active_job_store_record => store record`: returns the store's record
|
32
|
+
- `save_job_custom_data(custom_data = nil)`: to persist custom data while the job is performing
|
33
|
+
|
34
|
+
Class methods on the jobs:
|
35
|
+
- `job_executions => relation`: query the list of job executions for the specific job class (returns an ActiveRecord Relation)
|
36
|
+
|
27
37
|
## Usage examples
|
28
38
|
|
29
39
|
```rb
|
@@ -48,18 +58,6 @@ SomeJob.job_executions.first
|
|
48
58
|
# created_at: Wed, 09 Nov 2022 21:09:50.611900000 UTC +00:00>
|
49
59
|
```
|
50
60
|
|
51
|
-
Extract some logs:
|
52
|
-
|
53
|
-
```rb
|
54
|
-
puts ::ActiveJobStore::Record.order(id: :desc).pluck(:created_at, :job_class, :arguments, :state, :completed_at).map { _1.join(', ') }
|
55
|
-
# 2022-11-09 21:20:57 UTC, SomeJob, 123, completed, 2022-11-09 21:20:58 UTC
|
56
|
-
# 2022-11-09 21:18:26 UTC, AnotherJob, another test 2, completed, 2022-11-09 21:18:26 UTC
|
57
|
-
# 2022-11-09 21:13:18 UTC, SomeJob, Some test 3, completed, 2022-11-09 21:13:19 UTC
|
58
|
-
# 2022-11-09 21:12:18 UTC, SomeJob, Some test 2, error,
|
59
|
-
# 2022-11-09 21:10:13 UTC, AnotherJob, another test, completed, 2022-11-09 21:10:13 UTC
|
60
|
-
# 2022-11-09 21:09:50 UTC, SomeJob, Some test, completed, 2022-11-09 21:09:50 UTC
|
61
|
-
```
|
62
|
-
|
63
61
|
Query jobs in a specific range of time:
|
64
62
|
|
65
63
|
```rb
|
@@ -77,7 +75,34 @@ SomeJob.job_executions.completed.map { |job| { id: job.id, execution_time: job.c
|
|
77
75
|
# {:id=>1, :execution_time=>0.011442, :started_at=>Wed, 09 Nov 2022 21:09:50.611355000 UTC +00:00}]
|
78
76
|
```
|
79
77
|
|
80
|
-
|
78
|
+
Extract some logs:
|
79
|
+
|
80
|
+
```rb
|
81
|
+
puts ::ActiveJobStore::Record.order(id: :desc).pluck(:created_at, :job_class, :arguments, :state, :completed_at).map { _1.join(', ') }
|
82
|
+
# 2022-11-09 21:20:57 UTC, SomeJob, 123, completed, 2022-11-09 21:20:58 UTC
|
83
|
+
# 2022-11-09 21:18:26 UTC, AnotherJob, another test 2, completed, 2022-11-09 21:18:26 UTC
|
84
|
+
# 2022-11-09 21:13:18 UTC, SomeJob, Some test 3, completed, 2022-11-09 21:13:19 UTC
|
85
|
+
# 2022-11-09 21:12:18 UTC, SomeJob, Some test 2, error,
|
86
|
+
# 2022-11-09 21:10:13 UTC, AnotherJob, another test, completed, 2022-11-09 21:10:13 UTC
|
87
|
+
# 2022-11-09 21:09:50 UTC, SomeJob, Some test, completed, 2022-11-09 21:09:50 UTC
|
88
|
+
```
|
89
|
+
|
90
|
+
Query information from a job (even when it's performing):
|
91
|
+
|
92
|
+
```rb
|
93
|
+
job = SomeJob.perform_later 123
|
94
|
+
job.active_job_store_record.slice(:job_id, :job_class, :arguments)
|
95
|
+
# => {"job_id"=>"b009f7c7-a264-4fb5-a1f8-68a8141f323b", "job_class"=>"SomeJob", "arguments"=>[123]}
|
96
|
+
|
97
|
+
job = AnotherJob.perform_later 456
|
98
|
+
job.active_job_store_record.custom_data
|
99
|
+
# => {"progress"=>0.5}
|
100
|
+
### After a while:
|
101
|
+
job.active_job_store_record.reload.custom_data
|
102
|
+
# => {"progress"=>1.0}
|
103
|
+
```
|
104
|
+
|
105
|
+
## Features' details
|
81
106
|
|
82
107
|
To store the custom data (ex. a progress value):
|
83
108
|
|
@@ -100,7 +125,7 @@ AnotherJob.perform_later(456)
|
|
100
125
|
AnotherJob.job_executions.last.custom_data['progress'] # 1.0 (at the end)
|
101
126
|
```
|
102
127
|
|
103
|
-
|
128
|
+
To manipulate the custom data, there is the `active_job_store_custom_data` accessor:
|
104
129
|
|
105
130
|
```rb
|
106
131
|
class AnotherJob < ApplicationJob
|
@@ -123,7 +148,7 @@ AnotherJob.job_executions.last.custom_data
|
|
123
148
|
# => [{"time"=>"2022-11-09T21:20:57.580Z", "message"=>"SomeJob step 1"}, {"time"=>"2022-11-09T21:20:58.581Z", "message"=>"SomeJob step 2"}]
|
124
149
|
```
|
125
150
|
|
126
|
-
|
151
|
+
To process the result before storing it (ex. for serialization), override `active_job_store_format_result`:
|
127
152
|
|
128
153
|
```rb
|
129
154
|
class AnotherJob < ApplicationJob
|
@@ -6,14 +6,36 @@ module ActiveJobStore
|
|
6
6
|
|
7
7
|
attr_reader :record
|
8
8
|
|
9
|
+
def around_enqueue(job)
|
10
|
+
prepare_record_on_enqueue(job)
|
11
|
+
record.lock! # NOTE: needed to avoid update conflicts with perform when setting the state to enqueued
|
12
|
+
yield
|
13
|
+
job_enqueued!
|
14
|
+
end
|
15
|
+
|
16
|
+
def around_perform(job)
|
17
|
+
prepare_record_on_perform(job)
|
18
|
+
job_started!
|
19
|
+
result = yield
|
20
|
+
formatted_result = job.active_job_store_format_result(result)
|
21
|
+
job_competed!(custom_data: job.active_job_store_custom_data, result: formatted_result)
|
22
|
+
rescue StandardError => e
|
23
|
+
job_failed!(exception: e, custom_data: job.active_job_store_custom_data)
|
24
|
+
raise
|
25
|
+
end
|
26
|
+
|
27
|
+
def update_job_custom_data(custom_data)
|
28
|
+
record.update!(custom_data: custom_data)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
9
33
|
def job_competed!(result:, custom_data:)
|
10
34
|
record.update!(state: :completed, completed_at: Time.current, result: result, custom_data: custom_data)
|
11
35
|
record
|
12
36
|
end
|
13
37
|
|
14
38
|
def job_enqueued!
|
15
|
-
record.lock! # NOTE: needed to avoid update conflicts with perform when setting the state to enqueued
|
16
|
-
yield
|
17
39
|
record.update!(state: :enqueued, enqueued_at: Time.current)
|
18
40
|
record
|
19
41
|
end
|
@@ -44,12 +66,6 @@ module ActiveJobStore
|
|
44
66
|
record
|
45
67
|
end
|
46
68
|
|
47
|
-
def update_job_custom_data(custom_data)
|
48
|
-
record.update!(custom_data: custom_data)
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
|
53
69
|
def record_reference(job)
|
54
70
|
{
|
55
71
|
job_id: job.job_id,
|
data/lib/active_job_store.rb
CHANGED
@@ -4,47 +4,56 @@ require_relative 'active_job_store/engine'
|
|
4
4
|
require_relative 'active_job_store/store'
|
5
5
|
|
6
6
|
module ActiveJobStore
|
7
|
+
# Set / manipulate job's custom data
|
7
8
|
attr_accessor :active_job_store_custom_data
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
store.prepare_record_on_enqueue(job)
|
15
|
-
store.job_enqueued! do
|
16
|
-
block.call
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
base.around_perform do |job, block|
|
21
|
-
store.prepare_record_on_perform(job)
|
22
|
-
store.job_started!
|
23
|
-
result = block.call
|
24
|
-
formatted_result = job.active_job_store_format_result(result)
|
25
|
-
store.job_competed!(custom_data: active_job_store_custom_data, result: formatted_result)
|
26
|
-
rescue StandardError => e
|
27
|
-
store.job_failed!(exception: e, custom_data: active_job_store_custom_data)
|
28
|
-
raise
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
10
|
+
# Format / manipulate / serialize the job result
|
11
|
+
#
|
12
|
+
# @param result [any] Job's return value
|
13
|
+
#
|
14
|
+
# @return [any] Processed job's return value
|
33
15
|
def active_job_store_format_result(result)
|
34
16
|
result
|
35
17
|
end
|
36
18
|
|
19
|
+
# Persist custom data while the job is performing
|
20
|
+
#
|
21
|
+
# @param custom_data [any] Attributes to serialize (it must be serializable in JSON)
|
37
22
|
def save_job_custom_data(custom_data = nil)
|
38
23
|
self.active_job_store_custom_data = custom_data if custom_data
|
39
24
|
store.update_job_custom_data(active_job_store_custom_data)
|
40
25
|
end
|
41
26
|
|
27
|
+
# Return the associated Active Job Store record
|
28
|
+
#
|
29
|
+
# @return [ActiveJobStore::Record] the corresponding record
|
30
|
+
def active_job_store_record
|
31
|
+
store.record
|
32
|
+
end
|
33
|
+
|
42
34
|
module ClassMethods
|
35
|
+
# Query the list of job executions for the current job class
|
36
|
+
#
|
37
|
+
# @return [ActiveRecord Relation] query result
|
43
38
|
def job_executions
|
44
39
|
::ActiveJobStore::Record.where(job_class: to_s)
|
45
40
|
end
|
46
41
|
end
|
47
42
|
|
43
|
+
class << self
|
44
|
+
def included(base)
|
45
|
+
base.extend(ClassMethods)
|
46
|
+
|
47
|
+
base.around_enqueue do |job, block|
|
48
|
+
store.around_enqueue(job) { block.call }
|
49
|
+
end
|
50
|
+
|
51
|
+
base.around_perform do |job, block|
|
52
|
+
store.around_perform(job) { block.call }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
48
57
|
private
|
49
58
|
|
50
59
|
def store
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_job_store
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mattia Roccoberton
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-11-
|
11
|
+
date: 2022-11-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activejob
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '6.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activerecord
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '6.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '6.0'
|
27
41
|
description: ActiveJob Store permits to store jobs state and custom data on a database
|
28
42
|
email: mat@blocknot.es
|
29
43
|
executables: []
|