sucker_punch 1.6.0 → 2.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +15 -3
- data/CHANGES.md +30 -0
- data/README.md +99 -96
- data/Rakefile +9 -6
- data/bin/load +23 -0
- data/bin/shutdown +20 -0
- data/lib/sucker_punch/async_syntax.rb +18 -0
- data/lib/sucker_punch/core_ext.rb +50 -8
- data/lib/sucker_punch/counter.rb +72 -0
- data/lib/sucker_punch/job.rb +53 -10
- data/lib/sucker_punch/queue.rb +159 -34
- data/lib/sucker_punch/testing/inline.rb +33 -7
- data/lib/sucker_punch/version.rb +1 -1
- data/lib/sucker_punch.rb +46 -9
- data/sucker_punch.gemspec +5 -3
- data/test/sucker_punch/async_syntax_test.rb +33 -0
- data/test/sucker_punch/counter_test.rb +83 -0
- data/test/sucker_punch/job_test.rb +157 -0
- data/test/sucker_punch/queue_test.rb +99 -0
- data/test/sucker_punch_test.rb +52 -0
- data/test/test_helper.rb +8 -0
- metadata +36 -29
- data/spec/spec_helper.rb +0 -9
- data/spec/sucker_punch/core_ext_spec.rb +0 -13
- data/spec/sucker_punch/job_spec.rb +0 -42
- data/spec/sucker_punch/queue_spec.rb +0 -69
- data/spec/sucker_punch/testing/inline_spec.rb +0 -18
- data/spec/sucker_punch_spec.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fa1e2aa3c637a849298159655805260a18ce9315
|
4
|
+
data.tar.gz: 2a138d958c61e7c1e014ff7e9d682e8c9a5f78e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 03d99e04ebd2fc6aaa07e91242673411727a5cbc50d350d3b83a9a2b28fb81ec90bc26eb7c4d83b3f840da0881928b784b3c07e077205ad1d41333d627dac5ed
|
7
|
+
data.tar.gz: 588214f4b4d233352bf06ae84ad6b2948e575e2b089c7b7fe9b39d9dceecccc4b9f189fd24a6945119b4ffb2cdbd2962529ba43779b213aef65b297f60790fca
|
data/.travis.yml
CHANGED
@@ -1,12 +1,24 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
- 1.9.3
|
4
|
-
- jruby-19mode
|
5
3
|
- rbx-2
|
6
4
|
- 2.0.0
|
7
5
|
- 2.1.0
|
6
|
+
- 2.2.0
|
7
|
+
- 2.3.0
|
8
8
|
- ruby-head
|
9
|
+
- jruby-9.0.1.0
|
10
|
+
- jruby-9.0.3.0
|
11
|
+
- jruby-9.0.4.0
|
12
|
+
- jruby-head
|
13
|
+
|
14
|
+
jdk:
|
15
|
+
- oraclejdk8
|
16
|
+
|
9
17
|
matrix:
|
10
18
|
allow_failures:
|
11
|
-
- rvm: jruby-19mode
|
12
19
|
- rvm: rbx-2
|
20
|
+
- rvm: jruby-head
|
21
|
+
|
22
|
+
before_script:
|
23
|
+
- "echo $JAVA_OPTS"
|
24
|
+
- "export JAVA_OPTS=-Xmx1024m"
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,33 @@
|
|
1
|
+
2.0.0.beta1
|
2
|
+
-------
|
3
|
+
|
4
|
+
- Refactor internals to use `concurrent-ruby`
|
5
|
+
- Yield more exception details to handler. The new syntax allows you to setup a
|
6
|
+
global exception with the following syntax:
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
# ex => The caught exception object
|
10
|
+
# klass => The job class
|
11
|
+
# args => An array of the args passed to the job
|
12
|
+
|
13
|
+
SuckerPunch.exception_handler = -> (ex, klass, args) { ExceptionNotifier.notify_exception(ex) }
|
14
|
+
```
|
15
|
+
|
16
|
+
- Invoke asynchronous job via `perform_async` and `perform_in` class method (*backwards
|
17
|
+
incompatible change*):
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
LogJob.perform_async("login")
|
21
|
+
LogJob.perform_in(60, "login") # `perform` will be executed 60 sec. later
|
22
|
+
```
|
23
|
+
|
24
|
+
- Drop support for Ruby `< 2.0`
|
25
|
+
- Allow shutdown timeout to be set:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
SuckerPunch.shutdown_timeout = 15 # time in seconds
|
29
|
+
```
|
30
|
+
|
1
31
|
1.6.0
|
2
32
|
--------
|
3
33
|
|
data/README.md
CHANGED
@@ -1,20 +1,29 @@
|
|
1
|
+
# Notice: This README is for the `master` branch (`v2 beta`), not the latest stable branch
|
2
|
+
|
1
3
|
# Sucker Punch
|
2
4
|
|
3
5
|
[![Build Status](https://travis-ci.org/brandonhilkert/sucker_punch.png?branch=master)](https://travis-ci.org/brandonhilkert/sucker_punch)
|
4
6
|
[![Code Climate](https://codeclimate.com/github/brandonhilkert/sucker_punch.png)](https://codeclimate.com/github/brandonhilkert/sucker_punch)
|
5
7
|
|
6
|
-
Sucker Punch is a single-process Ruby asynchronous processing library.
|
8
|
+
Sucker Punch is a single-process Ruby asynchronous processing library.
|
9
|
+
This reduces costs
|
10
|
+
of hosting on a service like Heroku along with the memory footprint of
|
11
|
+
having to maintain additional jobs if hosting on a dedicated server.
|
12
|
+
All queues can run within a single application (eg. Rails, Sinatra, etc.) process.
|
7
13
|
|
8
|
-
Sucker Punch is perfect for asynchronous processes like emailing, data
|
14
|
+
Sucker Punch is perfect for asynchronous processes like emailing, data
|
15
|
+
crunching, or social platform manipulation. No reason to hold up a
|
16
|
+
user when you can do these things in the background within the same
|
17
|
+
process as your web application...
|
9
18
|
|
10
|
-
Sucker Punch is built on top of [
|
11
|
-
|
19
|
+
Sucker Punch is built on top of [concurrent-ruby]
|
20
|
+
(https://github.com/ruby-concurrency/concurrent-ruby). Each job is setup as
|
12
21
|
a pool, which equates to its own queue with individual workers working against
|
13
22
|
the jobs. Unlike most other background processing libraries, Sucker
|
14
23
|
Punch's jobs are stored in memory. The benefit to this is there is no
|
15
|
-
additional infrastructure requirement (ie. database, redis, etc.).
|
16
|
-
|
17
|
-
|
24
|
+
additional infrastructure requirement (ie. database, redis, etc.). However,
|
25
|
+
if the web processes are restarted with jobs remaining in the queue,
|
26
|
+
they will be lost. For this reason, Sucker Punch is generally
|
18
27
|
recommended for jobs that are fast and non-mission critical (ie. logs, emails,
|
19
28
|
etc.).
|
20
29
|
|
@@ -22,7 +31,7 @@ etc.).
|
|
22
31
|
|
23
32
|
Add this line to your application's Gemfile:
|
24
33
|
|
25
|
-
gem 'sucker_punch', '~>
|
34
|
+
gem 'sucker_punch', '~> 2.0'
|
26
35
|
|
27
36
|
And then execute:
|
28
37
|
|
@@ -37,7 +46,7 @@ Or install it yourself as:
|
|
37
46
|
Each job acts as its own queue and should be a separate Ruby class that:
|
38
47
|
|
39
48
|
* includes `SuckerPunch::Job`
|
40
|
-
* defines the instance method
|
49
|
+
* defines the `perform` instance method that includes the code the job will run when enqueued
|
41
50
|
|
42
51
|
|
43
52
|
```Ruby
|
@@ -52,90 +61,94 @@ class LogJob
|
|
52
61
|
end
|
53
62
|
```
|
54
63
|
|
55
|
-
Synchronous
|
64
|
+
#### Synchronous
|
56
65
|
|
57
66
|
```Ruby
|
58
67
|
LogJob.new.perform("login")
|
59
68
|
```
|
60
69
|
|
61
|
-
Asynchronous
|
70
|
+
#### Asynchronous
|
62
71
|
|
63
72
|
```Ruby
|
64
|
-
LogJob.
|
73
|
+
LogJob.perform_async("login")
|
65
74
|
```
|
66
75
|
|
67
|
-
|
76
|
+
#### Configure the # of the Workers
|
68
77
|
|
69
|
-
|
70
|
-
|
78
|
+
The default number of workers (threads) running against your job is `2`. If
|
79
|
+
you'd like to configure this manually, the number of workers can be
|
80
|
+
set on the job using the `workers` class method:
|
71
81
|
|
72
|
-
|
82
|
+
```Ruby
|
83
|
+
class LogJob
|
73
84
|
include SuckerPunch::Job
|
85
|
+
workers 4
|
74
86
|
|
75
|
-
def perform(
|
76
|
-
|
77
|
-
user = User.find(user_id)
|
78
|
-
user.update_attributes(is_awesome: true)
|
79
|
-
end
|
87
|
+
def perform(event)
|
88
|
+
Log.new(event).track
|
80
89
|
end
|
81
90
|
end
|
82
91
|
```
|
83
92
|
|
84
|
-
|
93
|
+
#### Executing Jobs in the Future
|
85
94
|
|
86
|
-
|
87
|
-
|
95
|
+
Many background processing libraries have methods to perform operations after a
|
96
|
+
certain amount of time and Sucker Punch is no different. Use the `perform_in`
|
97
|
+
with an argument of the number of seconds in the future you would like the job
|
98
|
+
to job to run.
|
99
|
+
|
100
|
+
``` ruby
|
101
|
+
class DataJob
|
88
102
|
include SuckerPunch::Job
|
89
103
|
|
90
|
-
def perform(
|
91
|
-
|
92
|
-
user = User.find(user_id)
|
93
|
-
user.update_attributes(is_awesome: true)
|
94
|
-
LogJob.new.async.perform("User #{user.id} became awesome!")
|
95
|
-
end
|
104
|
+
def perform(data)
|
105
|
+
puts data
|
96
106
|
end
|
97
107
|
end
|
108
|
+
|
109
|
+
DataJob.perform_async("asdf") # immediately perform asynchronously
|
110
|
+
DataJob.perform_in(60, "asdf") # `perform` will be excuted 60 sec. later
|
98
111
|
```
|
99
112
|
|
100
|
-
|
113
|
+
#### `ActiveRecord` Connection Pool Connections
|
114
|
+
|
115
|
+
Jobs interacting with `ActiveRecord` should take special precaution not to
|
116
|
+
exhaust connections in the pool. This can be done
|
117
|
+
with `ActiveRecord::Base.connection_pool.with_connection`, which ensures
|
118
|
+
the connection is returned back to the pool when completed.
|
101
119
|
|
102
120
|
```Ruby
|
103
|
-
|
121
|
+
# app/jobs/awesome_job.rb
|
122
|
+
|
123
|
+
class AwesomeJob
|
104
124
|
include SuckerPunch::Job
|
105
|
-
workers 4
|
106
125
|
|
107
|
-
def perform(
|
108
|
-
|
126
|
+
def perform(user_id)
|
127
|
+
ActiveRecord::Base.connection_pool.with_connection do
|
128
|
+
user = User.find(user_id)
|
129
|
+
user.update(is_awesome: true)
|
130
|
+
end
|
109
131
|
end
|
110
132
|
end
|
111
133
|
```
|
112
134
|
|
113
|
-
|
114
|
-
|
115
|
-
## Perform In
|
116
|
-
|
117
|
-
Many background processing libraries have methods to perform operations after a
|
118
|
-
certain amount of time. Fortunately, timers are built-in to Celluloid, so you
|
119
|
-
can take advantage of them with the `later` method:
|
135
|
+
We can create a job from within another job:
|
120
136
|
|
121
|
-
```
|
122
|
-
class
|
137
|
+
```Ruby
|
138
|
+
class AwesomeJob
|
123
139
|
include SuckerPunch::Job
|
124
140
|
|
125
|
-
def perform(
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
141
|
+
def perform(user_id)
|
142
|
+
ActiveRecord::Base.connection_pool.with_connection do
|
143
|
+
user = User.find(user_id)
|
144
|
+
user.update_attributes(is_awesome: true)
|
145
|
+
LogJob.perform_async("User #{user.id} became awesome!")
|
146
|
+
end
|
131
147
|
end
|
132
148
|
end
|
133
|
-
|
134
|
-
Job.new.async.perform("asdf")
|
135
|
-
Job.new.async.later(60, "asdf") # `perform` will be excuted 60 sec. later
|
136
149
|
```
|
137
150
|
|
138
|
-
|
151
|
+
#### Logger
|
139
152
|
|
140
153
|
```Ruby
|
141
154
|
SuckerPunch.logger = Logger.new('sucker_punch.log')
|
@@ -145,43 +158,57 @@ SuckerPunch.logger # => #<Logger:0x007fa1f28b83f0>
|
|
145
158
|
_Note: If Sucker Punch is being used within a Rails application, Sucker Punch's logger
|
146
159
|
is set to Rails.logger by default._
|
147
160
|
|
148
|
-
|
161
|
+
#### Exceptions
|
149
162
|
|
150
163
|
You can customize how to handle uncaught exceptions that are raised by your jobs.
|
151
164
|
|
152
|
-
For example, using Rails and the ExceptionNotification gem,
|
165
|
+
For example, using Rails and the ExceptionNotification gem,
|
166
|
+
add a new initializer `config/initializers/sucker_punch.rb`:
|
153
167
|
|
154
168
|
```Ruby
|
155
|
-
|
169
|
+
# ex => The caught exception object
|
170
|
+
# klass => The job class
|
171
|
+
# args => An array of the args passed to the job
|
172
|
+
|
173
|
+
SuckerPunch.exception_handler = -> (ex, klass, args) { ExceptionNotifier.notify_exception(ex) }
|
156
174
|
```
|
157
175
|
|
158
176
|
Or, using Airbrake:
|
159
177
|
|
160
178
|
```Ruby
|
161
|
-
SuckerPunch.exception_handler
|
179
|
+
SuckerPunch.exception_handler = -> (ex, klass, args) { Airbrake.notify(ex) }
|
162
180
|
```
|
163
181
|
|
164
|
-
|
182
|
+
#### Shutdown Timeout
|
165
183
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
184
|
+
Sucker Punch goes through a series of checks to attempt to shut down the queues
|
185
|
+
and their threads. A "shutdown" command is issued to the queues, which gives
|
186
|
+
them notice but allows them to attempt to finish all remaining jobs.
|
187
|
+
Subsequently enqueued jobs are discarded at this time.
|
188
|
+
|
189
|
+
The default `shutdown_timeout` (the # of seconds to wait before forcefully
|
190
|
+
killing the threads) is 8 sec. This is to allow applications hosted on Heroku
|
191
|
+
to attempt to shutdown prior to the 10 sec. they give an application to
|
192
|
+
shutdown with some buffer.
|
193
|
+
|
194
|
+
To configure something other than the default 8 sec.:
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
SuckerPunch.shutdown_timeout = 15 # # of sec. to wait before killing threads
|
173
198
|
```
|
174
199
|
|
175
|
-
|
200
|
+
#### Timeouts
|
176
201
|
|
177
|
-
Using `Timeout` causes persistent connections to
|
178
|
-
|
202
|
+
Using `Timeout` causes persistent connections to
|
203
|
+
[randomly get corrupted](http://www.mikeperham.com/2015/05/08/timeout-rubys-most-dangerous-api).
|
204
|
+
Do not use timeouts as control flow, use built-in connection timeouts.
|
179
205
|
If you decide to use Timeout, only use it as last resort to know something went very wrong and
|
180
206
|
ideally restart the worker process after every timeout.
|
181
207
|
|
182
208
|
## Testing
|
183
209
|
|
184
|
-
Requiring this library causes your jobs to run everything inline.
|
210
|
+
Requiring this library causes your jobs to run everything inline.
|
211
|
+
So a call to the following will actually be SYNCHRONOUS:
|
185
212
|
|
186
213
|
```Ruby
|
187
214
|
# spec/spec_helper.rb
|
@@ -189,7 +216,7 @@ require 'sucker_punch/testing/inline'
|
|
189
216
|
```
|
190
217
|
|
191
218
|
```Ruby
|
192
|
-
|
219
|
+
LogJob.perform_async("login") # => Will be synchronous and block until job is finished
|
193
220
|
```
|
194
221
|
|
195
222
|
## Rails
|
@@ -230,28 +257,10 @@ end
|
|
230
257
|
### Initializers for forking servers (Unicorn, Passenger, etc.)
|
231
258
|
|
232
259
|
Previously, Sucker Punch required an initializer and that posed problems for
|
233
|
-
|
260
|
+
servers that fork (ie. Unicorn and Passenger). Version 1 was rewritten to
|
234
261
|
not require any special code to be executed after forking occurs. Please remove
|
235
262
|
if you're using version `>= 1.0.0`
|
236
263
|
|
237
|
-
### Class naming
|
238
|
-
|
239
|
-
Job classes are ultimately Celluloid Actor classes. As a result, class names
|
240
|
-
are susceptible to being clobbered by Celluloid's internal classes. To ensure
|
241
|
-
the intended application class is loaded, preface classes with `::`, or use
|
242
|
-
names like `NotificationsMailer` or `UserMailer`. Example:
|
243
|
-
|
244
|
-
```Ruby
|
245
|
-
class EmailJob
|
246
|
-
include SuckerPunch::Job
|
247
|
-
|
248
|
-
def perform(contact)
|
249
|
-
@contact = contact
|
250
|
-
::Notifications.contact_form(@contact).deliver # => If you don't use :: in this case, the notifications class from Celluloid will be loaded
|
251
|
-
end
|
252
|
-
end
|
253
|
-
```
|
254
|
-
|
255
264
|
### Cleaning test data transactions
|
256
265
|
|
257
266
|
If you're running tests in transactions (using Database Cleaner or a native solution), Sucker Punch jobs may have trouble finding database records that were created during test setup because the job class is running in a separate thread and the Transaction operates on a different thread so it clears out the data before the job can do its business. The best thing to do is cleanup data created for tests jobs through a truncation strategy by tagging the rspec tests as jobs and then specifying the strategy in `spec_helper` like below. And do not forget to turn off transactional fixtures (delete, comment or set it to `false`).
|
@@ -298,12 +307,6 @@ describe EmailJob, job: true do
|
|
298
307
|
end
|
299
308
|
```
|
300
309
|
|
301
|
-
## Gem Name
|
302
|
-
|
303
|
-
...is awesome. But I can't take credit for it. Thanks to
|
304
|
-
[@jmazzi](https://twitter.com/jmazzi) for his superior naming skills. If you're
|
305
|
-
looking for a name for something, he is the one to go to.
|
306
|
-
|
307
310
|
## Contributing
|
308
311
|
|
309
312
|
1. Fork it
|
data/Rakefile
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
-
require
|
2
|
+
require "rake/testtask"
|
3
3
|
|
4
|
-
|
4
|
+
Rake::TestTask.new(:test) do |t|
|
5
|
+
t.libs << "test"
|
6
|
+
t.libs << "lib"
|
7
|
+
t.test_files = FileList['test/**/*_test.rb']
|
8
|
+
end
|
5
9
|
|
6
|
-
|
7
|
-
task :default => :spec
|
8
|
-
task :test => :spec
|
10
|
+
task :default => :test
|
9
11
|
|
10
12
|
task :console do
|
11
13
|
exec "irb -r sucker_punch -I ./lib"
|
12
|
-
end
|
14
|
+
end
|
15
|
+
|
data/bin/load
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler'
|
4
|
+
Bundler.require(:default)
|
5
|
+
|
6
|
+
require_relative '../lib/sucker_punch'
|
7
|
+
|
8
|
+
class NoopJob
|
9
|
+
include SuckerPunch::Job
|
10
|
+
|
11
|
+
def perform(a)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
puts "Enqueuing 1MM jobs..."
|
16
|
+
|
17
|
+
1_000_000.times { NoopJob.perform_async(1) }
|
18
|
+
|
19
|
+
puts "Executing jobs..."
|
20
|
+
|
21
|
+
while SuckerPunch::Queue.all["NoopJob"]["jobs"]["enqueued"] > 0
|
22
|
+
sleep 0.01
|
23
|
+
end
|
data/bin/shutdown
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler'
|
4
|
+
Bundler.require(:default)
|
5
|
+
|
6
|
+
require_relative '../lib/sucker_punch'
|
7
|
+
|
8
|
+
class CountdownJob
|
9
|
+
include SuckerPunch::Job
|
10
|
+
|
11
|
+
def perform(i)
|
12
|
+
sleep 0.1
|
13
|
+
print "Executing job #{i}\n"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
puts "Enqueuing 100 jobs..."
|
18
|
+
|
19
|
+
100.times { |i| CountdownJob.perform_async(i) }
|
20
|
+
sleep 0.5
|
@@ -1,9 +1,51 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
begin
|
2
|
+
require 'active_support/core_ext/class/attribute'
|
3
|
+
rescue LoadError
|
4
|
+
|
5
|
+
# A dumbed down version of ActiveSupport's
|
6
|
+
# Class#class_attribute helper.
|
7
|
+
class Class
|
8
|
+
def class_attribute(*attrs)
|
9
|
+
instance_writer = true
|
10
|
+
|
11
|
+
attrs.each do |name|
|
12
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
13
|
+
def self.#{name}() nil end
|
14
|
+
def self.#{name}?() !!#{name} end
|
15
|
+
|
16
|
+
def self.#{name}=(val)
|
17
|
+
singleton_class.class_eval do
|
18
|
+
define_method(:#{name}) { val }
|
19
|
+
end
|
20
|
+
|
21
|
+
if singleton_class?
|
22
|
+
class_eval do
|
23
|
+
def #{name}
|
24
|
+
defined?(@#{name}) ? @#{name} : singleton_class.#{name}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
val
|
29
|
+
end
|
30
|
+
|
31
|
+
def #{name}
|
32
|
+
defined?(@#{name}) ? @#{name} : self.class.#{name}
|
33
|
+
end
|
34
|
+
|
35
|
+
def #{name}?
|
36
|
+
!!#{name}
|
37
|
+
end
|
38
|
+
RUBY
|
39
|
+
|
40
|
+
attr_writer name if instance_writer
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def singleton_class?
|
46
|
+
ancestors.first != self
|
47
|
+
end
|
48
|
+
end
|
9
49
|
end
|
50
|
+
|
51
|
+
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module SuckerPunch
|
2
|
+
module Counter
|
3
|
+
module Utilities
|
4
|
+
def value
|
5
|
+
@counter.value
|
6
|
+
end
|
7
|
+
|
8
|
+
def increment
|
9
|
+
@counter.increment
|
10
|
+
end
|
11
|
+
|
12
|
+
def decrement
|
13
|
+
@counter.decrement
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Busy
|
18
|
+
attr_reader :counter
|
19
|
+
|
20
|
+
include Utilities
|
21
|
+
|
22
|
+
COUNTER = Concurrent::Map.new do |hash, name|
|
23
|
+
hash.compute_if_absent(name) { Concurrent::AtomicFixnum.new }
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.clear
|
27
|
+
COUNTER.clear
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(queue_name)
|
31
|
+
@counter = COUNTER[queue_name]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Processed
|
36
|
+
attr_reader :counter
|
37
|
+
|
38
|
+
include Utilities
|
39
|
+
|
40
|
+
COUNTER = Concurrent::Map.new do |hash, name|
|
41
|
+
hash.compute_if_absent(name) { Concurrent::AtomicFixnum.new }
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.clear
|
45
|
+
COUNTER.clear
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize(queue_name)
|
49
|
+
@counter = COUNTER[queue_name]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class Failed
|
54
|
+
attr_reader :counter
|
55
|
+
|
56
|
+
include Utilities
|
57
|
+
|
58
|
+
COUNTER = Concurrent::Map.new do |hash, name|
|
59
|
+
hash.compute_if_absent(name) { Concurrent::AtomicFixnum.new }
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.clear
|
63
|
+
COUNTER.clear
|
64
|
+
end
|
65
|
+
|
66
|
+
def initialize(queue_name)
|
67
|
+
@counter = COUNTER[queue_name]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|