postburner 1.0.0.pre.12 → 1.0.0.pre.13

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: d49bdf9db5c61a4cc37f1ec0b0246b275f7ca825935e1083c98f9caef5ae383d
4
- data.tar.gz: 9990e7870348f823d415755d76d0e33b0b10528dd3412c793c2922829a2ab9fd
3
+ metadata.gz: 61fa262497356b4b08226b9cb7138184c9a0b46958cb7a81d4c4ebd622be5487
4
+ data.tar.gz: 93bd5ef944fa62392546d96d607d02c076d94a2dc6e7d8f18fc32cfc90cdd4ec
5
5
  SHA512:
6
- metadata.gz: 7b625d36b312e8eb1b1a4fb6509d87d23518a34943ee0150ccba3d57dd3b6b5970bbf40f5bf283be8c052b3be2b072888fa1fa3d47b9f72264b513ee5db7a05e
7
- data.tar.gz: 9fdd52fb338a3a6575042e2af955711128c02b9534074935a5360113391169f0ab53657c6155acf40ca8ee34424a2b01583500a3efb75eb48e9ea467e428c759
6
+ metadata.gz: e2129e509d590c58c9d46192f6a60ea4576af7e4e56f94fceceb3d39c0d8db8fbda7f4bb1e65f140b294d9b4378ea965ec728088517384034c07881cb186c6fe
7
+ data.tar.gz: 9807a50fd61a2c24e8fe0620cafbc4fd10d903cde1a7d2b5a21118452c709fd69578e211a152bd10752fef9ab82561524d3d5040ae896394f8bab07c0dbdf6df
data/README.md CHANGED
@@ -111,7 +111,7 @@ bundle exec rake postburner:work WORKER=default
111
111
  - [Beanstalkd Integration](#beanstalkd-integration)
112
112
  - [Installation](#installation)
113
113
  - [Deployment](#deployment)
114
- - [Web UI](#web-ui)
114
+ - [Web UI - v2 Coming Soon](#web-ui)
115
115
 
116
116
  ## Why
117
117
 
@@ -249,6 +249,30 @@ Jobs without `Postburner::Beanstalkd` use defaults from `config/postburner.yml`:
249
249
  - `default_priority: 65536`
250
250
  - `default_ttr: 300`
251
251
 
252
+ #### Configuring Third-Party Jobs
253
+
254
+ For jobs you don't control (e.g., `Turbo::Streams::BroadcastJob`, `ActionMailer::MailDeliveryJob`), use the `enqueue_options` hook:
255
+
256
+ ```ruby
257
+ # config/initializers/postburner.rb
258
+ Postburner.configure do |config|
259
+ config.enqueue_options = ->(job) do
260
+ case job.class.name
261
+ when 'Turbo::Streams::BroadcastJob'
262
+ { priority: 100, ttr: 60 }
263
+ when 'ActionMailer::MailDeliveryJob'
264
+ { priority: 500, ttr: 120 }
265
+ else
266
+ {} # Use defaults
267
+ end
268
+ end
269
+ end
270
+ ```
271
+
272
+ **Priority cascade:** `job.priority` (from `.set(priority: n)`) > `enqueue_options` hook > class-level > `default_priority`
273
+
274
+ **TTR cascade:** class-level `ttr` > `enqueue_options` hook > `default_ttr`
275
+
252
276
  ### Tracked Jobs
253
277
 
254
278
  Tracked jobs store full execution details in PostgreSQL, providing comprehensive audit trails (i.e. logging, timing, errors, retry tracking) for critical operations.
@@ -53,6 +53,9 @@ module Postburner
53
53
  #
54
54
  # @example Queue at specific time
55
55
  # job.queue!(at: Time.zone.now + 2.days)
56
+ # job.queue!(at: Time.zone.parse('2025-01-15 09:00:00'))
57
+ # job.queue!(at: '2025-01-15 09:00:00'.in_time_zone)
58
+ # job.queue!(at: Time.parse('2025-01-15 09:00:00 EST'))
56
59
  #
57
60
  # @example Queue with priority
58
61
  # job.queue!(pri: 0, delay: 30.minutes)
@@ -109,6 +109,7 @@ module Postburner
109
109
  validates :name, presence: true, uniqueness: true
110
110
  validates :job_class, presence: true
111
111
  validates :timezone, presence: true
112
+ validate :validate_timezone_exists!
112
113
  validate :validate_scheduling_mode!
113
114
  validate :validate_job_class_exists!
114
115
  validate :validate_cron_expression!, if: :cron?
@@ -387,6 +388,24 @@ module Postburner
387
388
  )
388
389
  end
389
390
 
391
+ # Validate that timezone is a recognized ActiveSupport timezone.
392
+ #
393
+ # Uses Time.find_zone to check if the timezone string resolves to a valid
394
+ # ActiveSupport::TimeZone. Invalid timezones would cause nil pointer errors
395
+ # during schedule calculations.
396
+ #
397
+ # @return [void]
398
+ #
399
+ # @api private
400
+ #
401
+ def validate_timezone_exists!
402
+ return if timezone.blank?
403
+
404
+ if Time.find_zone(timezone).nil?
405
+ errors.add(:timezone, "is not a recognized timezone")
406
+ end
407
+ end
408
+
390
409
  # Validate that exactly one scheduling mode is configured.
391
410
  #
392
411
  # Ensures either anchor+interval+interval_unit OR cron is set, but not both.
@@ -106,6 +106,47 @@ module ActiveJob
106
106
  job.class.included_modules.include?(Postburner::Tracked)
107
107
  end
108
108
 
109
+ # Resolves Beanstalkd options (priority and TTR) for a job.
110
+ #
111
+ # Uses a priority cascade:
112
+ # 1. job.priority (from .set(priority: n))
113
+ # 2. enqueue_options hook (for third-party jobs like Turbo)
114
+ # 3. Class-level configuration (postburner_ttr, priority DSL)
115
+ # 4. Global defaults from configuration
116
+ #
117
+ # @param job [ActiveJob::Base] The job instance
118
+ #
119
+ # @return [Hash] Hash with :pri and :ttr keys
120
+ #
121
+ def job_options(job)
122
+ hook_options = resolve_enqueue_options(job)
123
+
124
+ # Priority cascade: job.priority > hook > class-level > default
125
+ pri = job.priority ||
126
+ hook_options[:priority] ||
127
+ Postburner.configuration.default_priority
128
+
129
+ # TTR cascade: class-level > hook > default
130
+ ttr = (job.class.respond_to?(:postburner_ttr) && job.class.postburner_ttr) ||
131
+ hook_options[:ttr] ||
132
+ Postburner.configuration.default_ttr
133
+
134
+ { pri: pri, ttr: ttr }
135
+ end
136
+
137
+ # Calls the enqueue_options hook if configured.
138
+ #
139
+ # @param job [ActiveJob::Base] The job instance
140
+ #
141
+ # @return [Hash] Options hash with :priority and/or :ttr, or empty hash
142
+ #
143
+ def resolve_enqueue_options(job)
144
+ hook = Postburner.configuration.enqueue_options
145
+ return {} unless hook.respond_to?(:call)
146
+
147
+ hook.call(job) || {}
148
+ end
149
+
109
150
  # Enqueues a tracked job (with PostgreSQL audit trail).
110
151
  #
111
152
  # Creates a Postburner::TrackedJob record, then queues minimal payload
@@ -130,18 +171,13 @@ module ActiveJob
130
171
  # Queue to Beanstalkd with minimal payload
131
172
  Postburner.connected do |conn|
132
173
  tube_name = expand_tube_name(job.queue_name)
133
-
134
- # Get priority and TTR
135
- # Priority order: job.priority (from .set or class.priority) > default
136
- pri = job.priority || Postburner.configuration.default_priority
137
- ttr = job.class.respond_to?(:postburner_ttr) && job.class.postburner_ttr ||
138
- Postburner.configuration.default_ttr
174
+ opts = job_options(job)
139
175
 
140
176
  bkid = conn.tubes[tube_name].put(
141
177
  Postburner::ActiveJob::Payload.tracked_payload(job, tracked_job.id),
142
- pri: pri,
178
+ pri: opts[:pri],
143
179
  delay: delay,
144
- ttr: ttr
180
+ ttr: opts[:ttr]
145
181
  )
146
182
 
147
183
  # Update tracked_job with Beanstalkd ID
@@ -164,18 +200,13 @@ module ActiveJob
164
200
 
165
201
  Postburner.connected do |conn|
166
202
  tube_name = expand_tube_name(job.queue_name)
167
-
168
- # Get priority and TTR
169
- # Priority order: job.priority (from .set or class.priority) > default
170
- pri = job.priority || Postburner.configuration.default_priority
171
- ttr = job.class.respond_to?(:postburner_ttr) && job.class.postburner_ttr ||
172
- Postburner.configuration.default_ttr
203
+ opts = job_options(job)
173
204
 
174
205
  conn.tubes[tube_name].put(
175
206
  Postburner::ActiveJob::Payload.default_payload(job),
176
- pri: pri,
207
+ pri: opts[:pri],
177
208
  delay: delay,
178
- ttr: ttr
209
+ ttr: opts[:ttr]
179
210
  )
180
211
  end
181
212
  end
@@ -23,6 +23,7 @@ module Postburner
23
23
  # Global settings
24
24
  attr_accessor :beanstalk_url, :logger, :default_queue, :default_priority, :default_ttr
25
25
  attr_accessor :default_scheduler_interval, :default_scheduler_priority
26
+ attr_accessor :enqueue_options
26
27
 
27
28
  # Worker-specific settings (loaded for a single worker)
28
29
  attr_accessor :worker_config
@@ -35,6 +36,9 @@ module Postburner
35
36
  # @option options [Integer] :default_ttr Default time-to-run in seconds (default: 300)
36
37
  # @option options [Integer] :default_scheduler_interval Scheduler check interval in seconds (default: 300)
37
38
  # @option options [Integer] :default_scheduler_priority Scheduler job priority (default: 100)
39
+ # @option options [Proc] :enqueue_options Proc that receives job and returns options hash
40
+ # with :priority and/or :ttr keys. Called during enqueue to customize job options.
41
+ # Priority cascade: job.priority > hook > class-level > default
38
42
  # @option options [Hash] :worker_config Worker configuration hash with keys:
39
43
  # - :name [String] Worker name
40
44
  # - :queues [Array<String>] Queue/tube names to process
@@ -52,6 +56,7 @@ module Postburner
52
56
  @default_ttr = options[:default_ttr] || 300
53
57
  @default_scheduler_interval = options[:default_scheduler_interval] || 300
54
58
  @default_scheduler_priority = options[:default_scheduler_priority] || 100
59
+ @enqueue_options = options[:enqueue_options]
55
60
  @worker_config = options[:worker_config] || {
56
61
  name: 'default',
57
62
  queues: ['default'],
@@ -1,3 +1,3 @@
1
1
  module Postburner
2
- VERSION = '1.0.0.pre.12'
2
+ VERSION = '1.0.0.pre.13'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: postburner
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre.12
4
+ version: 1.0.0.pre.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Smith