delayable 0.4.2 → 0.5.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
  SHA256:
3
- metadata.gz: c17ddd3e91c54be2b587b653633a034aec19f240a0a15439b80aa5ed88a9c11f
4
- data.tar.gz: e589da2392206c0f1574199fd1bc3b3c2c59161886a2f11effeb32b79fb5ecfd
3
+ metadata.gz: fbc0e3130501e50157a5dd2807576126022d145f89a3a005eb596b41c3456ecf
4
+ data.tar.gz: 729e2cf6548e11b220d7f8f19da46e55c1e520de3046ced844c5b858e4b1b2e5
5
5
  SHA512:
6
- metadata.gz: 9c22ae61f2b817ac71bd85f96bb9d65f3d0d985a58b5fdf9dd67e10ec7654afc71943c09aa5710ac367a2a1bc9d5579b45eccdf365b486168f9df01ca0af5cbb
7
- data.tar.gz: 6c73c6c141da927a236674c774ec8ad3124128b3f0017e6d05ac40ae4a72a04eaf2fb9ac4d22076cd5f241b68b9c9b19cac42e5ab2cbe9bc35c6093b18b333e1
6
+ metadata.gz: 3bd0b541a0d948c9c320a0ed7caf4e8f5585a147ed551c7e1b1c397c119cf4a23969ac510888c0f985e1d7c00997fac896fbdc3aa850d9ba0dc0865670336bf2
7
+ data.tar.gz: c81b5c272398ea577e9030852410a7813a8abcad24d7ec3ea3843e36b1529a0dfd79647d80cfe12edc093dc298ea2963c45680894376405ee15d4c8a94e58fa0
data/CHANGELOG.md ADDED
@@ -0,0 +1,10 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ ## 0.5.0 - 2026-08-03
6
+
7
+ ### Added
8
+
9
+ - Added class-level `_all_later` helpers for delayed instance methods.
10
+ - Added bulk enqueue support through `ActiveJob.perform_all_later`, with individual enqueue fallback for Rails 7.0 and adapters without bulk support.
data/README.md CHANGED
@@ -9,6 +9,7 @@ A Ruby gem that makes it easy to convert any method call into a background job u
9
9
  - **Flexible Configuration**: Configure queue names, delays, and concurrency limits per method
10
10
  - **Method Parameter Support**: Full support for regular arguments, keyword arguments, and blocks
11
11
  - **Bang Method Handling**: Automatic support for methods ending with `!`
12
+ - **Bulk Enqueuing**: Enqueue the same instance method for many receivers at once
12
13
  - **ActiveJob Integration**: Seamlessly integrates with your existing ActiveJob setup
13
14
 
14
15
  ## Installation
@@ -80,6 +81,46 @@ processor.process_csv_import_later("/tmp/users.csv", 123)
80
81
  processor.sync_external_data_later("https://api.example.com/data", 1.hour.ago)
81
82
  ```
82
83
 
84
+ ### Bulk Instance Methods
85
+
86
+ Every delayed instance method also gets a class-level `_all_later` helper. It creates one job per receiver and passes the same positional and keyword arguments to each:
87
+
88
+ ```ruby
89
+ class Unit
90
+ include Delayable
91
+
92
+ def sync_channex_availability(date_from, date_to, channel:)
93
+ # Sync availability for this unit
94
+ end
95
+ delay :sync_channex_availability, queue: :integrations
96
+ end
97
+
98
+ Unit.sync_channex_availability_all_later(
99
+ units,
100
+ Date.current,
101
+ 1.year.from_now.to_date,
102
+ channel: :channex
103
+ )
104
+ ```
105
+
106
+ The helper preserves `Current.attributes` and all generated job configuration. A configured wait applies to every job and can be overridden per bulk call:
107
+
108
+ ```ruby
109
+ Unit.sync_channex_availability_all_later(
110
+ units,
111
+ date_from,
112
+ date_to,
113
+ channel: :channex,
114
+ wait: 30.seconds
115
+ )
116
+ ```
117
+
118
+ Bang methods use `_all_later!`, such as `Unit.refresh_all_later!(units)`. Delayable does not remove duplicate receivers; use `units.uniq` when needed. An empty collection returns without enqueuing anything.
119
+
120
+ Bulk helpers are only generated for instance methods. Delayed class methods still use their regular `_later` helper.
121
+
122
+ Delayable uses `ActiveJob.perform_all_later` when available (Rails 7.1+). A true bulk queue operation requires an ActiveJob adapter that implements `enqueue_all`; otherwise ActiveJob enqueues each job individually. On Rails 7.0, Delayable also falls back to individual enqueues.
123
+
83
124
  ### Class Methods
84
125
 
85
126
  You can also delay class methods by setting the `class_method: true` option:
@@ -429,6 +470,7 @@ DataProcessor::ProcessCsvImportJob.queue_name
429
470
  - Ruby >= 3.4.0
430
471
  - Rails >= 7.0.4.3
431
472
  - ActiveJob configured with a backend (Sidekiq, Resque, etc.)
473
+ - An ActiveJob adapter with `enqueue_all` support for a true bulk queue operation (optional)
432
474
  - **SolidQueue** (optional) - Required only if using `limits_concurrency` feature
433
475
 
434
476
  ## Contributing
@@ -1,3 +1,3 @@
1
1
  module Delayable
2
- VERSION = '0.4.2'.freeze
2
+ VERSION = '0.5.0'.freeze
3
3
  end
data/lib/delayable.rb CHANGED
@@ -25,10 +25,23 @@ module Delayable
25
25
  )
26
26
 
27
27
  defined_wait = wait
28
+ build_job = method(:delayable_build_job)
29
+ extract_wait = method(:delayable_extract_wait)
30
+ enqueue_jobs = method(:delayable_enqueue_jobs)
28
31
  delayable_define_method(class_method:, method_name:) do |*arguments, **kwargs|
29
- wait = kwargs.key?(:wait) ? kwargs.delete(:wait) : defined_wait
30
- run_data = { current_attributes: Current.attributes, record: self }
31
- job.set(wait:).perform_later(run_data, *arguments, **kwargs)
32
+ job_wait = extract_wait.call(kwargs, defined_wait)
33
+ build_job.call(job, self, job_wait, arguments, kwargs, enqueue: true)
34
+ end
35
+
36
+ return if class_method
37
+
38
+ delayable_define_bulk_method(method_name) do |receivers, *arguments, **kwargs|
39
+ receivers = receivers.to_a
40
+ next if receivers.empty?
41
+
42
+ job_wait = extract_wait.call(kwargs, defined_wait)
43
+ jobs = receivers.map { |receiver| build_job.call(job, receiver, job_wait, arguments, kwargs) }
44
+ enqueue_jobs.call(jobs)
32
45
  end
33
46
  end
34
47
 
@@ -56,6 +69,24 @@ module Delayable
56
69
  end
57
70
  end
58
71
 
72
+ def delayable_build_job(job, receiver, wait, arguments, kwargs, enqueue: false)
73
+ run_data = { current_attributes: Current.attributes, record: receiver }
74
+ return job.set(wait:).perform_later(run_data, *arguments, **kwargs) if enqueue
75
+
76
+ job.new(run_data, *arguments, **kwargs).set(wait:)
77
+ end
78
+
79
+ def delayable_extract_wait(kwargs, defined_wait)
80
+ kwargs.key?(:wait) ? kwargs.delete(:wait) : defined_wait
81
+ end
82
+
83
+ def delayable_enqueue_jobs(jobs)
84
+ return ActiveJob.perform_all_later(*jobs) if ActiveJob.respond_to?(:perform_all_later)
85
+
86
+ jobs.each(&:enqueue)
87
+ nil
88
+ end
89
+
59
90
  def delayable_job_name(method_name, class_method: false)
60
91
  class_name = bang_method?(method_name) ? "#{method_name.to_s.chomp('!').camelize}Bang" : method_name.to_s.camelize
61
92
  :"#{'Class' if class_method}#{class_name}Job"
@@ -63,8 +94,16 @@ module Delayable
63
94
 
64
95
  def delayable_define_method(class_method:, method_name:, &)
65
96
  define_method_type = class_method ? :define_singleton_method : :define_method
66
- method_name = bang_method?(method_name) ? "#{method_name.to_s.chomp('!')}_later!" : "#{method_name}_later"
67
- public_send(define_method_type, method_name, &)
97
+ public_send(define_method_type, delayable_method_name(method_name), &)
98
+ end
99
+
100
+ def delayable_define_bulk_method(method_name, &)
101
+ define_singleton_method(delayable_method_name(method_name, bulk: true), &)
102
+ end
103
+
104
+ def delayable_method_name(method_name, bulk: false)
105
+ suffix = bulk ? '_all_later' : '_later'
106
+ bang_method?(method_name) ? "#{method_name.to_s.chomp('!')}#{suffix}!" : "#{method_name}#{suffix}"
68
107
  end
69
108
 
70
109
  def bang_method?(method_name)
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: delayable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Trae Robrock
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2026-07-08 00:00:00.000000000 Z
10
+ date: 2026-08-03 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rails
@@ -33,6 +33,7 @@ extra_rdoc_files: []
33
33
  files:
34
34
  - ".rubocop.yml"
35
35
  - ".ruby-version"
36
+ - CHANGELOG.md
36
37
  - MIT-LICENSE
37
38
  - README.md
38
39
  - Rakefile