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 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
- SuckerPunch.config do
30
- queue name: :log_queue, worker: LogWorker, size: 10
31
- queue name: :awesome_queue, worker: AwesomeWorker, size: 2
32
- end
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].size # => 7
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.
@@ -15,11 +15,12 @@ module SuckerPunch
15
15
  raise MissingQueueName unless options[:name]
16
16
  raise MissingWorkerName unless options[:worker]
17
17
 
18
- klass = options.fetch(:worker)
18
+ klass = options.fetch(:worker)
19
19
  registry_name = options.fetch(:name)
20
- size = options.fetch(:size, nil)
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, size)
24
+ q.register(klass, workers)
24
25
  end
25
- end
26
+ end
@@ -18,8 +18,12 @@ module SuckerPunch
18
18
  end
19
19
  end
20
20
 
21
+ def workers
22
+ size
23
+ end
24
+
21
25
  def method_missing(method_name, *args, &block)
22
26
  Celluloid::Actor[name].send(method_name, *args, &block)
23
27
  end
24
28
  end
25
- end
29
+ end
@@ -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
@@ -1,3 +1,3 @@
1
1
  module SuckerPunch
2
- VERSION = "0.3.1"
2
+ VERSION = "0.4"
3
3
  end
@@ -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, 7)
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 == 7
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, 7)
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 == 7
41
- queue.idle_size.should == 7
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 '../../lib/sucker_punch/testing/inline'
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
@@ -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, 7)
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, size: 7
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.3.1
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-20 00:00:00.000000000 Z
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