active_job-performs 0.3.1 → 0.3.3
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/Gemfile.lock +15 -15
- data/README.md +97 -13
- data/lib/active_job/performs/version.rb +1 -1
- data/lib/active_job/performs.rb +15 -15
- metadata +3 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 360213ab324cae80fefcf276ecb9803ed8e4ec62166dc9eded626b67f8329b97
|
4
|
+
data.tar.gz: 92fa0c284711569f812da53e7acca9cbe15cea03aec0ccb9c2512465a7b93f39
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16fd7671e6eaeba29bac333597170661ca5333c3e14e3142ba910579316641dc2e2ba31f3fdd49508e5e0263a3fc67b34032e4ef61bb1b1a8dc3679a6a9ec26b
|
7
|
+
data.tar.gz: 353e3cf1bc646e32883352a2f4ebb80121987e415872ce9d0e32256fcbed7f559e66576a1ee15b71e2fec3930d54f362a5b8905cd502cac7daf4df7b618191e3
|
data/Gemfile.lock
CHANGED
@@ -1,22 +1,22 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
active_job-performs (0.3.
|
4
|
+
active_job-performs (0.3.3)
|
5
5
|
activejob (>= 6.1)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
activejob (7.1.3.
|
11
|
-
activesupport (= 7.1.3.
|
10
|
+
activejob (7.1.3.4)
|
11
|
+
activesupport (= 7.1.3.4)
|
12
12
|
globalid (>= 0.3.6)
|
13
|
-
activemodel (7.1.3.
|
14
|
-
activesupport (= 7.1.3.
|
15
|
-
activerecord (7.1.3.
|
16
|
-
activemodel (= 7.1.3.
|
17
|
-
activesupport (= 7.1.3.
|
13
|
+
activemodel (7.1.3.4)
|
14
|
+
activesupport (= 7.1.3.4)
|
15
|
+
activerecord (7.1.3.4)
|
16
|
+
activemodel (= 7.1.3.4)
|
17
|
+
activesupport (= 7.1.3.4)
|
18
18
|
timeout (>= 0.4.0)
|
19
|
-
activesupport (7.1.3.
|
19
|
+
activesupport (7.1.3.4)
|
20
20
|
base64
|
21
21
|
bigdecimal
|
22
22
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
@@ -28,7 +28,7 @@ GEM
|
|
28
28
|
tzinfo (~> 2.0)
|
29
29
|
base64 (0.2.0)
|
30
30
|
bigdecimal (3.1.8)
|
31
|
-
concurrent-ruby (1.
|
31
|
+
concurrent-ruby (1.3.3)
|
32
32
|
connection_pool (2.4.1)
|
33
33
|
debug (1.9.2)
|
34
34
|
irb (~> 1.10)
|
@@ -39,10 +39,10 @@ GEM
|
|
39
39
|
i18n (1.14.5)
|
40
40
|
concurrent-ruby (~> 1.0)
|
41
41
|
io-console (0.7.2)
|
42
|
-
irb (1.13.
|
42
|
+
irb (1.13.2)
|
43
43
|
rdoc (>= 4.0.0)
|
44
44
|
reline (>= 0.4.2)
|
45
|
-
minitest (5.
|
45
|
+
minitest (5.24.0)
|
46
46
|
minitest-sprint (1.2.2)
|
47
47
|
path_expander (~> 1.1)
|
48
48
|
mutex_m (0.2.0)
|
@@ -52,11 +52,11 @@ GEM
|
|
52
52
|
rake (13.2.1)
|
53
53
|
rdoc (6.7.0)
|
54
54
|
psych (>= 4.0.0)
|
55
|
-
reline (0.5.
|
55
|
+
reline (0.5.9)
|
56
56
|
io-console (~> 0.5)
|
57
57
|
sqlite3 (1.7.3-arm64-darwin)
|
58
58
|
sqlite3 (1.7.3-x86_64-linux)
|
59
|
-
stringio (3.1.
|
59
|
+
stringio (3.1.1)
|
60
60
|
timeout (0.4.1)
|
61
61
|
tzinfo (2.0.6)
|
62
62
|
concurrent-ruby (~> 1.0)
|
@@ -76,4 +76,4 @@ DEPENDENCIES
|
|
76
76
|
sqlite3 (~> 1.4)
|
77
77
|
|
78
78
|
BUNDLED WITH
|
79
|
-
2.5.
|
79
|
+
2.5.14
|
data/README.md
CHANGED
@@ -1,8 +1,85 @@
|
|
1
1
|
# ActiveJob::Performs
|
2
2
|
|
3
|
-
`ActiveJob::Performs` adds
|
3
|
+
`ActiveJob::Performs` adds a `performs` class method to make the model + job loop vastly more conventional. You use it like this:
|
4
4
|
|
5
|
-
|
5
|
+
```ruby
|
6
|
+
class Post < ApplicationRecord
|
7
|
+
performs :publish
|
8
|
+
# Or `performs def publish`!
|
9
|
+
|
10
|
+
def publish
|
11
|
+
# Some logic to publish a post
|
12
|
+
end
|
13
|
+
end
|
14
|
+
```
|
15
|
+
|
16
|
+
Here's what `performs` generates under the hood:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
class Post < ApplicationRecord
|
20
|
+
class Job < ApplicationJob; end # We build a general Job class to share configuration between method jobs.
|
21
|
+
|
22
|
+
# Individual method jobs inherit from the `Post::Job` defined above.
|
23
|
+
class PublishJob < Job
|
24
|
+
# We generate the required `perform` method passing in the `post` and calling `publish` on it.
|
25
|
+
def perform(post, *, **) = post.publish(*, **)
|
26
|
+
end
|
27
|
+
|
28
|
+
# On Rails 7.1+, where `ActiveJob.perform_all_later` exists, we also generate
|
29
|
+
# a bulk method to enqueue many jobs at once. So you can do this:
|
30
|
+
#
|
31
|
+
# Post.unpublished.in_batches.each(&:publish_later_bulk)
|
32
|
+
def self.publish_later_bulk(set = all)
|
33
|
+
ActiveJob.perform_all_later set.map { PublishJob.new(_1) }
|
34
|
+
end
|
35
|
+
|
36
|
+
# We generate `publish_later` to wrap the job execution forwarding arguments and options.
|
37
|
+
def publish_later(*, **) = PublishJob.perform_later(self, *, **)
|
38
|
+
|
39
|
+
def publish
|
40
|
+
# Some logic to publish a post.
|
41
|
+
end
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
## Benefits
|
46
|
+
|
47
|
+
1. Conventional Jobs: they'll now mostly call instance methods like `publish_later` -> `publish`.
|
48
|
+
1. Follows Rails' internal conventions: this borrows from `ActionMailbox::InboundEmail#process_later` calling `process` and `ActionMailer::Base#deliver_later` calling `deliver`.
|
49
|
+
1. Clarity & less guess work: the `_later` methods standardize how you call jobs throughout your app, so you can instantly tell what's happening.
|
50
|
+
1. Less tedium: getting an instance method run in the background is just now a `performs` call with some potential configuration.
|
51
|
+
1. Fewer files to manage: you don't have to dig up something in `app/jobs` just to learn almost nothing from the boilerplate in there.
|
52
|
+
1. Remaining jobs stand out: `app/jobs` is way lighter, so any jobs in there that don't fit the `performs` pattern now stand out way more.
|
53
|
+
1. More consolidated logic: sometimes Job classes house model-level logic, but now it's all the way out in `app/jobs` instead of `app/models`, huh?
|
54
|
+
|
55
|
+
> [!TIP]
|
56
|
+
> On that last point, `performs` does put more logic back within your Active Records, so if you need further encapsulation to prevent them growing too large, consider checking out [active_record-associated_object](https://github.com/kaspth/active_record-associated_object).
|
57
|
+
|
58
|
+
### Used in production & praise from people
|
59
|
+
|
60
|
+
The https://www.rubyevents.org team uses `ActiveJob::Performs` quite a bit:
|
61
|
+
|
62
|
+
- [See `performs` calls in RubyEvents](https://github.com/search?q=repo%3Arubyevents%2Frubyevents+performs+language%3ARuby&type=code&l=Ruby)
|
63
|
+
|
64
|
+
|
65
|
+
Here's what [@claudiob](https://github.com/claudiob) had to say after using `ActiveJob::Performs`:
|
66
|
+
|
67
|
+
> I’ve been using active_job-performs for the last month and I love it love it love it!!
|
68
|
+
>
|
69
|
+
> Your thought process behind it is so thorough. I have a bunch of jobs now attached to models and my app/jobs folder… is empty!!
|
70
|
+
>
|
71
|
+
> This saves me a lot of mental hoops, I don’t have to switch between files anymore, everything is self-contained. Thank you!!!
|
72
|
+
|
73
|
+
From [@andycroll](https://github.com/andycroll) in a [writeup](https://andycroll.com/ruby/launching-usingrails) about launching [UsingRails](https://usingrails.com):
|
74
|
+
|
75
|
+
> I’ve also adopted a couple of gems—with exceptional Rails-level taste and author pedigree—that I hadn’t used in anger before, including `active_job-performs` from Kasper […]. Would recommend both.
|
76
|
+
|
77
|
+
And [@nshki](https://github.com/nshki) after trying it:
|
78
|
+
|
79
|
+
> Spent some time playing with [@kaspth](https://github.com/kaspth)'s [`ActiveRecord::AssociatedObject`](https://github.com/kaspth/active_record-associated_object) and `ActiveJob::Performs` and wow! The conventions these gems put in place help simplify a codebase drastically. I particularly love `ActiveJob::Performs`—it helped me refactor out all `ApplicationJob` classes I had and keep important context in the right domain model.
|
80
|
+
|
81
|
+
## Usage
|
82
|
+
### with `ActiveRecord::Base` & other `GlobalID::Identification` objects
|
6
83
|
|
7
84
|
`ActiveJob::Performs` works with any object that has `include GlobalID::Identification` and responds to that interface.
|
8
85
|
|
@@ -13,7 +90,7 @@ class Post < ActiveRecord::Base
|
|
13
90
|
extend ActiveJob::Performs # We technically auto-extend ActiveRecord::Base, but other object hierarchies need this.
|
14
91
|
|
15
92
|
# `performs` builds a `Post::PublishJob` and routes configs over to it.
|
16
|
-
performs :publish, queue_as: :important, discard_on: SomeError do
|
93
|
+
performs :publish, queue_adapter: :sidekiq, queue_as: :important, discard_on: SomeError do
|
17
94
|
retry_on TimeoutError, wait: :polynomially_longer
|
18
95
|
end
|
19
96
|
|
@@ -32,6 +109,7 @@ class Post < ActiveRecord::Base
|
|
32
109
|
|
33
110
|
# Individual method jobs inherit from the `Post::Job` defined above.
|
34
111
|
class PublishJob < Job
|
112
|
+
self.queue_adapter = :sidekiq
|
35
113
|
queue_as :important
|
36
114
|
discard_on SomeError
|
37
115
|
retry_on TimeoutError, wait: :polynomially_longer
|
@@ -46,8 +124,12 @@ class Post < ActiveRecord::Base
|
|
46
124
|
# a bulk method to enqueue many jobs at once. So you can do this:
|
47
125
|
#
|
48
126
|
# Post.unpublished.in_batches.each(&:publish_later_bulk)
|
49
|
-
|
50
|
-
|
127
|
+
#
|
128
|
+
# Or pass in a subset of posts as an argument:
|
129
|
+
#
|
130
|
+
# Post.publish_later_bulk Post.unpublished
|
131
|
+
def self.publish_later_bulk(set = all)
|
132
|
+
ActiveJob.perform_all_later set.map { PublishJob.new(_1) }
|
51
133
|
end
|
52
134
|
|
53
135
|
# We generate `publish_later` to wrap the job execution.
|
@@ -61,7 +143,10 @@ class Post < ActiveRecord::Base
|
|
61
143
|
end
|
62
144
|
```
|
63
145
|
|
64
|
-
|
146
|
+
> [!NOTE]
|
147
|
+
> We prefer & call `{name}=` setter methods, but fall back to getters. That's how we support `self.queue_adapter=`, but also `queue_as` which is not configured via `queue_as=`.
|
148
|
+
|
149
|
+
We generate the `Post::Job` class above to share configuration between method level jobs. E.g. if you had a `retract` method that was setup very similar, you could do:
|
65
150
|
|
66
151
|
```ruby
|
67
152
|
class Post < ActiveRecord::Base
|
@@ -184,7 +269,7 @@ end
|
|
184
269
|
|
185
270
|
### Usage with `ActiveRecord::AssociatedObject`
|
186
271
|
|
187
|
-
The [`ActiveRecord::AssociatedObject`](https://github.com/kaspth/active_record-associated_object) gem also implements `GlobalID::Identification`, so you
|
272
|
+
The [`ActiveRecord::AssociatedObject`](https://github.com/kaspth/active_record-associated_object) gem also implements `GlobalID::Identification`, so you use `performs` exactly like you would on Active Records:
|
188
273
|
|
189
274
|
```ruby
|
190
275
|
class Post::Publisher < ActiveRecord::AssociatedObject
|
@@ -204,6 +289,11 @@ class Post::Publisher < ActiveRecord::AssociatedObject
|
|
204
289
|
end
|
205
290
|
```
|
206
291
|
|
292
|
+
> [!NOTE]
|
293
|
+
> There's one difference with Active Record: you must pass in a set to `_later_bulk` methods. Like so:
|
294
|
+
>
|
295
|
+
> `Post::Publisher.publish_later_bulk Post::Publisher.first(10)`
|
296
|
+
|
207
297
|
### Passing `wait` to `performs`
|
208
298
|
|
209
299
|
If there's a job you want to defer, `performs` can set it for each invocation:
|
@@ -230,12 +320,6 @@ class Post < ActiveRecord::Base
|
|
230
320
|
end
|
231
321
|
```
|
232
322
|
|
233
|
-
### Praise from people
|
234
|
-
|
235
|
-
Here's what [@nshki](https://github.com/nshki) found when they tried `ActiveJob::Performs`:
|
236
|
-
|
237
|
-
> Spent some time playing with [@kaspth](https://github.com/kaspth)'s [`ActiveRecord::AssociatedObject`](https://github.com/kaspth/active_record-associated_object) and `ActiveJob::Performs` and wow! The conventions these gems put in place help simplify a codebase drastically. I particularly love `ActiveJob::Performs`—it helped me refactor out all `ApplicationJob` classes I had and keep important context in the right domain model.
|
238
|
-
|
239
323
|
## Installation
|
240
324
|
|
241
325
|
Install the gem and add to the application's Gemfile by executing:
|
data/lib/active_job/performs.rb
CHANGED
@@ -5,18 +5,14 @@ require_relative "performs/version"
|
|
5
5
|
module ActiveJob; end
|
6
6
|
module ActiveJob::Performs
|
7
7
|
module Waiting
|
8
|
-
|
9
|
-
value.respond_to?(:call) ? value : proc { value }
|
10
|
-
end unless Kernel.respond_to?(:Proc) # Optimistically assume Ruby gets this and it'll work fine.
|
8
|
+
attr_reader :wait, :wait_until
|
11
9
|
|
12
|
-
def wait(value
|
13
|
-
@wait =
|
14
|
-
@wait
|
10
|
+
def wait=(value)
|
11
|
+
@wait = value.respond_to?(:call) ? value : proc { value }
|
15
12
|
end
|
16
13
|
|
17
|
-
def wait_until(value
|
18
|
-
@wait_until =
|
19
|
-
@wait_until
|
14
|
+
def wait_until=(value)
|
15
|
+
@wait_until = value.respond_to?(:call) ? value : proc { value }
|
20
16
|
end
|
21
17
|
|
22
18
|
def scoped_by_wait(record)
|
@@ -46,10 +42,10 @@ module ActiveJob::Performs
|
|
46
42
|
end
|
47
43
|
RUBY
|
48
44
|
|
49
|
-
if ActiveJob.respond_to?(:perform_all_later)
|
45
|
+
if ActiveJob.respond_to?(:perform_all_later)
|
50
46
|
class_eval <<~RUBY, __FILE__, __LINE__ + 1
|
51
|
-
def self.#{method}_later_bulk#{suffix}
|
52
|
-
ActiveJob.perform_all_later
|
47
|
+
def self.#{method}_later_bulk#{suffix}(set#{" = all" if respond_to?(:all)})
|
48
|
+
ActiveJob.perform_all_later set.map { #{job}.scoped_by_wait(_1).new(_1) }
|
53
49
|
end
|
54
50
|
RUBY
|
55
51
|
end
|
@@ -69,9 +65,13 @@ module ActiveJob::Performs
|
|
69
65
|
name.safe_constantize || const_set(name, Class.new(yield))
|
70
66
|
end
|
71
67
|
|
72
|
-
def apply_performs_to(
|
73
|
-
|
74
|
-
|
68
|
+
def apply_performs_to(job, **configs, &block)
|
69
|
+
job.class_exec(&block) if block_given?
|
70
|
+
|
71
|
+
configs.each do |name, value|
|
72
|
+
name = "#{name}=".then.find { job.respond_to? _1 } || name
|
73
|
+
job.public_send name, value
|
74
|
+
end
|
75
75
|
end
|
76
76
|
|
77
77
|
def performs_later_methods
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_job-performs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kasper Timm Hansen
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: activejob
|
@@ -24,7 +23,6 @@ dependencies:
|
|
24
23
|
- - ">="
|
25
24
|
- !ruby/object:Gem::Version
|
26
25
|
version: '6.1'
|
27
|
-
description:
|
28
26
|
email:
|
29
27
|
- hey@kaspth.com
|
30
28
|
executables: []
|
@@ -47,7 +45,6 @@ metadata:
|
|
47
45
|
homepage_uri: https://github.com/kaspth/active_job-performs
|
48
46
|
source_code_uri: https://github.com/kaspth/active_job-performs
|
49
47
|
changelog_uri: https://github.com/kaspth/active_job-performs/blob/main/CHANGELOG.md
|
50
|
-
post_install_message:
|
51
48
|
rdoc_options: []
|
52
49
|
require_paths:
|
53
50
|
- lib
|
@@ -62,8 +59,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
62
59
|
- !ruby/object:Gem::Version
|
63
60
|
version: '0'
|
64
61
|
requirements: []
|
65
|
-
rubygems_version: 3.
|
66
|
-
signing_key:
|
62
|
+
rubygems_version: 3.6.9
|
67
63
|
specification_version: 4
|
68
64
|
summary: ActiveJob::Performs adds the `performs` macro to set up jobs by convention.
|
69
65
|
test_files: []
|