acidic_job 1.0.0.rc4 → 1.0.0.rc5
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/lib/acidic_job/context.rb +1 -1
- data/lib/acidic_job/version.rb +1 -1
- metadata +5 -27
- data/.codacy.yml +0 -4
- data/.github/FUNDING.yml +0 -13
- data/.github/workflows/main.yml +0 -38
- data/.gitignore +0 -18
- data/.rubocop-https---www-goodcop-style-base-yml +0 -1051
- data/.rubocop.yml +0 -11
- data/.ruby-version +0 -1
- data/Gemfile +0 -5
- data/Gemfile.lock +0 -209
- data/Rakefile +0 -16
- data/TODO +0 -77
- data/UPGRADE_GUIDE.md +0 -81
- data/acidic_job.gemspec +0 -50
- data/bin/console +0 -21
- data/bin/setup +0 -8
- data/bin/test_all +0 -26
- data/blog_post.md +0 -28
- data/combustion/log/test.log +0 -0
- data/gemfiles/rails_7.0.gemfile +0 -11
- data/gemfiles/rails_7.1.gemfile +0 -11
- data/gemfiles/rails_7.2.gemfile +0 -11
- data/gemfiles/rails_8.0.gemfile +0 -11
data/.rubocop.yml
DELETED
data/.ruby-version
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
ruby-3.3.4
|
data/Gemfile
DELETED
data/Gemfile.lock
DELETED
@@ -1,209 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
acidic_job (1.0.0.rc4)
|
5
|
-
activejob (>= 7.1)
|
6
|
-
activerecord (>= 7.1)
|
7
|
-
activesupport (>= 7.1)
|
8
|
-
json (>= 2.7.0)
|
9
|
-
railties (>= 7.1)
|
10
|
-
|
11
|
-
GEM
|
12
|
-
remote: https://rubygems.org/
|
13
|
-
specs:
|
14
|
-
actionmailer (8.0.2)
|
15
|
-
actionpack (= 8.0.2)
|
16
|
-
actionview (= 8.0.2)
|
17
|
-
activejob (= 8.0.2)
|
18
|
-
activesupport (= 8.0.2)
|
19
|
-
mail (>= 2.8.0)
|
20
|
-
rails-dom-testing (~> 2.2)
|
21
|
-
actionpack (8.0.2)
|
22
|
-
actionview (= 8.0.2)
|
23
|
-
activesupport (= 8.0.2)
|
24
|
-
nokogiri (>= 1.8.5)
|
25
|
-
rack (>= 2.2.4)
|
26
|
-
rack-session (>= 1.0.1)
|
27
|
-
rack-test (>= 0.6.3)
|
28
|
-
rails-dom-testing (~> 2.2)
|
29
|
-
rails-html-sanitizer (~> 1.6)
|
30
|
-
useragent (~> 0.16)
|
31
|
-
actionview (8.0.2)
|
32
|
-
activesupport (= 8.0.2)
|
33
|
-
builder (~> 3.1)
|
34
|
-
erubi (~> 1.11)
|
35
|
-
rails-dom-testing (~> 2.2)
|
36
|
-
rails-html-sanitizer (~> 1.6)
|
37
|
-
activejob (8.0.2)
|
38
|
-
activesupport (= 8.0.2)
|
39
|
-
globalid (>= 0.3.6)
|
40
|
-
activemodel (8.0.2)
|
41
|
-
activesupport (= 8.0.2)
|
42
|
-
activerecord (8.0.2)
|
43
|
-
activemodel (= 8.0.2)
|
44
|
-
activesupport (= 8.0.2)
|
45
|
-
timeout (>= 0.4.0)
|
46
|
-
activesupport (8.0.2)
|
47
|
-
base64
|
48
|
-
benchmark (>= 0.3)
|
49
|
-
bigdecimal
|
50
|
-
concurrent-ruby (~> 1.0, >= 1.3.1)
|
51
|
-
connection_pool (>= 2.2.5)
|
52
|
-
drb
|
53
|
-
i18n (>= 1.6, < 2)
|
54
|
-
logger (>= 1.4.2)
|
55
|
-
minitest (>= 5.1)
|
56
|
-
securerandom (>= 0.3)
|
57
|
-
tzinfo (~> 2.0, >= 2.0.5)
|
58
|
-
uri (>= 0.13.1)
|
59
|
-
ast (2.4.3)
|
60
|
-
base64 (0.2.0)
|
61
|
-
benchmark (0.4.0)
|
62
|
-
bigdecimal (3.1.9)
|
63
|
-
builder (3.3.0)
|
64
|
-
chaotic_job (0.3.0)
|
65
|
-
combustion (1.5.0)
|
66
|
-
activesupport (>= 3.0.0)
|
67
|
-
railties (>= 3.0.0)
|
68
|
-
thor (>= 0.14.6)
|
69
|
-
concurrent-ruby (1.3.5)
|
70
|
-
connection_pool (2.5.3)
|
71
|
-
crass (1.0.6)
|
72
|
-
date (3.4.1)
|
73
|
-
docile (1.4.1)
|
74
|
-
drb (2.2.1)
|
75
|
-
erubi (1.13.1)
|
76
|
-
globalid (1.2.1)
|
77
|
-
activesupport (>= 6.1)
|
78
|
-
i18n (1.14.7)
|
79
|
-
concurrent-ruby (~> 1.0)
|
80
|
-
io-console (0.8.0)
|
81
|
-
irb (1.15.2)
|
82
|
-
pp (>= 0.6.0)
|
83
|
-
rdoc (>= 4.0.0)
|
84
|
-
reline (>= 0.4.2)
|
85
|
-
json (2.12.0)
|
86
|
-
language_server-protocol (3.17.0.5)
|
87
|
-
lint_roller (1.1.0)
|
88
|
-
logger (1.7.0)
|
89
|
-
loofah (2.24.1)
|
90
|
-
crass (~> 1.0.2)
|
91
|
-
nokogiri (>= 1.12.0)
|
92
|
-
mail (2.8.1)
|
93
|
-
mini_mime (>= 0.1.1)
|
94
|
-
net-imap
|
95
|
-
net-pop
|
96
|
-
net-smtp
|
97
|
-
mini_mime (1.1.5)
|
98
|
-
mini_portile2 (2.8.9)
|
99
|
-
minitest (5.25.5)
|
100
|
-
net-imap (0.5.8)
|
101
|
-
date
|
102
|
-
net-protocol
|
103
|
-
net-pop (0.1.2)
|
104
|
-
net-protocol
|
105
|
-
net-protocol (0.2.2)
|
106
|
-
timeout
|
107
|
-
net-smtp (0.5.1)
|
108
|
-
net-protocol
|
109
|
-
nokogiri (1.18.8)
|
110
|
-
mini_portile2 (~> 2.8.2)
|
111
|
-
racc (~> 1.4)
|
112
|
-
nokogiri (1.18.8-x86_64-darwin)
|
113
|
-
racc (~> 1.4)
|
114
|
-
parallel (1.27.0)
|
115
|
-
parser (3.3.8.0)
|
116
|
-
ast (~> 2.4.1)
|
117
|
-
racc
|
118
|
-
pp (0.6.2)
|
119
|
-
prettyprint
|
120
|
-
prettyprint (0.2.0)
|
121
|
-
prism (1.4.0)
|
122
|
-
psych (5.2.6)
|
123
|
-
date
|
124
|
-
stringio
|
125
|
-
racc (1.8.1)
|
126
|
-
rack (3.1.15)
|
127
|
-
rack-session (2.1.1)
|
128
|
-
base64 (>= 0.1.0)
|
129
|
-
rack (>= 3.0.0)
|
130
|
-
rack-test (2.2.0)
|
131
|
-
rack (>= 1.3)
|
132
|
-
rackup (2.2.1)
|
133
|
-
rack (>= 3)
|
134
|
-
rails-dom-testing (2.2.0)
|
135
|
-
activesupport (>= 5.0.0)
|
136
|
-
minitest
|
137
|
-
nokogiri (>= 1.6)
|
138
|
-
rails-html-sanitizer (1.6.2)
|
139
|
-
loofah (~> 2.21)
|
140
|
-
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
141
|
-
railties (8.0.2)
|
142
|
-
actionpack (= 8.0.2)
|
143
|
-
activesupport (= 8.0.2)
|
144
|
-
irb (~> 1.13)
|
145
|
-
rackup (>= 1.0.0)
|
146
|
-
rake (>= 12.2)
|
147
|
-
thor (~> 1.0, >= 1.2.2)
|
148
|
-
zeitwerk (~> 2.6)
|
149
|
-
rainbow (3.1.1)
|
150
|
-
rake (13.2.1)
|
151
|
-
rdoc (6.13.1)
|
152
|
-
psych (>= 4.0.0)
|
153
|
-
regexp_parser (2.10.0)
|
154
|
-
reline (0.6.1)
|
155
|
-
io-console (~> 0.5)
|
156
|
-
rubocop (1.75.6)
|
157
|
-
json (~> 2.3)
|
158
|
-
language_server-protocol (~> 3.17.0.2)
|
159
|
-
lint_roller (~> 1.1.0)
|
160
|
-
parallel (~> 1.10)
|
161
|
-
parser (>= 3.3.0.2)
|
162
|
-
rainbow (>= 2.2.2, < 4.0)
|
163
|
-
regexp_parser (>= 2.9.3, < 3.0)
|
164
|
-
rubocop-ast (>= 1.44.0, < 2.0)
|
165
|
-
ruby-progressbar (~> 1.7)
|
166
|
-
unicode-display_width (>= 2.4.0, < 4.0)
|
167
|
-
rubocop-ast (1.44.1)
|
168
|
-
parser (>= 3.3.7.2)
|
169
|
-
prism (~> 1.4)
|
170
|
-
ruby-progressbar (1.13.0)
|
171
|
-
securerandom (0.4.1)
|
172
|
-
simplecov (0.22.0)
|
173
|
-
docile (~> 1.1)
|
174
|
-
simplecov-html (~> 0.11)
|
175
|
-
simplecov_json_formatter (~> 0.1)
|
176
|
-
simplecov-html (0.13.1)
|
177
|
-
simplecov_json_formatter (0.1.4)
|
178
|
-
sqlite3 (2.6.0)
|
179
|
-
mini_portile2 (~> 2.8.0)
|
180
|
-
sqlite3 (2.6.0-x86_64-darwin)
|
181
|
-
stringio (3.1.7)
|
182
|
-
thor (1.3.2)
|
183
|
-
timeout (0.4.3)
|
184
|
-
tzinfo (2.0.6)
|
185
|
-
concurrent-ruby (~> 1.0)
|
186
|
-
unicode-display_width (3.1.4)
|
187
|
-
unicode-emoji (~> 4.0, >= 4.0.4)
|
188
|
-
unicode-emoji (4.0.4)
|
189
|
-
uri (1.0.3)
|
190
|
-
useragent (0.16.11)
|
191
|
-
zeitwerk (2.7.2)
|
192
|
-
|
193
|
-
PLATFORMS
|
194
|
-
ruby
|
195
|
-
x86_64-darwin-17
|
196
|
-
|
197
|
-
DEPENDENCIES
|
198
|
-
acidic_job!
|
199
|
-
actionmailer (>= 7.1)
|
200
|
-
chaotic_job
|
201
|
-
combustion
|
202
|
-
minitest
|
203
|
-
rake
|
204
|
-
rubocop
|
205
|
-
simplecov
|
206
|
-
sqlite3
|
207
|
-
|
208
|
-
BUNDLED WITH
|
209
|
-
2.5.21
|
data/Rakefile
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "bundler/gem_tasks"
|
4
|
-
require "rake/testtask"
|
5
|
-
|
6
|
-
Rake::TestTask.new(:test) do |t|
|
7
|
-
t.libs << "test"
|
8
|
-
t.libs << "lib"
|
9
|
-
t.test_files = FileList["test/**/*_test.rb"]
|
10
|
-
end
|
11
|
-
|
12
|
-
require "rubocop/rake_task"
|
13
|
-
|
14
|
-
RuboCop::RakeTask.new
|
15
|
-
|
16
|
-
task default: %i[test rubocop]
|
data/TODO
DELETED
@@ -1,77 +0,0 @@
|
|
1
|
-
- [x] Track number of runs per execution (resolves #79)
|
2
|
-
This is accomplished with the new `entries` table, as proven by the `idempotency_check` feature, which only runs on a retry.
|
3
|
-
|
4
|
-
- [x] Store errors with more context and without full error history (resolves #80)
|
5
|
-
This is also accomplished with the new `entries` table, by storing a separate error entry for any raised errors.
|
6
|
-
|
7
|
-
- [x] All traversal over a collection added to the context within the workflow (resolves #81)
|
8
|
-
The new collection traversal logic resolves #81, as proven by the test case. You can traverse a key for a context value. For example,
|
9
|
-
```ruby
|
10
|
-
execute :prepare_collection
|
11
|
-
traverse :collection, using: :process_item
|
12
|
-
|
13
|
-
def prepare_collection = @ctx[:collection] = 1..5
|
14
|
-
def process_item(item) = @processed_items << item
|
15
|
-
```
|
16
|
-
|
17
|
-
- [x] Handle case where non-idempotent external write succeeds but recording fails (resolves #82)
|
18
|
-
The new `idempotency_check` option accomplishes this, by allowing a step making external IO to define a method that checks if the write was already successfully made when re-running a step in a retry.
|
19
|
-
|
20
|
-
- [x] Ensure any and all exceptions can be serialized and deserialized (resolves #83)
|
21
|
-
The original serializer was too naive and couldn't deserialize, for example, an `ActionView::Template::Error` which requires that `$!` be set when initializing the object.
|
22
|
-
|
23
|
-
The new `ExceptionSerializer` uses Ruby's built-in YAML encoding of exceptions to serialize and deserialize the objects, laying on Zlib to ensure compact byte storage.
|
24
|
-
|
25
|
-
- [x] Handle duplicate workflow step names (resolves #87)
|
26
|
-
Adding a `DuplicateStepError` exception raised when building the workflow definition resolved this issue.
|
27
|
-
|
28
|
-
- [ ] Add a `context` step type (resolves #89)
|
29
|
-
Use case: the workflow may or may not have the data it needs to proceed. If it doesn't, it should make an API call to fetch the data. The API call may take a while, so we should be able to handle that as well.
|
30
|
-
|
31
|
-
Example usage:
|
32
|
-
```ruby
|
33
|
-
context :slack_author, fallback: :fetch_slack_author
|
34
|
-
|
35
|
-
def slack_author
|
36
|
-
Slack::Profile.find_by(uid: @user_uid)
|
37
|
-
end
|
38
|
-
|
39
|
-
def fetch_slack_author
|
40
|
-
api_response = Slack::Client.new().get_user(uid: @user_uid)
|
41
|
-
if api_response[:ok]
|
42
|
-
[Slack::ProcessProfileSlackJob.new(@installation, api_response[:user])]
|
43
|
-
else
|
44
|
-
raise DoNotRetryJob
|
45
|
-
end
|
46
|
-
end
|
47
|
-
```
|
48
|
-
|
49
|
-
Psuedo code for implementation:
|
50
|
-
```ruby
|
51
|
-
result = resolve_method(primary_method_name).call
|
52
|
-
if result
|
53
|
-
@ctx[primary_method_name] = result
|
54
|
-
else
|
55
|
-
fallback = resolve_method(fallback_method_name).call
|
56
|
-
case fallback
|
57
|
-
in ActiveJob::Base then awaits(fallback)
|
58
|
-
in Array[ActiveJob::Base] then awaits(fallback)
|
59
|
-
else @ctx[primary_method_name] = result
|
60
|
-
end
|
61
|
-
end
|
62
|
-
```
|
63
|
-
|
64
|
-
- [ ] Add documentation on how to "migrate" a workflow (resolves #90)
|
65
|
-
The v1 alpha already includes a check that the persisted workflow definition matches the job's current definition. This ensures that no job tries to run with an outdated definition. However, we should document the proper way to update a workflow definition.
|
66
|
-
|
67
|
-
The process can only be additive, like a strong migration. First, you create a new job with a new name that is a clone of the original job. Make the necessary changes to the new job. Update your codebase to only enqueue the new job. Deploy this change, where both the new job and the old jobs exist, but the application only enqueues the new job. Once deployed, wait until all currently running instances of the old job complete (provide some docs on how to check this). Once all old job instances are complete, you can safely delete the old job and deploy that change. This process ensures that no job is running with an outdated definition.
|
68
|
-
|
69
|
-
- [ ] Automatically retry the serializable transaction for find/create the Run record (resolves #91)
|
70
|
-
Serializable transactions are prone to failure: https://stackoverflow.com/a/21715207/2884386
|
71
|
-
|
72
|
-
Currently, if the transaction fails, the job will fail. We need to build automatic retries into the gem, as this failure will naturally resolve. But, we should also add a limit to the number of retries to prevent infinite loops.
|
73
|
-
|
74
|
-
- [ ] Ensure the gem works with GoodJob (resolves #92 and #94)
|
75
|
-
In the current version, GoodJob can't handle messing with the `job_id` and retrying a failed job raises a NoMethodError: "undefined method `utc' for an instance of Float".
|
76
|
-
|
77
|
-
- [ ] Ensure users can transactionally enqueue other entities, like ActionMailer or Noticed objects
|
data/UPGRADE_GUIDE.md
DELETED
@@ -1,81 +0,0 @@
|
|
1
|
-
# AcidicJob Upgrade Guide
|
2
|
-
|
3
|
-
## 1. Update version requirements in `Gemfile`
|
4
|
-
|
5
|
-
```diff
|
6
|
-
- gem "acidic_job"
|
7
|
-
+ gem "acidic_job", "~> 1.0.0.pre1"
|
8
|
-
```
|
9
|
-
|
10
|
-
result:
|
11
|
-
```
|
12
|
-
Installing acidic_job 1.0.0.pre4 (was 0.7.7)
|
13
|
-
Bundle updated!
|
14
|
-
```
|
15
|
-
|
16
|
-
## 2. Generate migration for new `AcidicJob::Run` model
|
17
|
-
|
18
|
-
```bash
|
19
|
-
rails generate acidic_job
|
20
|
-
```
|
21
|
-
|
22
|
-
result:
|
23
|
-
```
|
24
|
-
create db/migrate/#{yyyymmddhhmmss}_create_acidic_job_runs.rb
|
25
|
-
```
|
26
|
-
|
27
|
-
## 3. Delete any unneeded `AcidicJob::Key` records
|
28
|
-
|
29
|
-
Typically, records that are already finished do not need to be retained. Sometimes, however, applications key finished records around for some amount of time for debugging or metrics aggregation. Whatever your application's logic is for whether or not an `AcidicJob::Key` record is still needed, for all unneeded records, delete them.
|
30
|
-
|
31
|
-
For example, this would delete all finished `Key` records over 1 month old:
|
32
|
-
|
33
|
-
```ruby
|
34
|
-
AcidicJob::Key.where(recovery_point: AcidicJob::Key::RECOVERY_POINT_FINISHED, last_run_at: ..1.month.ago).delete_all
|
35
|
-
```
|
36
|
-
|
37
|
-
## 4. Migrate `AcidicJob::Key` to `AcidicJob::Run`
|
38
|
-
|
39
|
-
`AcidicJob` ships with an upgrade module that provides a script to migrate older `Key` records to the new `Run` model.
|
40
|
-
|
41
|
-
```ruby
|
42
|
-
AcidicJob::UpgradeService.execute
|
43
|
-
```
|
44
|
-
|
45
|
-
This script will prepare an `insert_all` command for `Run` records by mapping the older `Key` data to the new `Run` schema. It also creates the new `Run` records with the same `id` as their `Key` counterparts, and then deletes all `Key` records successfully mapped over. Any `Key` records that were failed to be mapped over will be reported, along with the exception, in the `errored_keys` portion of the resulting hash.
|
46
|
-
|
47
|
-
result:
|
48
|
-
```
|
49
|
-
{
|
50
|
-
run_records: <Integer>,
|
51
|
-
key_records: <Integer>,
|
52
|
-
errored_keys: <Array>
|
53
|
-
}
|
54
|
-
```
|
55
|
-
|
56
|
-
## 5. Triage remaining `AcidicJob::Key` records
|
57
|
-
|
58
|
-
If there were any `AcidicJob::Key` records that failed to be mapped to the new `Run` model, you will need to manually triage whatever the exception was. In all likelihood, the exception would be relating to the translation of the `Key#job_args` field to the `Run#serialized_job` field, as all other fields have a fairly straight-forward mapping. If you can't resolve the issue, please open an Issue in GitHub.
|
59
|
-
|
60
|
-
## 6. Ensure all `AcidicJob::Staged` records are processed
|
61
|
-
|
62
|
-
`AcidicJob` still ships with an upgrade module that provides the older `Key` and `Staged` records, so this functionality will still be present to handle any existing records in your database when you deploy the updated version.
|
63
|
-
|
64
|
-
## 7. Remove the old tables
|
65
|
-
|
66
|
-
Once you have successfully migrated everything over and the new system has been running smoothly for some time, you should drop the old `acidic_job_keys` and `staged_acidic_jobs` tables. We provide a migration generator just for this purpose:
|
67
|
-
|
68
|
-
```bash
|
69
|
-
rails generate acidic_job:drop_tables
|
70
|
-
```
|
71
|
-
|
72
|
-
result:
|
73
|
-
```
|
74
|
-
create db/migrate/#{yyyymmddhhmmss}_drop_old_acidic_job_tables.rb
|
75
|
-
```
|
76
|
-
|
77
|
-
You can then run the migration to have those tables removed:
|
78
|
-
|
79
|
-
```bash
|
80
|
-
rails db:migrate
|
81
|
-
```
|
data/acidic_job.gemspec
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "lib/acidic_job/version"
|
4
|
-
|
5
|
-
Gem::Specification.new do |spec|
|
6
|
-
spec.name = "acidic_job"
|
7
|
-
spec.version = AcidicJob::VERSION
|
8
|
-
spec.authors = ["fractaledmind"]
|
9
|
-
spec.email = ["stephen.margheim@gmail.com"]
|
10
|
-
|
11
|
-
spec.summary = "Idempotent operations for Rails apps, built on top of ActiveJob."
|
12
|
-
spec.description = "Idempotent operations for Rails apps, built on top of ActiveJob."
|
13
|
-
spec.homepage = "https://github.com/fractaledmind/acidic_job"
|
14
|
-
spec.license = "MIT"
|
15
|
-
spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
|
16
|
-
|
17
|
-
spec.metadata["homepage_uri"] = spec.homepage
|
18
|
-
spec.metadata["source_code_uri"] = "https://github.com/fractaledmind/acidic_job"
|
19
|
-
spec.metadata["changelog_uri"] = "https://github.com/fractaledmind/acidic_job/CHANGELOG.md"
|
20
|
-
|
21
|
-
# Specify which files should be added to the gem when it is released.
|
22
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
-
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
24
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
25
|
-
end
|
26
|
-
spec.bindir = "exe"
|
27
|
-
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
28
|
-
spec.require_paths = ["lib"]
|
29
|
-
|
30
|
-
spec.add_dependency "json", ">= 2.7.0" # see: https://github.com/ruby/json/pull/519
|
31
|
-
">= 7.1".tap do |rails_version|
|
32
|
-
spec.add_dependency "activejob", rails_version
|
33
|
-
spec.add_dependency "activerecord", rails_version
|
34
|
-
spec.add_dependency "activesupport", rails_version
|
35
|
-
spec.add_dependency "railties", rails_version
|
36
|
-
spec.add_development_dependency "actionmailer", rails_version
|
37
|
-
end
|
38
|
-
|
39
|
-
spec.add_development_dependency "chaotic_job"
|
40
|
-
spec.add_development_dependency "combustion"
|
41
|
-
spec.add_development_dependency "minitest"
|
42
|
-
spec.add_development_dependency "rake"
|
43
|
-
spec.add_development_dependency "rubocop"
|
44
|
-
spec.add_development_dependency "simplecov"
|
45
|
-
spec.add_development_dependency "sqlite3"
|
46
|
-
|
47
|
-
# For more information and examples about making a new gem, checkout our
|
48
|
-
# guide at: https://bundler.io/guides/creating_gem.html
|
49
|
-
spec.metadata["rubygems_mfa_required"] = "true"
|
50
|
-
end
|
data/bin/console
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "bundler/setup"
|
5
|
-
|
6
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
-
# with your gem easier. You can also use a different console, if you like.
|
8
|
-
|
9
|
-
require "combustion"
|
10
|
-
require "sqlite3"
|
11
|
-
Combustion.path = "test/combustion"
|
12
|
-
Combustion.initialize! :active_record, :active_job
|
13
|
-
|
14
|
-
require "acidic_job"
|
15
|
-
|
16
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
17
|
-
# require "pry"
|
18
|
-
# Pry.start
|
19
|
-
|
20
|
-
require "irb"
|
21
|
-
IRB.start(__FILE__)
|
data/bin/setup
DELETED
data/bin/test_all
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
run_tests() {
|
2
|
-
if [ "$#" -ne 2 ]; then
|
3
|
-
echo "Usage: run_tests RUBY_VERSION RAILS_VERSION"
|
4
|
-
echo "Example: run_tests 3.0.7 7.1"
|
5
|
-
return 1
|
6
|
-
fi
|
7
|
-
|
8
|
-
local ruby="$1"
|
9
|
-
local gemfile="gemfiles/rails_$2.gemfile"
|
10
|
-
|
11
|
-
echo "**************************************************"
|
12
|
-
echo "Running tests with Ruby $1 and Rails $2..."
|
13
|
-
ASDF_RUBY_VERSION=$ruby BUNDLE_GEMFILE=$gemfile bundle check ||
|
14
|
-
ASDF_RUBY_VERSION=$ruby BUNDLE_GEMFILE=$gemfile bundle install &&
|
15
|
-
ASDF_RUBY_VERSION=$ruby BUNDLE_GEMFILE=$gemfile bundle exec rake
|
16
|
-
}
|
17
|
-
|
18
|
-
run_tests "3.0.7" "7.1"
|
19
|
-
run_tests "3.1.6" "7.1"
|
20
|
-
run_tests "3.1.6" "7.2"
|
21
|
-
run_tests "3.2.5" "7.1"
|
22
|
-
run_tests "3.2.5" "7.2"
|
23
|
-
run_tests "3.2.5" "8.0"
|
24
|
-
run_tests "3.3.5" "7.1"
|
25
|
-
run_tests "3.3.5" "7.2"
|
26
|
-
run_tests "3.3.5" "8.0"
|
data/blog_post.md
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
# ACIDic Operations in Rails
|
2
|
-
|
3
|
-
At the conceptual heart of basically any software are "operations"—the discrete actions the software performs. At the horizon of basically any software is the goal to make that sofware _robust_. Typically, one makes a software system robust by making each of its operations robust. Moreover, typically, robustness in software is considered as the software being "ACIDic"—atomic, consistent, isolated, durable.
|
4
|
-
|
5
|
-
In a loosely collected series of articles, Brandur Leach lays out the core techniques and principles required to make an HTTP API properly ACIDic:
|
6
|
-
|
7
|
-
1. https://brandur.org/acid
|
8
|
-
2. https://brandur.org/http-transactions
|
9
|
-
3. https://brandur.org/job-drain
|
10
|
-
4. https://brandur.org/idempotency-keys
|
11
|
-
|
12
|
-
With these techniques and principles in mind, our challenge is bring them into the world of a standard Rails application. This will require us to conceptually map the concepts of an HTTP request, an API server action, and an HTTP response into the world of a running Rails process.
|
13
|
-
|
14
|
-
We can begin to make this mapping by observing that an API server action is a specific instantiation of the general concept of an "operation". Like all operations, it has a "trigger" (the HTTP request) and a "response" (the HTTP response). So, what we need is a foundation upon which to build our Rails "operations".
|
15
|
-
|
16
|
-
In order to help us find that tool, let us consider the necessary characteristics we need. We need something that we can easily trigger from other Ruby code throughout our Rails application (controller actions, model methods, model callbacks, etc.). It should also be able to be run both synchronously (blocking execution and then returning its response to the caller) and asychronously (non-blocking and the caller doesn't know its response). It should then also be able to retry a specific operation (in much the way that an API consumer can "retry an operation" by hitting the same endpoint with the same request).
|
17
|
-
|
18
|
-
As we lay out these characteristics, I imagine your mind is going where mine went—`ActiveJob` gives us a solid foundation upon which we can build "ACIDic" operations.
|
19
|
-
|
20
|
-
So, our challenge to build tooling which will allow us to make "operational" jobs _robust_.
|
21
|
-
|
22
|
-
What we need primarily is to be able to make our jobs *idempotent*, and one of the simplest yet still most powerful tools for making an operation idempotent is the idempotency key. As laid out in the article linked above, an idempotency key is a record that we store in our database to uniquely identify a particular execution of an operation and a related "recovery point" for where we are in the process of that operation.
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
data/combustion/log/test.log
DELETED
File without changes
|
data/gemfiles/rails_7.0.gemfile
DELETED
data/gemfiles/rails_7.1.gemfile
DELETED
data/gemfiles/rails_7.2.gemfile
DELETED
data/gemfiles/rails_8.0.gemfile
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
source "https://rubygems.org"
|
4
|
-
|
5
|
-
gem "activejob", "~> 8.0.0.rc1"
|
6
|
-
gem "activerecord", "~> 8.0.0.rc1"
|
7
|
-
gem "activesupport", "~> 8.0.0.rc1"
|
8
|
-
gem "railties", "~> 8.0.0.rc1"
|
9
|
-
gem "sqlite3", ">= 2.1.0"
|
10
|
-
|
11
|
-
gemspec path: "../"
|