postburner 0.6.5 → 0.7.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: 7712222bcad943495a38f620aefaffbcc26d3483e68c07c1aae5102d20144baf
4
- data.tar.gz: 1dc644fcdb72b196e2694c2dd935b4f08cf3229873c08625a4db898e0195e7a3
3
+ metadata.gz: 9d8b5fb47d69c141d348c00520ff51579fc67f8300ac804f75b96cb023a8c584
4
+ data.tar.gz: 49d79bc8e8e04edc9cca6d74e5f66326573a8defc859fc54d875c02dee626e4b
5
5
  SHA512:
6
- metadata.gz: ea6308f6a9a13134ca84a693a933818d82d3ccf05a02f7f1bfc51a8d37178419143e9903e2f0b9a529dc3cab283196122dc6be833d0eeee10ec0a1ea3b5a9889
7
- data.tar.gz: 1b8ac590e3289de30eccfe3ef6a4d65fa0e034d6f43069b03e1190b324dab38dc65d5eb358e3ea306daa15db044a86151e3118a27b803cee2d78bfbfbd99facc
6
+ metadata.gz: 9f835395176f8ce70a2790e2e6f34e08ae051fde7711bd2ed17f83f2f211133dc15ba914967e5cf0737ab57b4e1737ea055cbb283ff4223f76921ad1dd2aea29
7
+ data.tar.gz: a793a67476072574c1f5e1a2439d21377ea2074053a3ef6834daac4c28fe9e72048e0d6333c1536dce4dcf8801ea449d8f506dd3e76c0d2af8631c21b94b304b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.7.0 - 2022-10-24
4
+
5
+ ### Added
6
+ - - add ActiveJob style callbacks for enqueue, attempt, processing, and processed.
7
+
8
+ ### Fixed
9
+ - remove assets config as for rails >=7
10
+
3
11
  ## v0.6.5 - 2022-05-21
4
12
 
5
13
  ### Fixed
@@ -0,0 +1,286 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/callbacks"
4
+ require "active_support/core_ext/object/with_options"
5
+ require "active_support/core_ext/module/attribute_accessors"
6
+
7
+ module Postburner
8
+ # = Postburner Job Callbacks
9
+ #
10
+ # Postburner Job provides hooks during the life cycle of a job. Callbacks allow you
11
+ # to trigger logic during this cycle. In called order, available callbacks are:
12
+ #
13
+ # * <tt>before_enqueue</tt>
14
+ # * <tt>after_enqueue</tt>
15
+ # * <tt>before_attempt</tt>
16
+ # * <tt>before_processing</tt>
17
+ # * <tt>after_processing</tt>
18
+ # * <tt>after_processed</tt>
19
+ # * <tt>after_attempt</tt>
20
+ #
21
+ # Around callbacks are also defined:
22
+ # * <tt>around_enqueue</tt>
23
+ # * <tt>around_attempt</tt>
24
+ # * <tt>around_processing</tt>
25
+ #
26
+ # NOTE: Calling the same callback multiple times will overwrite previous callback definitions.
27
+ #
28
+ module Callbacks
29
+ extend ActiveSupport::Concern
30
+ include ActiveSupport::Callbacks
31
+
32
+ included do
33
+ cattr_accessor :skip_after_callbacks_if_terminated,
34
+ instance_accessor: false,
35
+ default: false
36
+
37
+ with_options(skip_after_callbacks_if_terminated: skip_after_callbacks_if_terminated) do
38
+ define_callbacks :enqueue
39
+ define_callbacks :attempt
40
+ define_callbacks :processing
41
+ define_callbacks :processed
42
+ end
43
+ end
44
+ module ClassMethods
45
+ def inherited(klass)
46
+ klass.get_callbacks(:enqueue).
47
+ config[:skip_after_callbacks_if_terminated] =
48
+ skip_after_callbacks_if_terminated
49
+ klass.get_callbacks(:processing).
50
+ config[:skip_after_callbacks_if_terminated] =
51
+ skip_after_callbacks_if_terminated
52
+ klass.get_callbacks(:attempt).
53
+ config[:skip_after_callbacks_if_terminated] =
54
+ skip_after_callbacks_if_terminated
55
+ klass.get_callbacks(:processed).
56
+ config[:skip_after_callbacks_if_terminated] =
57
+ skip_after_callbacks_if_terminated
58
+ super
59
+ end
60
+
61
+ # Defines a callback that will get called right before the
62
+ # job starts and any metadata is persisted.
63
+ #
64
+ # class VideoProcessJob < Postburner::Base
65
+ #
66
+ # before_attempt do |job|
67
+ # $statsd.increment "attempting-video-job.try"
68
+ # end
69
+ #
70
+ # def perform(video_id)
71
+ # Video.find(video_id).process
72
+ # end
73
+ # end
74
+ #
75
+ def before_attempt(*filters, &blk)
76
+ set_callback(:attempt, :before, *filters, &blk)
77
+ end
78
+
79
+ # Defines a callback that will get called right after the
80
+ # job finishes and all metadata is persisted.
81
+ #
82
+ # This isn't called unless the attempt finishes without error,
83
+ # though this is subject to change in the future
84
+ #
85
+ # class VideoProcessJob < Postburner::Base
86
+ #
87
+ # before_attempt do |job|
88
+ # $statsd.increment "attempt-complete-video-job.try"
89
+ # end
90
+ #
91
+ # def perform(video_id)
92
+ # Video.find(video_id).process
93
+ # end
94
+ # end
95
+ #
96
+ def after_attempt(*filters, &blk)
97
+ set_callback(:attempt, :after, *filters, &blk)
98
+ end
99
+
100
+ # Defines a callback that will get called around the attempt
101
+ # of the job.
102
+ #
103
+ # class VideoProcessJob < Postburner::Base
104
+ #
105
+ # around_enqueue do |job, block|
106
+ # $statsd.time "video-job.process" do
107
+ # block.call
108
+ # end
109
+ # end
110
+ #
111
+ # def perform(video_id)
112
+ # Video.find(video_id).process
113
+ # end
114
+ # end
115
+ #
116
+ def around_attempt(*filters, &blk)
117
+ set_callback(:attempt, :around, *filters, &blk)
118
+ end
119
+
120
+ # Defines a callback that will get called right before the
121
+ # job's perform method is executed.
122
+ #
123
+ # class VideoProcessJob < Postburner::Base
124
+ #
125
+ # before_processing do |job|
126
+ # UserMailer.notify_video_started_processing(job.arguments.first)
127
+ # end
128
+ #
129
+ # def perform(video_id)
130
+ # Video.find(video_id).process
131
+ # end
132
+ # end
133
+ #
134
+ def before_processing(*filters, &blk)
135
+ set_callback(:processing, :before, *filters, &blk)
136
+ end
137
+
138
+ # Defines a callback that will get called right after the
139
+ # job's perform method has finished.
140
+ #
141
+ # class VideoProcessJob < Postburner::Base
142
+ #
143
+ # after_processing do |job|
144
+ # UserMailer.notify_video_processed(job.arguments.first)
145
+ # end
146
+ #
147
+ # def perform(video_id)
148
+ # Video.find(video_id).process
149
+ # end
150
+ # end
151
+ #
152
+ def after_processing(*filters, &blk)
153
+ set_callback(:processing, :after, *filters, &blk)
154
+ end
155
+
156
+ # Defines a callback that will get called around the job's perform method.
157
+ #
158
+ # class VideoProcessJob < Postburner::Base
159
+ #
160
+ # around_processing do |job, block|
161
+ # UserMailer.notify_video_started_processing(job.arguments.first)
162
+ # block.call
163
+ # UserMailer.notify_video_processed(job.arguments.first)
164
+ # end
165
+ #
166
+ # def perform(video_id)
167
+ # Video.find(video_id).process
168
+ # end
169
+ # end
170
+ #
171
+ # You can access the return value of the job only if the execution wasn't halted.
172
+ #
173
+ # class VideoProcessJob < Postburner::Base
174
+ # around_processing do |job, block|
175
+ # value = block.call
176
+ # puts value # => "Hello World!"
177
+ # end
178
+ #
179
+ # def perform
180
+ # "Hello World!"
181
+ # end
182
+ # end
183
+ #
184
+ def around_processing(*filters, &blk)
185
+ set_callback(:processing, :around, *filters, &blk)
186
+ end
187
+
188
+ # Defines a callback that will get called right after the
189
+ # job's processed_at timestamp has been persisted, marking the
190
+ # job as successfully completed, i.e. no errors raised.
191
+ #
192
+ # This is rather similar to after_processing but all of the
193
+ # job's metadata has been set.
194
+ #
195
+ # class VideoProcessJob < Postburner::Base
196
+ #
197
+ # after_processed do |job|
198
+ # UserMailer.notify_video_processed(job.arguments.first)
199
+ # end
200
+ #
201
+ # def perform(video_id)
202
+ # Video.find(video_id).process
203
+ # end
204
+ # end
205
+ #
206
+ def after_processed(*filters, &blk)
207
+ set_callback(:processed, :after, *filters, &blk)
208
+ end
209
+
210
+ # Defines a callback that will get called right before the
211
+ # job is enqueued.
212
+ #
213
+ # class VideoProcessJob < Postburner::Base
214
+ #
215
+ # before_enqueue do |job|
216
+ # $statsd.increment "enqueue-video-job.try"
217
+ # end
218
+ #
219
+ # def perform(video_id)
220
+ # Video.find(video_id).process
221
+ # end
222
+ # end
223
+ #
224
+ def before_enqueue(*filters, &blk)
225
+ set_callback(:enqueue, :before, *filters, &blk)
226
+ end
227
+
228
+ # Defines a callback that will get called right after the
229
+ # job is enqueued.
230
+ #
231
+ # class VideoProcessJob < Postburner::Base
232
+ #
233
+ # after_enqueue do |job|
234
+ # $statsd.increment "enqueue-video-job.success"
235
+ # end
236
+ #
237
+ # def perform(video_id)
238
+ # Video.find(video_id).process
239
+ # end
240
+ # end
241
+ #
242
+ def after_enqueue(*filters, &blk)
243
+ set_callback(:enqueue, :after, *filters, &blk)
244
+ end
245
+
246
+ # Defines a callback that will get called around the enqueuing
247
+ # of the job.
248
+ #
249
+ # class VideoProcessJob < Postburner::Base
250
+ #
251
+ # around_enqueue do |job, block|
252
+ # $statsd.time "video-job.process" do
253
+ # block.call
254
+ # end
255
+ # end
256
+ #
257
+ # def perform(video_id)
258
+ # Video.find(video_id).process
259
+ # end
260
+ # end
261
+ #
262
+ def around_enqueue(*filters, &blk)
263
+ set_callback(:enqueue, :around, *filters, &blk)
264
+ end
265
+ end
266
+
267
+ private
268
+
269
+ # NOTE processed / attempt exclueded here -- intentionally
270
+ #
271
+ def halted_callback_hook(_filter, name) # :nodoc:
272
+ return super unless %i(enqueue processing).include?(name.to_sym)
273
+ callbacks = public_send("_#{name}_callbacks")
274
+
275
+ if !self.class.skip_after_callbacks_if_terminated && callbacks.any? { |c| c.kind == :after }
276
+ ActiveSupport::Deprecation.warn(<<~EOM)
277
+ In Rails 7.0, `after_enqueue`/`after_work` callbacks no longer run if `before_enqueue`/`before_work` respectively halts with `throw :abort`.
278
+ To enable this behavior, uncomment the `config.active_job.skip_after_callbacks_if_terminated` config
279
+ in the new 6.1 framework defaults initializer.
280
+ EOM
281
+ end
282
+
283
+ super
284
+ end
285
+ end
286
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Postburner
2
4
  # Must implement a perform method, if an exception is raised the job
3
5
  # doesn't complete.
@@ -14,6 +16,7 @@ module Postburner
14
16
  #
15
17
  class Job < ApplicationRecord
16
18
  include Backburner::Queue
19
+ include Callbacks
17
20
 
18
21
  LOG_LEVELS = [
19
22
  :debug,
@@ -48,7 +51,9 @@ module Postburner
48
51
 
49
52
  @_insert_options = options
50
53
 
51
- self.save!
54
+ run_callbacks :enqueue do
55
+ self.save!
56
+ end
52
57
  end
53
58
 
54
59
  def requeue!(options={})
@@ -73,77 +78,85 @@ module Postburner
73
78
  [Postburner::Job] [#{id}] Not Found.
74
79
  MSG
75
80
  end
76
- job&.perform!(job.args)
81
+ #job&.perform!(job.args)
82
+ job.perform!(job.args)
77
83
  end
78
84
 
79
85
  def perform!(args={})
80
- self.attempting
81
-
82
- self.update_columns(
83
- attempting_at: self.attempting_at,
84
- attempts: self.attempts,
85
- attempt_count: self.attempts.length,
86
- lag: self.lag,
87
- processing_at: Time.zone.now,
88
- )
89
-
90
- begin
91
- if self.queued_at.nil?
92
- self.log! "Not Queued", level: :error
93
- return
94
- end
95
-
96
- if self.queued_at > Time.zone.now
97
- self.log! "Future Queued", level: :error
98
- return
99
- end
100
-
101
- if self.processed_at.present?
102
- self.log! "Already Processed", level: :error
103
- self.delete!
104
- return
105
- end
106
-
107
- if self.removed_at.present?
108
- self.log! "Removed", level: :error
109
- return
110
- end
111
-
112
- if self.run_at && self.run_at > Time.zone.now
113
- response = self.insert! delay: self.run_at - Time.zone.now
114
- self.log! "PREMATURE; RE-INSERTED: #{response}"
115
- return
116
- end
117
-
118
- self.log!("START (bkid #{self.bkid})")
86
+ run_callbacks :attempt do
87
+ self.attempting
88
+
89
+ self.update_columns(
90
+ attempting_at: self.attempting_at,
91
+ attempts: self.attempts,
92
+ attempt_count: self.attempts.length,
93
+ lag: self.lag,
94
+ processing_at: Time.zone.now,
95
+ )
119
96
 
120
97
  begin
121
- self.perform(args)
98
+ if self.queued_at.nil?
99
+ self.log! "Not Queued", level: :error
100
+ return
101
+ end
102
+
103
+ if self.queued_at > Time.zone.now
104
+ self.log! "Future Queued", level: :error
105
+ return
106
+ end
107
+
108
+ if self.processed_at.present?
109
+ self.log! "Already Processed", level: :error
110
+ self.delete!
111
+ return
112
+ end
113
+
114
+ if self.removed_at.present?
115
+ self.log! "Removed", level: :error
116
+ return
117
+ end
118
+
119
+ if self.run_at && self.run_at > Time.zone.now
120
+ response = self.insert! delay: self.run_at - Time.zone.now
121
+ self.log! "PREMATURE; RE-INSERTED: #{response}"
122
+ return
123
+ end
124
+
125
+ self.log!("START (bkid #{self.bkid})")
126
+
127
+ run_callbacks :processing do
128
+ begin
129
+ self.perform(args)
130
+ rescue Exception => exception
131
+ self.persist_metadata!
132
+ self.log! '[Postburner] Exception raised during perform prevented completion.'
133
+ raise exception
134
+ end
135
+ end
136
+
137
+ self.log!("DONE (bkid #{self.bkid})")
138
+
139
+ begin
140
+ now = Time.zone.now
141
+ _duration = (now - self.processing_at) * 1000 rescue nil
142
+
143
+ run_callbacks :processed do
144
+ persist_metadata!(
145
+ processed_at: now,
146
+ duration: _duration,
147
+ )
148
+ end
149
+ rescue Exception => e
150
+ self.log_exception!(e)
151
+ self.log! '[Postburner] Could not set data after processing.'
152
+ # TODO README doesn't retry if Postburner is to blame
153
+ end
154
+
122
155
  rescue Exception => exception
123
- self.persist_metadata!
124
- self.log! '[Postburner] Exception raised during perform prevented completion.'
156
+ self.log_exception!(exception)
125
157
  raise exception
126
158
  end
127
-
128
- self.log!("DONE (bkid #{self.bkid})")
129
-
130
- begin
131
- now = Time.zone.now
132
- _duration = (now - self.processing_at) * 1000 rescue nil
133
- persist_metadata!(
134
- processed_at: now,
135
- duration: _duration,
136
- )
137
- rescue Exception => e
138
- self.log_exception!(e)
139
- self.log! '[Postburner] Could not set data after processing.'
140
- # TODO README doesn't retry if Postburner is to blame
141
- end
142
-
143
- rescue Exception => exception
144
- self.log_exception!(exception)
145
- raise exception
146
- end
159
+ end # run_callbacks :attempt
147
160
 
148
161
  end
149
162
 
@@ -1,3 +1,3 @@
1
1
  module Postburner
2
- VERSION = '0.6.5'
2
+ VERSION = '0.7.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: postburner
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.5
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Smith
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-21 00:00:00.000000000 Z
11
+ date: 2022-10-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -79,6 +79,7 @@ files:
79
79
  - Rakefile
80
80
  - app/assets/config/postburner_manifest.js
81
81
  - app/assets/stylesheets/postburner/application.css
82
+ - app/concerns/postburner/callbacks.rb
82
83
  - app/controllers/postburner/application_controller.rb
83
84
  - app/controllers/postburner/jobs_controller.rb
84
85
  - app/controllers/postburner/static_controller.rb
@@ -122,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
122
123
  - !ruby/object:Gem::Version
123
124
  version: '0'
124
125
  requirements: []
125
- rubygems_version: 3.1.6
126
+ rubygems_version: 3.3.7
126
127
  signing_key:
127
128
  specification_version: 4
128
129
  summary: Postgres backed beanstalkd queue via backburner