postburner 0.7.2 → 0.9.0.rc.1

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.
data/lib/postburner.rb CHANGED
@@ -1,8 +1,317 @@
1
1
  require "postburner/version"
2
2
  require "postburner/engine"
3
+ require "postburner/strategies/queue"
4
+ require "postburner/strategies/nice_queue"
5
+ require "postburner/strategies/test_queue"
6
+ require "postburner/strategies/immediate_test_queue"
7
+ require "postburner/strategies/null_queue"
3
8
 
9
+ # Postburner - PostgreSQL-backed job queue system built on Backburner and Beanstalkd.
10
+ #
11
+ # Postburner is a Ruby on Rails Engine that provides a database-backed job queue with
12
+ # full audit trails, inspection capabilities, and multiple execution strategies. Every
13
+ # job is stored as an ActiveRecord model, enabling database queries, foreign key
14
+ # relationships, and comprehensive statistics tracking.
15
+ #
16
+ # ## Core Concepts
17
+ #
18
+ # - **Jobs:** Subclass {Postburner::Job} and implement `perform` method
19
+ # - **Queue Strategies:** Control how jobs are executed (async, inline, test modes)
20
+ # - **Beanstalkd Integration:** Production queuing via Backburner
21
+ # - **Database Persistence:** Full audit trail with timestamps, logs, and errors
22
+ # - **Callbacks:** ActiveJob-style lifecycle hooks (enqueue, attempt, processing, processed)
23
+ #
24
+ # ## Queue Strategies
25
+ #
26
+ # Postburner uses a strategy pattern to control job execution:
27
+ #
28
+ # - **{NiceQueue}** (default): Async via Beanstalkd, gracefully handles premature execution
29
+ # - **{Queue}**: Async via Beanstalkd, strict premature execution errors
30
+ # - **{TestQueue}**: Inline/synchronous, requires explicit time travel for scheduled jobs
31
+ # - **{ImmediateTestQueue}**: Inline/synchronous with automatic time travel
32
+ # - **{NullQueue}**: Creates jobs without queueing, manual execution with time travel
33
+ #
34
+ # ## Auto-Detection
35
+ #
36
+ # Postburner automatically detects Rails test mode and switches to {TestQueue} when:
37
+ # - `Rails.env.test?` is true
38
+ # - `ActiveJob::Base.queue_adapter_name == :test`
39
+ #
40
+ # ## Usage
41
+ #
42
+ # @example Creating and queueing a job
43
+ # class ProcessPayment < Postburner::Job
44
+ # queue 'critical'
45
+ # queue_priority 0
46
+ #
47
+ # def perform(args)
48
+ # payment = Payment.find(args['payment_id'])
49
+ # payment.process!
50
+ # log "Payment #{payment.id} processed"
51
+ # end
52
+ # end
53
+ #
54
+ # job = ProcessPayment.create!(args: { 'payment_id' => 123 })
55
+ # job.queue!(delay: 1.hour)
56
+ #
57
+ # @example Switching queue strategies
58
+ # # Production with graceful premature handling (default)
59
+ # Postburner.nice_async_strategy!
60
+ #
61
+ # # Production with strict premature errors
62
+ # Postburner.async_strategy!
63
+ #
64
+ # # Test mode with explicit time control
65
+ # Postburner.inline_test_strategy!
66
+ #
67
+ # # Test mode with automatic time travel
68
+ # Postburner.inline_immediate_test_strategy!
69
+ #
70
+ # @example Using Beanstalkd connection
71
+ # Postburner.connected do |conn|
72
+ # conn.tubes['my.tube'].stats
73
+ # conn.tubes['my.tube'].kick(3)
74
+ # end
75
+ #
76
+ # @example Checking if in test mode
77
+ # if Postburner.testing?
78
+ # # Jobs execute inline
79
+ # else
80
+ # # Jobs queued to Beanstalkd
81
+ # end
82
+ #
83
+ # @see Postburner::Job
84
+ # @see NiceQueue
85
+ # @see Queue
86
+ # @see TestQueue
87
+ # @see ImmediateTestQueue
88
+ #
4
89
  module Postburner
90
+ # @!attribute [rw] queue_strategy
91
+ # The current queue strategy class used for job execution.
92
+ #
93
+ # Defaults to {NiceQueue} for production, auto-switches to {TestQueue}
94
+ # in Rails test environment.
95
+ #
96
+ # @return [Class] One of Queue, NiceQueue, TestQueue, or ImmediateTestQueue
97
+ #
98
+ # @example
99
+ # Postburner.queue_strategy
100
+ # # => Postburner::NiceQueue
101
+ #
102
+ # @see #nice_async_strategy!
103
+ # @see #async_strategy!
104
+ # @see #inline_test_strategy!
105
+ # @see #inline_immediate_test_strategy!
106
+ #
107
+ mattr_accessor :queue_strategy
5
108
 
109
+ # Initialize with NiceQueue (production) by default
110
+ # NiceQueue re-inserts premature jobs with appropriate delay
111
+ self.queue_strategy = Postburner::NiceQueue
112
+
113
+ # Auto-detect Rails test mode and switch to TestQueue
114
+ if defined?(Rails) && Rails.env.test? && defined?(ActiveJob::Base)
115
+ if ActiveJob::Base.queue_adapter_name == :test
116
+ self.queue_strategy = Postburner::TestQueue
117
+ end
118
+ end
119
+
120
+ # Activates strict test mode with inline job execution.
121
+ #
122
+ # Sets queue strategy to {TestQueue}, which executes jobs synchronously
123
+ # without Beanstalkd. Scheduled jobs (with future run_at) raise
124
+ # {Postburner::Job::PrematurePerform} exception, forcing explicit time
125
+ # management with `travel_to`.
126
+ #
127
+ # Use this strategy when you want explicit control over time progression
128
+ # in tests and want to catch scheduling bugs by failing loudly.
129
+ #
130
+ # @return [void]
131
+ #
132
+ # @example
133
+ # Postburner.inline_test_strategy!
134
+ # job = MyJob.create!(args: {})
135
+ # job.queue! # Executes immediately
136
+ # assert job.reload.processed_at
137
+ #
138
+ # @example With scheduled jobs
139
+ # Postburner.inline_test_strategy!
140
+ # job = MyJob.create!(args: {})
141
+ # job.queue!(delay: 1.hour)
142
+ # # Raises PrematurePerform - use travel_to instead
143
+ #
144
+ # @see TestQueue
145
+ # @see #inline_immediate_test_strategy!
146
+ #
147
+ def self.inline_test_strategy!
148
+ self.queue_strategy = Postburner::TestQueue
149
+ end
150
+
151
+ # Activates test mode with automatic time travel for scheduled jobs.
152
+ #
153
+ # Sets queue strategy to {ImmediateTestQueue}, which executes jobs
154
+ # synchronously and automatically uses time travel for jobs with future
155
+ # run_at timestamps.
156
+ #
157
+ # Use this strategy for integration/feature tests where you want
158
+ # convenience over explicit time control.
159
+ #
160
+ # @return [void]
161
+ #
162
+ # @example
163
+ # Postburner.inline_immediate_test_strategy!
164
+ # job = MyJob.create!(args: {})
165
+ # job.queue!(delay: 1.hour)
166
+ # # Automatically travels to scheduled time and executes
167
+ # assert job.reload.processed_at
168
+ #
169
+ # @note Jobs execute in queue order, not scheduled time order
170
+ # @note Requires ActiveSupport::Testing::TimeHelpers
171
+ #
172
+ # @see ImmediateTestQueue
173
+ # @see #inline_test_strategy!
174
+ #
175
+ def self.inline_immediate_test_strategy!
176
+ self.queue_strategy = Postburner::ImmediateTestQueue
177
+ end
178
+
179
+ # Activates strict production mode with asynchronous job execution.
180
+ #
181
+ # Sets queue strategy to {Queue}, which queues jobs to Beanstalkd and
182
+ # raises {Postburner::Job::PrematurePerform} if a job is executed before
183
+ # its scheduled run_at time.
184
+ #
185
+ # Use this strategy for production debugging or when you want strict
186
+ # enforcement of scheduling. For most production use cases, prefer
187
+ # {#nice_async_strategy!} instead.
188
+ #
189
+ # @return [void]
190
+ #
191
+ # @example
192
+ # Postburner.async_strategy!
193
+ # job = MyJob.create!(args: {})
194
+ # job.queue!(delay: 1.hour)
195
+ # # Queued to Beanstalkd, will raise if picked up early
196
+ #
197
+ # @note Requires Beanstalkd server running
198
+ # @note NOT the default production strategy
199
+ #
200
+ # @see Queue
201
+ # @see #nice_async_strategy!
202
+ #
203
+ def self.async_strategy!
204
+ self.queue_strategy = Postburner::Queue
205
+ end
206
+
207
+ # Activates default production mode with graceful premature handling.
208
+ #
209
+ # Sets queue strategy to {NiceQueue} (the default), which queues jobs to
210
+ # Beanstalkd and gracefully handles premature execution by re-inserting
211
+ # jobs with appropriate delay.
212
+ #
213
+ # This is the recommended production strategy and is set by default on
214
+ # initialization.
215
+ #
216
+ # @return [void]
217
+ #
218
+ # @example
219
+ # Postburner.nice_async_strategy!
220
+ # job = MyJob.create!(args: {})
221
+ # job.queue!(delay: 1.hour)
222
+ # # Queued to Beanstalkd, automatically re-inserted if picked up early
223
+ #
224
+ # @note This is the DEFAULT strategy
225
+ # @note Requires Beanstalkd server running
226
+ #
227
+ # @see NiceQueue
228
+ # @see #async_strategy!
229
+ #
230
+ def self.nice_async_strategy!
231
+ self.queue_strategy = Postburner::NiceQueue
232
+ end
233
+
234
+ # Activates null mode for creating jobs without queueing to Beanstalkd.
235
+ #
236
+ # Sets queue strategy to {NullQueue}, which creates job records in the
237
+ # database but does NOT queue them to Beanstalkd. Jobs can be executed
238
+ # later by manually calling {NullQueue.handle_perform!}, which includes
239
+ # automatic time travel for scheduled jobs.
240
+ #
241
+ # Use this strategy for deferred batch processing, conditional execution,
242
+ # or scenarios where you want to create jobs in advance and execute them
243
+ # manually on-demand.
244
+ #
245
+ # @return [void]
246
+ #
247
+ # @example Create job without queueing
248
+ # Postburner.null_strategy!
249
+ # job = MyJob.create!(args: {})
250
+ # job.queue!
251
+ # # Job created but NOT queued to Beanstalkd
252
+ # job.bkid # => nil
253
+ #
254
+ # @example Manually execute later
255
+ # Postburner.null_strategy!
256
+ # job = MyJob.create!(args: {})
257
+ # job.queue!(delay: 1.hour)
258
+ # # Later, manually execute with automatic time travel
259
+ # Postburner::Job.perform(job.id)
260
+ # # Job executes as if it's 1 hour in the future
261
+ #
262
+ # @note Jobs execute when manually triggered via Postburner::Job.perform
263
+ # @note Does not require Beanstalkd to be running
264
+ # @note Useful for batch processing and deferred execution patterns
265
+ #
266
+ # @see NullQueue
267
+ # @see Postburner::Job.perform
268
+ #
269
+ def self.null_strategy!
270
+ self.queue_strategy = Postburner::NullQueue
271
+ end
272
+
273
+ # Checks if currently using a test queue strategy.
274
+ #
275
+ # Returns true if the current queue strategy is {TestQueue} or
276
+ # {ImmediateTestQueue}, indicating that jobs execute inline/synchronously
277
+ # without Beanstalkd.
278
+ #
279
+ # @return [Boolean] true if using test strategy, false if using production strategy
280
+ #
281
+ # @example
282
+ # Postburner.nice_async_strategy!
283
+ # Postburner.testing? # => false
284
+ #
285
+ # Postburner.inline_test_strategy!
286
+ # Postburner.testing? # => true
287
+ #
288
+ # @see TestQueue
289
+ # @see ImmediateTestQueue
290
+ #
291
+ def self.testing?
292
+ queue_strategy.testing
293
+ end
294
+
295
+ # Returns a cached Beanstalkd connection.
296
+ #
297
+ # Creates a new {Backburner::Connection} using the configured Beanstalkd
298
+ # URL and caches it. Automatically reconnects if the connection is stale.
299
+ #
300
+ # For most use cases, prefer {#connected} which handles connection cleanup.
301
+ #
302
+ # @return [Backburner::Connection] Beanstalkd connection object
303
+ #
304
+ # @raise [Beaneater::NotConnected] if connection fails
305
+ #
306
+ # @example
307
+ # conn = Postburner.connection
308
+ # conn.tubes['my.tube'].stats
309
+ #
310
+ # @note Connection is cached in @_connection instance variable
311
+ # @note Automatically reconnects if connection is not active
312
+ #
313
+ # @see #connected
314
+ #
6
315
  def self.connection
7
316
  @_connection ||= Backburner::Connection.new(
8
317
  Backburner.configuration.beanstalk_url
@@ -11,6 +320,41 @@ module Postburner
11
320
  @_connection
12
321
  end
13
322
 
323
+ # Yields a Beanstalkd connection or returns cached connection.
324
+ #
325
+ # When called with a block, yields the connection and ensures it's closed
326
+ # after the block completes. When called without a block, returns the
327
+ # cached connection.
328
+ #
329
+ # @overload connected
330
+ # Returns the cached Beanstalkd connection.
331
+ # @return [Backburner::Connection] Beanstalkd connection
332
+ #
333
+ # @overload connected {|conn| ... }
334
+ # Yields connection and ensures cleanup.
335
+ # @yieldparam conn [Backburner::Connection] Beanstalkd connection
336
+ # @return [void]
337
+ #
338
+ # @example With block (recommended)
339
+ # Postburner.connected do |conn|
340
+ # conn.tubes.to_a.each do |tube|
341
+ # puts tube.name
342
+ # end
343
+ # end
344
+ # # Connection automatically closed
345
+ #
346
+ # @example Without block
347
+ # conn = Postburner.connected
348
+ # conn.tubes['my.tube'].stats
349
+ #
350
+ # @example Direct tube operations
351
+ # Postburner.connected do |conn|
352
+ # conn.tubes['critical'].kick(10)
353
+ # conn.tubes['background'].stats
354
+ # end
355
+ #
356
+ # @see #connection
357
+ #
14
358
  def self.connected
15
359
  if block_given?
16
360
  begin
@@ -23,6 +367,21 @@ module Postburner
23
367
  end
24
368
  end
25
369
 
370
+ # Removes all jobs from all tubes (not yet implemented).
371
+ #
372
+ # This is a destructive operation intended for development/testing cleanup.
373
+ # Requires confirmation string "CONFIRM" to prevent accidental execution.
374
+ #
375
+ # @param confirm [String] Must be exactly "CONFIRM" to execute
376
+ #
377
+ # @return [void]
378
+ #
379
+ # @example
380
+ # Postburner.remove_all!("CONFIRM")
381
+ #
382
+ # @note Currently a no-op - implementation pending
383
+ # @todo Implement job removal from all tubes
384
+ #
26
385
  def self.remove_all!(confirm)
27
386
  return unless confirm == "CONFIRM"
28
387
 
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: postburner
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 0.9.0.rc.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Smith
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2022-10-30 00:00:00.000000000 Z
10
+ date: 2025-11-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rails
@@ -16,14 +15,14 @@ dependencies:
16
15
  requirements:
17
16
  - - ">="
18
17
  - !ruby/object:Gem::Version
19
- version: '6.1'
18
+ version: '7.2'
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - ">="
25
24
  - !ruby/object:Gem::Version
26
- version: '6.1'
25
+ version: '7.2'
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: backburner
29
28
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +51,20 @@ dependencies:
52
51
  - - ">="
53
52
  - !ruby/object:Gem::Version
54
53
  version: 1.2.3
54
+ - !ruby/object:Gem::Dependency
55
+ name: ostruct
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 0.6.0
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: 0.6.0
55
68
  - !ruby/object:Gem::Dependency
56
69
  name: haml-rails
57
70
  requirement: !ruby/object:Gem::Requirement
@@ -79,6 +92,7 @@ files:
79
92
  - Rakefile
80
93
  - app/assets/config/postburner_manifest.js
81
94
  - app/assets/stylesheets/postburner/application.css
95
+ - app/concerns/postburner/callbacks.rb
82
96
  - app/controllers/postburner/application_controller.rb
83
97
  - app/controllers/postburner/jobs_controller.rb
84
98
  - app/controllers/postburner/static_controller.rb
@@ -98,6 +112,12 @@ files:
98
112
  - lib/generators/postburner/install/templates/migrations/create_postburner_jobs.rb.erb
99
113
  - lib/postburner.rb
100
114
  - lib/postburner/engine.rb
115
+ - lib/postburner/strategies/immediate_test_queue.rb
116
+ - lib/postburner/strategies/nice_queue.rb
117
+ - lib/postburner/strategies/null_queue.rb
118
+ - lib/postburner/strategies/queue.rb
119
+ - lib/postburner/strategies/test_queue.rb
120
+ - lib/postburner/time_helpers.rb
101
121
  - lib/postburner/version.rb
102
122
  - lib/tasks/postburner_tasks.rake
103
123
  homepage: https://gitlab.nearapogee.com/opensource/postburner
@@ -107,7 +127,6 @@ metadata:
107
127
  homepage_uri: https://gitlab.nearapogee.com/opensource/postburner
108
128
  source_code_uri: https://gitlab.nearapogee.com/opensource/postburner
109
129
  changelog_uri: https://gitlab.nearapogee.com/opensource/postburner/-/blob/master/CHANGELOG.md
110
- post_install_message:
111
130
  rdoc_options: []
112
131
  require_paths:
113
132
  - lib
@@ -122,8 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
122
141
  - !ruby/object:Gem::Version
123
142
  version: '0'
124
143
  requirements: []
125
- rubygems_version: 3.3.7
126
- signing_key:
144
+ rubygems_version: 3.6.2
127
145
  specification_version: 4
128
146
  summary: Postgres backed beanstalkd queue via backburner
129
147
  test_files: []