quebert 2.0.3 → 2.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 063bc22b230d2549c427562deb220554b1b6b931
4
- data.tar.gz: 0f4db324c52f319abe1229112f0ea4219172f47d
3
+ metadata.gz: 13a07e8336155e0c777ed1295201b2d7d23e9bee
4
+ data.tar.gz: 6e3929be1a44ee006809f3b24a1ef605aed7605d
5
5
  SHA512:
6
- metadata.gz: b001d8710708db59714b9722c75cf0919ab1520a369ff2c3c246645450a02ba0e47235be186f805984d46693c7766b654bc579e73f8bca176c7176e37935e2ad
7
- data.tar.gz: 76331a2a7b8600945285f562802b80f68954909d0b0a62f8b5ae857c8c5d782d5c364e74438f38ef542a91588ea2f2ba8dc7d46fa6abd107c59c07c46f4b5d28
6
+ metadata.gz: f56a3426063aa8353e6e52f8c61bb7a76e73bdbced8df6a919872979fb33102ce0e9cbd536046ccc30fa21d1e57b38b994d275abcfd560366d6b451cf7507257
7
+ data.tar.gz: 2f464763bb13a6eefd45ebc46f8a2dbc3a326dff7e5968960319f37a52bcf10c3d5d5c3abf64a55d6ca009a30b12d705b65367f47d0e0ab9572969aeb5651427
data/.gitignore CHANGED
@@ -1,6 +1,9 @@
1
1
  ## MAC OS
2
2
  .DS_Store
3
3
 
4
+ ## RUBY
5
+ .bundle
6
+
4
7
  ## TEXTMATE
5
8
  *.tmproj
6
9
  tmtags
@@ -19,4 +22,4 @@ rdoc
19
22
  pkg
20
23
  Gemfile.lock
21
24
 
22
- ## PROJECT::SPECIFIC
25
+ ## PROJECT::SPECIFIC
data/.rbenv-version CHANGED
@@ -1 +1 @@
1
- 1.9.3-p484
1
+ 2.1.2
data/README.md CHANGED
@@ -18,6 +18,7 @@ Quebert is a serious project. Its used in a production environment at Poll Every
18
18
  * Rails/ActiveRecord integration similar to async_observer
19
19
  * Pluggable exception handling (for Hoptoad integration)
20
20
  * Run workers with pid, log, and config files. These do not daemonize (do it yourself punk!)
21
+ * Provide custom hooks to be called before, after & around jobs are run
21
22
 
22
23
  Some features that are currently missing that I will soon add include:
23
24
 
@@ -53,6 +54,25 @@ Then perform the jobs!
53
54
  Quebert.backend.reserve.perform # => 6
54
55
  Quebert.backend.reserve.perform # => 15
55
56
 
57
+ ## Before/After/Around Hooks
58
+
59
+ Quebert has support for providing custom hooks to be called before, after & around your jobs are being run.
60
+ A common example is making sure that any active ActiveRecord database connections are put back on the connection pool after a job is done:
61
+
62
+ Quebert.config.after_job do
63
+ ActiveRecord::Base.clear_active_connections!
64
+ end
65
+
66
+ Quebert.config.before_job do |job|
67
+ # all hooks take an optional job argument
68
+ # in case you want to do something with that job
69
+ end
70
+
71
+ Quebert.config.around_job do |job|
72
+ # this hook gets called twice
73
+ # once before & once after a job is performed
74
+ end
75
+
56
76
  ## Async Sender
57
77
 
58
78
  Take any ol' class and include the Quebert::AsyncSender.
@@ -29,13 +29,60 @@ module Quebert
29
29
  end
30
30
  self
31
31
  end
32
-
32
+
33
33
  def worker
34
34
  @worker ||= Struct.new(:exception_handler).new
35
35
  end
36
-
36
+
37
37
  def self.from_hash(hash)
38
38
  new.from_hash(hash) # Config this puppy up from a config hash
39
39
  end
40
+
41
+ def before_job(job = nil, &block)
42
+ if job
43
+ before_hooks.each do |h|
44
+ h.call(job)
45
+ end
46
+ else
47
+ before_hooks << block if block
48
+ end
49
+ self
50
+ end
51
+
52
+ def after_job(job = nil, &block)
53
+ if job
54
+ after_hooks.each do |h|
55
+ h.call(job)
56
+ end
57
+ else
58
+ after_hooks << block if block
59
+ end
60
+ self
61
+ end
62
+
63
+ def around_job(job = nil, &block)
64
+ if job
65
+ around_hooks.each do |h|
66
+ h.call(job)
67
+ end
68
+ else
69
+ around_hooks << block if block
70
+ end
71
+ self
72
+ end
73
+
74
+ private
75
+
76
+ def before_hooks
77
+ @before_hooks ||= []
78
+ end
79
+
80
+ def after_hooks
81
+ @after_hooks ||= []
82
+ end
83
+
84
+ def around_hooks
85
+ @around_hooks ||= []
86
+ end
40
87
  end
41
88
  end
@@ -14,86 +14,79 @@ module Quebert
14
14
 
15
15
  def initialize(beanstalk_job, queue)
16
16
  @beanstalk_job, @queue = beanstalk_job, queue
17
-
18
- begin
19
- @job = Job.from_json(beanstalk_job.body)
20
- rescue Job::Delete
21
- beanstalk_job.delete
22
- log "Deleted on initialization", :error
23
- rescue Job::Release
24
- beanstalk_job.release @job.priority, @job.delay
25
- log "Released on initialization with priority: #{@job.priority} and delay: #{@job.delay}", :error
26
- rescue Job::Bury
27
- beanstalk_job.bury
28
- log "Buried on initialization", :error
29
- rescue Exception => e
30
- beanstalk_job.bury
31
- log "Exception caught on initialization. #{e.inspect}", :error
32
- raise e
33
- end
17
+ @job = Job.from_json(beanstalk_job.body)
18
+ rescue Job::Delete
19
+ beanstalk_job.delete
20
+ log "Deleted on initialization", :error
21
+ rescue Job::Release
22
+ beanstalk_job.release @job.priority, @job.delay
23
+ log "Released on initialization with priority: #{@job.priority} and delay: #{@job.delay}", :error
24
+ rescue Job::Bury
25
+ beanstalk_job.bury
26
+ log "Buried on initialization", :error
27
+ rescue Exception => e
28
+ beanstalk_job.bury
29
+ log "Exception caught on initialization. #{e.inspect}", :error
30
+ raise
34
31
  end
35
-
36
- def perform
37
- begin
38
- log "Performing with args #{job.args.inspect}"
39
- log "Beanstalk Job Stats: #{beanstalk_job.stats.inspect}"
40
32
 
41
- result = false
42
- time = Benchmark.realtime do
43
- result = job.perform!
44
- beanstalk_job.delete
45
- end
33
+ def perform
34
+ log "Performing with args #{job.args.inspect}"
35
+ log "Beanstalk Job Stats: #{beanstalk_job.stats.inspect}"
46
36
 
47
- log "Completed in #{(time*1000*1000).to_i/1000.to_f} ms\n"
48
- result
49
- rescue Job::Delete
50
- log "Deleting job", :error
37
+ result = false
38
+ time = Benchmark.realtime do
39
+ result = job.perform!
51
40
  beanstalk_job.delete
52
- log "Job deleted", :error
53
- rescue Job::Release
54
- log "Releasing with priority: #{@job.priority} and delay: #{@job.delay}", :error
55
- beanstalk_job.release :pri => @job.priority, :delay => @job.delay
56
- log "Job released", :error
57
- rescue Job::Bury
58
- log "Burrying job", :error
59
- beanstalk_job.bury
60
- log "Job burried", :error
61
- rescue Job::Timeout => e
62
- log "Job timed out!", :error
63
- retry_with_delay
64
- raise e
65
- rescue Job::Retry => e
66
- # The difference between the Retry and Timeout class is that
67
- # Retry does not log an exception where as Timeout does
68
- log "Manually retrying with delay"
69
- retry_with_delay
70
- rescue Exception => e
71
- log "Exception caught on perform. Burying job. #{e.inspect} #{e.backtrace.join("\n")}", :error
72
- beanstalk_job.bury
73
- log "Job buried", :error
74
- raise e
75
41
  end
42
+
43
+ log "Completed in #{(time*1000*1000).to_i/1000.to_f} ms\n"
44
+ result
45
+ rescue Job::Delete
46
+ log "Deleting job", :error
47
+ beanstalk_job.delete
48
+ log "Job deleted", :error
49
+ rescue Job::Release
50
+ log "Releasing with priority: #{@job.priority} and delay: #{@job.delay}", :error
51
+ beanstalk_job.release :pri => @job.priority, :delay => @job.delay
52
+ log "Job released", :error
53
+ rescue Job::Bury
54
+ log "Burrying job", :error
55
+ beanstalk_job.bury
56
+ log "Job burried", :error
57
+ rescue Job::Timeout => e
58
+ log "Job timed out. Retrying with delay. #{e.inspect} #{e.backtrace.join("\n")}", :error
59
+ retry_with_delay
60
+ raise
61
+ rescue Job::Retry
62
+ # The difference between the Retry and Timeout class is that
63
+ # Retry does not log an exception where as Timeout does
64
+ log "Manually retrying with delay"
65
+ retry_with_delay
66
+ rescue Exception => e
67
+ log "Exception caught on perform. Burying job. #{e.inspect} #{e.backtrace.join("\n")}", :error
68
+ beanstalk_job.bury
69
+ log "Job buried", :error
70
+ raise
76
71
  end
77
72
 
78
73
  protected
79
74
  def retry_with_delay
80
- begin
81
- delay = TIMEOUT_RETRY_DELAY_SEED + TIMEOUT_RETRY_GROWTH_RATE**beanstalk_job.stats["releases"].to_i
75
+ delay = TIMEOUT_RETRY_DELAY_SEED + TIMEOUT_RETRY_GROWTH_RATE**beanstalk_job.stats["releases"].to_i
82
76
 
83
- if delay > MAX_TIMEOUT_RETRY_DELAY
84
- log "Max retry delay exceeded. Burrying job"
85
- beanstalk_job.bury
86
- log "Job burried"
87
- else
88
- log "TTR exceeded. Releasing with priority: #{@job.priority} and delay: #{delay}"
89
- beanstalk_job.release :pri => @job.priority, :delay => delay
90
- log "Job released"
91
- end
92
- rescue ::Beaneater::NotFoundError
93
- log "Job ran longer than allowed. Beanstalk already deleted it!!!!", :error
94
- # Sometimes the timer doesn't behave correctly and this job actually runs longer than
95
- # allowed. At that point the beanstalk job no longer exists anymore. Lets let it go and don't blow up.
77
+ if delay > MAX_TIMEOUT_RETRY_DELAY
78
+ log "Max retry delay exceeded. Burrying job"
79
+ beanstalk_job.bury
80
+ log "Job burried"
81
+ else
82
+ log "TTR exceeded. Releasing with priority: #{@job.priority} and delay: #{delay}"
83
+ beanstalk_job.release :pri => @job.priority, :delay => delay
84
+ log "Job released"
96
85
  end
86
+ rescue ::Beaneater::NotFoundError
87
+ log "Job ran longer than allowed. Beanstalk already deleted it!!!!", :error
88
+ # Sometimes the timer doesn't behave correctly and this job actually runs longer than
89
+ # allowed. At that point the beanstalk job no longer exists anymore. Lets let it go and don't blow up.
97
90
  end
98
91
 
99
92
  def log(message, level=:info)
data/lib/quebert/job.rb CHANGED
@@ -51,10 +51,18 @@ module Quebert
51
51
 
52
52
  # Runs the perform method that somebody else should be implementing
53
53
  def perform!
54
+ Quebert.config.before_job(self)
55
+ Quebert.config.around_job(self)
56
+
54
57
  # Honor the timeout and kill the job in ruby-space. Beanstalk
55
58
  # should be cleaning up this job and returning it to the queue
56
59
  # as well.
57
- ::Timeout.timeout(@ttr, Job::Timeout){ perform(*args) }
60
+ val = ::Timeout.timeout(@ttr, Job::Timeout){ perform(*args) }
61
+
62
+ Quebert.config.around_job(self)
63
+ Quebert.config.after_job(self)
64
+
65
+ val
58
66
  end
59
67
 
60
68
  # Accepts arguments that override the job options and enqueu this stuff.
@@ -1,3 +1,3 @@
1
1
  module Quebert
2
- VERSION = "2.0.3"
2
+ VERSION = "2.0.4"
3
3
  end
data/spec/job_spec.rb CHANGED
@@ -153,4 +153,35 @@ describe Quebert::Job do
153
153
  }.should raise_exception(Quebert::Job::Timeout)
154
154
  end
155
155
  end
156
+
157
+ context "before, after & around hooks" do
158
+ it "should call each type of hook as expected" do
159
+ before_jobs = []
160
+ after_jobs = []
161
+ around_jobs = []
162
+
163
+ jobs = (1..10).map do |i|
164
+ Adder.new(i, i)
165
+ end
166
+
167
+ Quebert.config.before_job do |job|
168
+ before_jobs << job
169
+ end
170
+
171
+ Quebert.config.after_job do |job|
172
+ after_jobs << job
173
+ end
174
+
175
+ Quebert.config.around_job do |job|
176
+ around_jobs << job
177
+ end
178
+
179
+ jobs.each(&:perform!)
180
+
181
+ before_jobs.should eql jobs
182
+ after_jobs.should eql jobs
183
+ # around_job hooks are called twice per job (before & after its performed)
184
+ around_jobs.should eql jobs.zip(jobs).flatten
185
+ end
186
+ end
156
187
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quebert
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brad Gessler
@@ -10,34 +10,34 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2014-07-18 00:00:00.000000000 Z
13
+ date: 2014-10-28 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: json
17
17
  requirement: !ruby/object:Gem::Requirement
18
18
  requirements:
19
- - - '>='
19
+ - - ">="
20
20
  - !ruby/object:Gem::Version
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
- - - '>='
26
+ - - ">="
27
27
  - !ruby/object:Gem::Version
28
28
  version: '0'
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: beaneater
31
31
  requirement: !ruby/object:Gem::Requirement
32
32
  requirements:
33
- - - '>='
33
+ - - ">="
34
34
  - !ruby/object:Gem::Version
35
35
  version: '0'
36
36
  type: :runtime
37
37
  prerelease: false
38
38
  version_requirements: !ruby/object:Gem::Requirement
39
39
  requirements:
40
- - - '>='
40
+ - - ">="
41
41
  - !ruby/object:Gem::Version
42
42
  version: '0'
43
43
  - !ruby/object:Gem::Dependency
@@ -62,11 +62,11 @@ executables:
62
62
  extensions: []
63
63
  extra_rdoc_files: []
64
64
  files:
65
- - .document
66
- - .gitignore
67
- - .rbenv-version
68
- - .rspec
69
- - .travis.yml
65
+ - ".document"
66
+ - ".gitignore"
67
+ - ".rbenv-version"
68
+ - ".rspec"
69
+ - ".travis.yml"
70
70
  - Gemfile
71
71
  - Guardfile
72
72
  - LICENSE.md
@@ -121,17 +121,17 @@ require_paths:
121
121
  - lib
122
122
  required_ruby_version: !ruby/object:Gem::Requirement
123
123
  requirements:
124
- - - '>='
124
+ - - ">="
125
125
  - !ruby/object:Gem::Version
126
126
  version: '0'
127
127
  required_rubygems_version: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - '>='
129
+ - - ">="
130
130
  - !ruby/object:Gem::Version
131
131
  version: '0'
132
132
  requirements: []
133
133
  rubyforge_project: quebert
134
- rubygems_version: 2.2.0
134
+ rubygems_version: 2.2.2
135
135
  signing_key:
136
136
  specification_version: 4
137
137
  summary: A worker queue framework built around beanstalkd