sucker_punch 0.3.1 → 0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.md +26 -0
- data/README.md +95 -10
- data/lib/sucker_punch.rb +5 -4
- data/lib/sucker_punch/queue.rb +5 -1
- data/lib/sucker_punch/testing.rb +44 -0
- data/lib/sucker_punch/version.rb +1 -1
- data/spec/{queue_spec.rb → sucker_punch/queue_spec.rb} +13 -6
- data/spec/{testing → sucker_punch/testing}/inline_spec.rb +2 -2
- data/spec/sucker_punch/testing_spec.rb +88 -0
- data/spec/{worker_spec.rb → sucker_punch/worker_spec.rb} +0 -0
- data/spec/sucker_punch_spec.rb +11 -3
- metadata +11 -8
data/CHANGES.md
CHANGED
@@ -1,3 +1,29 @@
|
|
1
|
+
0.4
|
2
|
+
-----------
|
3
|
+
- Prefer `workers` stat method over `size`
|
4
|
+
- Update config to use `workers` instead of `size`
|
5
|
+
|
6
|
+
old config:
|
7
|
+
|
8
|
+
```Ruby
|
9
|
+
# config/initializers/sucker_punch.rb
|
10
|
+
|
11
|
+
SuckerPunch.config do
|
12
|
+
queue name: :log_queue, worker: LogWorker, size: 10
|
13
|
+
end
|
14
|
+
```
|
15
|
+
|
16
|
+
new config:
|
17
|
+
|
18
|
+
```Ruby
|
19
|
+
# config/initializers/sucker_punch.rb
|
20
|
+
|
21
|
+
SuckerPunch.config do
|
22
|
+
queue name: :log_queue, worker: LogWorker, workers: 10
|
23
|
+
end
|
24
|
+
```
|
25
|
+
- Add testing library to stub out workers (see testing section in README)
|
26
|
+
|
1
27
|
0.3.1
|
2
28
|
-----------
|
3
29
|
|
data/README.md
CHANGED
@@ -23,20 +23,21 @@ Or install it yourself as:
|
|
23
23
|
|
24
24
|
## Configuration
|
25
25
|
|
26
|
-
`config/initializers/sucker_punch.rb`
|
27
26
|
|
28
27
|
```Ruby
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
28
|
+
# config/initializers/sucker_punch.rb
|
29
|
+
|
30
|
+
SuckerPunch.config do
|
31
|
+
queue name: :log_queue, worker: LogWorker, workers: 10
|
32
|
+
queue name: :awesome_queue, worker: AwesomeWorker, workers: 2
|
33
|
+
end
|
33
34
|
```
|
34
35
|
|
35
36
|
## Usage
|
36
37
|
|
37
|
-
`app/workers/log_worker.rb`
|
38
|
-
|
39
38
|
```Ruby
|
39
|
+
# app/workers/log_worker.rb
|
40
|
+
|
40
41
|
class LogWorker
|
41
42
|
include SuckerPunch::Worker
|
42
43
|
|
@@ -50,9 +51,10 @@ All workers should define an instance method `perform`, of which the job being q
|
|
50
51
|
|
51
52
|
Workers interacting with `ActiveRecord` should take special precaution not to exhaust connections in the pool. This can be done with `ActiveRecord::Base.connection_pool.with_connection`, which ensures the connection is returned back to the pool when completed.
|
52
53
|
|
53
|
-
`app/workers/awesome_worker.rb`
|
54
54
|
|
55
55
|
```Ruby
|
56
|
+
# app/workers/awesome_worker.rb
|
57
|
+
|
56
58
|
class AwesomeWorker
|
57
59
|
include SuckerPunch::Worker
|
58
60
|
|
@@ -103,15 +105,70 @@ SuckerPunch::Queue[:log_queue].async.perform("login") # => nil
|
|
103
105
|
## Stats
|
104
106
|
|
105
107
|
```Ruby
|
106
|
-
SuckerPunch::Queue[:log_queue].
|
108
|
+
SuckerPunch::Queue[:log_queue].workers # => 7
|
107
109
|
SuckerPunch::Queue[:log_queue].busy_size # => 4
|
108
110
|
SuckerPunch::Queue[:log_queue].idle_size # => 3
|
109
111
|
```
|
110
112
|
|
111
113
|
## Testing
|
112
114
|
|
113
|
-
`spec/spec_helper.rb`
|
114
115
|
```Ruby
|
116
|
+
# spec/spec_helper.rb
|
117
|
+
require 'sucker_punch/testing'
|
118
|
+
```
|
119
|
+
|
120
|
+
Requiring this library completely stubs out the internals of Sucker Puncker, but will provide the necessary tools to confirm your jobs are being enqueucompletely stubs out the internals of Sucker Puncker, but will provide the necessary tools to confirm your jobs are being enqueued.
|
121
|
+
|
122
|
+
```Ruby
|
123
|
+
# spec/spec_helper.rb
|
124
|
+
require 'sucker_punch/testing'
|
125
|
+
|
126
|
+
RSpec.configure do |config|
|
127
|
+
config.after(:before) do
|
128
|
+
SuckerPunch.reset! # => Resets the queues and jobs in the queues before each test
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# config/initializer/sucker_punch.rb
|
133
|
+
SuckerPunch.config do
|
134
|
+
queue name: :email, worker: EmailWorker, workers: 2
|
135
|
+
end
|
136
|
+
|
137
|
+
# config/workers/email_worker.rb
|
138
|
+
class EmailWorker
|
139
|
+
include SuckerPunch::Worker
|
140
|
+
|
141
|
+
def perform(email, user_id)
|
142
|
+
user = User.find(user_id)
|
143
|
+
UserMailer.send(email.to_sym, user)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# spec/models/user.rb
|
148
|
+
class User < ActiveRecord::Base
|
149
|
+
def send_welcome_email
|
150
|
+
SuckerPunch::Queue.new(:email).async.perform(:welcome, self.id)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# spec/spec_helper.rb
|
155
|
+
require 'sucker_punch/testing'
|
156
|
+
|
157
|
+
# spec/models/user_spec.rb
|
158
|
+
require 'spec_helper'
|
159
|
+
|
160
|
+
describe User do
|
161
|
+
describe "#send_welcome_email" do
|
162
|
+
user = FactoryGirl.create(:user)
|
163
|
+
expect{
|
164
|
+
user.send_welcome_email
|
165
|
+
}.to change{ SuckerPunch::Queue.new(:email).jobs.size }.by(1)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
```
|
169
|
+
|
170
|
+
```Ruby
|
171
|
+
# spec/spec_helper.rb
|
115
172
|
require 'sucker_punch/testing/inline'
|
116
173
|
```
|
117
174
|
|
@@ -121,6 +178,34 @@ Requiring this library causes your workers to run everything inline. So a call t
|
|
121
178
|
SuckerPunch::Queue[:log_queue].async.perform("login")
|
122
179
|
```
|
123
180
|
|
181
|
+
## Troubleshooting
|
182
|
+
|
183
|
+
When using Passenger or Unicorn, you should configure the queues within a block that runs after the child process is forked.
|
184
|
+
|
185
|
+
```Ruby
|
186
|
+
# config/unicorn.rb
|
187
|
+
#
|
188
|
+
# The following is only need if in your unicorn config
|
189
|
+
# you set:
|
190
|
+
# preload_app true
|
191
|
+
after_fork do |server, worker|
|
192
|
+
SuckerPunch.config do
|
193
|
+
queue name: :log_queue, worker: LogWorker, workers: 10
|
194
|
+
end
|
195
|
+
end
|
196
|
+
```
|
197
|
+
```Ruby
|
198
|
+
# config/initializers/sucker_punch.rb
|
199
|
+
#
|
200
|
+
if defined?(PhusionPassenger)
|
201
|
+
PhusionPassenger.on_event(:starting_worker_process) do |forked|
|
202
|
+
SuckerPunch.config do
|
203
|
+
queue name: :log_queue, worker: LogWorker, workers: 10
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
```
|
208
|
+
|
124
209
|
## Gem Name
|
125
210
|
|
126
211
|
...is awesome. But I can't take credit for it. Thanks to [@jmazzi](https://twitter.com/jmazzi) for his superior naming skills. If you're looking for a name for something, he is the one to go to.
|
data/lib/sucker_punch.rb
CHANGED
@@ -15,11 +15,12 @@ module SuckerPunch
|
|
15
15
|
raise MissingQueueName unless options[:name]
|
16
16
|
raise MissingWorkerName unless options[:worker]
|
17
17
|
|
18
|
-
klass
|
18
|
+
klass = options.fetch(:worker)
|
19
19
|
registry_name = options.fetch(:name)
|
20
|
-
|
20
|
+
workers = options.fetch(:workers, nil)
|
21
|
+
workers ||= options.fetch(:size, nil)
|
21
22
|
|
22
23
|
q = Queue.new(registry_name)
|
23
|
-
q.register(klass,
|
24
|
+
q.register(klass, workers)
|
24
25
|
end
|
25
|
-
end
|
26
|
+
end
|
data/lib/sucker_punch/queue.rb
CHANGED
@@ -0,0 +1,44 @@
|
|
1
|
+
module SuckerPunch
|
2
|
+
class << self
|
3
|
+
attr_accessor :queues
|
4
|
+
|
5
|
+
def reset!
|
6
|
+
self.queues = {}
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
SuckerPunch.reset!
|
11
|
+
|
12
|
+
class Queue
|
13
|
+
attr_reader :name
|
14
|
+
|
15
|
+
def initialize(name)
|
16
|
+
@name = name
|
17
|
+
SuckerPunch.queues[name] ||= []
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.[](name)
|
21
|
+
new(name)
|
22
|
+
end
|
23
|
+
|
24
|
+
def register(klass, size)
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def workers
|
29
|
+
raise "Not implemented"
|
30
|
+
end
|
31
|
+
|
32
|
+
def jobs
|
33
|
+
SuckerPunch.queues[@name]
|
34
|
+
end
|
35
|
+
|
36
|
+
def async
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def method_missing(name, *args, &block)
|
41
|
+
SuckerPunch.queues[@name] << { method: name, args: Array(args) }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/sucker_punch/version.rb
CHANGED
@@ -15,7 +15,7 @@ describe SuckerPunch::Queue do
|
|
15
15
|
|
16
16
|
describe "#register" do
|
17
17
|
before(:each) do
|
18
|
-
SuckerPunch::Queue.new(:crazy_queue).register(FakeWorker,
|
18
|
+
SuckerPunch::Queue.new(:crazy_queue).register(FakeWorker, 2)
|
19
19
|
end
|
20
20
|
|
21
21
|
it "turns the class into an actor" do
|
@@ -25,7 +25,14 @@ describe SuckerPunch::Queue do
|
|
25
25
|
end
|
26
26
|
|
27
27
|
it "sets worker size" do
|
28
|
-
Celluloid::Actor[:crazy_queue].size.should ==
|
28
|
+
Celluloid::Actor[:crazy_queue].size.should == 2
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#workers" do
|
33
|
+
it "returns number of workers" do
|
34
|
+
SuckerPunch::Queue.new(:crazy_queue).register(FakeWorker, 2)
|
35
|
+
SuckerPunch::Queue.new(:crazy_queue).workers.should == 2
|
29
36
|
end
|
30
37
|
end
|
31
38
|
|
@@ -33,13 +40,13 @@ describe SuckerPunch::Queue do
|
|
33
40
|
let(:queue) { SuckerPunch::Queue.new(:crazy_queue) }
|
34
41
|
|
35
42
|
before(:each) do
|
36
|
-
SuckerPunch::Queue.new(:crazy_queue).register(FakeWorker,
|
43
|
+
SuckerPunch::Queue.new(:crazy_queue).register(FakeWorker, 2)
|
37
44
|
end
|
38
45
|
|
39
46
|
it "sends messages to Actor" do
|
40
|
-
queue.size.should ==
|
41
|
-
queue.idle_size.should ==
|
47
|
+
queue.size.should == 2
|
48
|
+
queue.idle_size.should == 2
|
42
49
|
queue.busy_size.should == 0
|
43
50
|
end
|
44
51
|
end
|
45
|
-
end
|
52
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require_relative '
|
2
|
+
require_relative '../../../lib/sucker_punch/testing/inline'
|
3
3
|
|
4
4
|
class PatchedWorker
|
5
5
|
include SuckerPunch::Worker
|
@@ -10,7 +10,7 @@ class PatchedWorker
|
|
10
10
|
end
|
11
11
|
SuckerPunch::Queue.new(:patched_queue).register(PatchedWorker, 2)
|
12
12
|
|
13
|
-
describe "Testing" do
|
13
|
+
describe "SuckerPunch Inline Testing" do
|
14
14
|
let(:queue) { SuckerPunch::Queue.new(:patched_queue) }
|
15
15
|
|
16
16
|
it "processes jobs inline" do
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class TestingWorker
|
4
|
+
include Celluloid
|
5
|
+
|
6
|
+
def perform(input)
|
7
|
+
input = "after"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
SuckerPunch.config do
|
12
|
+
queue name: :queue, worker: TestingWorker
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "SuckerPunch Testing" do
|
16
|
+
before :each do
|
17
|
+
require_relative '../../lib/sucker_punch/testing'
|
18
|
+
SuckerPunch.reset!
|
19
|
+
end
|
20
|
+
|
21
|
+
describe ".reset!" do
|
22
|
+
it "resets the queues to be empty" do
|
23
|
+
4.times { SuckerPunch::Queue.new(:queue).async.perform("before") }
|
24
|
+
SuckerPunch.reset!
|
25
|
+
queue = SuckerPunch::Queue.new(:queue)
|
26
|
+
expect(queue.jobs.count).to eq 0
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe Queue do
|
31
|
+
it "returns previous instance when queried again" do
|
32
|
+
queue = SuckerPunch::Queue.new(:queue)
|
33
|
+
queue.async.perform("before")
|
34
|
+
expect(SuckerPunch::Queue.new(:queue).jobs.count).to eq 1
|
35
|
+
end
|
36
|
+
|
37
|
+
describe ".[]" do
|
38
|
+
it "returns the queue instance" do
|
39
|
+
queue = SuckerPunch::Queue.new(:queue)
|
40
|
+
queue.async.perform("before")
|
41
|
+
expect(SuckerPunch::Queue[:queue].jobs.count).to eq 1
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#register" do
|
46
|
+
it "returns nil" do
|
47
|
+
queue = SuckerPunch::Queue.new(:queue)
|
48
|
+
expect(queue.register(TestingWorker, 3)).to eq nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#workers" do
|
53
|
+
it "raises an exception if called" do
|
54
|
+
queue = SuckerPunch::Queue.new(:queue)
|
55
|
+
expect{ queue.workers }.to raise_error "Not implemented"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#jobs" do
|
60
|
+
it "returns an array of the jobs in the queue" do
|
61
|
+
queue = SuckerPunch::Queue.new(:queue)
|
62
|
+
queue.async.perform("before")
|
63
|
+
expect(queue.jobs).to eq [{ method: :perform, args: ["before"] }]
|
64
|
+
end
|
65
|
+
|
66
|
+
it "returns the number of jobs in the queue" do
|
67
|
+
queue = SuckerPunch::Queue.new(:queue)
|
68
|
+
4.times { queue.async.perform("before") }
|
69
|
+
expect(queue.jobs.count).to eq 4
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "#async" do
|
74
|
+
it "returns self" do
|
75
|
+
queue = SuckerPunch::Queue.new(:queue)
|
76
|
+
expect(queue.async).to eq queue
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "enqueueing a job" do
|
81
|
+
it "adds the job to the queue" do
|
82
|
+
queue = SuckerPunch::Queue.new(:queue)
|
83
|
+
queue.async.perform("before")
|
84
|
+
expect(queue.jobs).to eq [{ method: :perform, args: ["before"] }]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
File without changes
|
data/spec/sucker_punch_spec.rb
CHANGED
@@ -9,10 +9,18 @@ describe SuckerPunch do
|
|
9
9
|
|
10
10
|
context "properly configured" do
|
11
11
|
it "registers the queue" do
|
12
|
-
SuckerPunch::Queue.any_instance.should_receive(:register).with(FakeWorker,
|
12
|
+
SuckerPunch::Queue.any_instance.should_receive(:register).with(FakeWorker, 3)
|
13
13
|
|
14
14
|
SuckerPunch.config do
|
15
|
-
queue name: :crazy_queue, worker: FakeWorker,
|
15
|
+
queue name: :crazy_queue, worker: FakeWorker, workers: 3
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it "supports size for workers count" do
|
20
|
+
SuckerPunch::Queue.any_instance.should_receive(:register).with(FakeWorker, 3)
|
21
|
+
|
22
|
+
SuckerPunch.config do
|
23
|
+
queue name: :crazy_queue, worker: FakeWorker, size: 3
|
16
24
|
end
|
17
25
|
end
|
18
26
|
end
|
@@ -38,4 +46,4 @@ describe SuckerPunch do
|
|
38
46
|
end
|
39
47
|
|
40
48
|
end
|
41
|
-
end
|
49
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sucker_punch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: '0.4'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-03-
|
12
|
+
date: 2013-03-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -76,14 +76,16 @@ files:
|
|
76
76
|
- lib/sucker_punch.rb
|
77
77
|
- lib/sucker_punch/exceptions.rb
|
78
78
|
- lib/sucker_punch/queue.rb
|
79
|
+
- lib/sucker_punch/testing.rb
|
79
80
|
- lib/sucker_punch/testing/inline.rb
|
80
81
|
- lib/sucker_punch/version.rb
|
81
82
|
- lib/sucker_punch/worker.rb
|
82
|
-
- spec/queue_spec.rb
|
83
83
|
- spec/spec_helper.rb
|
84
|
+
- spec/sucker_punch/queue_spec.rb
|
85
|
+
- spec/sucker_punch/testing/inline_spec.rb
|
86
|
+
- spec/sucker_punch/testing_spec.rb
|
87
|
+
- spec/sucker_punch/worker_spec.rb
|
84
88
|
- spec/sucker_punch_spec.rb
|
85
|
-
- spec/testing/inline_spec.rb
|
86
|
-
- spec/worker_spec.rb
|
87
89
|
- sucker_punch.gemspec
|
88
90
|
homepage: https://github.com/brandonhilkert/sucker_punch
|
89
91
|
licenses: []
|
@@ -111,8 +113,9 @@ specification_version: 3
|
|
111
113
|
summary: Sucker Punch is a Ruby asynchronous processing using Celluloid, heavily influenced
|
112
114
|
by Sidekiq and girl_friday.
|
113
115
|
test_files:
|
114
|
-
- spec/queue_spec.rb
|
115
116
|
- spec/spec_helper.rb
|
117
|
+
- spec/sucker_punch/queue_spec.rb
|
118
|
+
- spec/sucker_punch/testing/inline_spec.rb
|
119
|
+
- spec/sucker_punch/testing_spec.rb
|
120
|
+
- spec/sucker_punch/worker_spec.rb
|
116
121
|
- spec/sucker_punch_spec.rb
|
117
|
-
- spec/testing/inline_spec.rb
|
118
|
-
- spec/worker_spec.rb
|