queueing_rabbit 0.5.0 → 0.6.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.
- data/lib/queueing_rabbit/client/amqp.rb +9 -1
- data/lib/queueing_rabbit/client/bunny.rb +16 -1
- data/lib/queueing_rabbit/configuration.rb +4 -0
- data/lib/queueing_rabbit/version.rb +1 -1
- data/lib/queueing_rabbit/worker.rb +59 -7
- data/lib/queueing_rabbit.rb +6 -2
- data/spec/integration/worker_termination_spec.rb +45 -0
- data/spec/unit/queueing_rabbit/client/amqp_spec.rb +1 -1
- data/spec/unit/queueing_rabbit/worker_spec.rb +1 -0
- metadata +6 -4
@@ -78,7 +78,7 @@ module QueueingRabbit
|
|
78
78
|
def close
|
79
79
|
info "closing AMQP broker connection..."
|
80
80
|
|
81
|
-
connection.
|
81
|
+
connection.disconnect do
|
82
82
|
yield if block_given?
|
83
83
|
|
84
84
|
EM.stop if EM.reactor_running?
|
@@ -142,6 +142,14 @@ module QueueingRabbit
|
|
142
142
|
EM.next_tick(&block)
|
143
143
|
end
|
144
144
|
|
145
|
+
def wait_while_for(proc, period, _ = nil, &block)
|
146
|
+
if proc.call
|
147
|
+
EM.add_timer(period, &block)
|
148
|
+
else
|
149
|
+
block.call
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
145
153
|
def begin_worker_loop
|
146
154
|
EM.run do
|
147
155
|
yield if block_given?
|
@@ -15,7 +15,11 @@ module QueueingRabbit
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def ack
|
18
|
-
@channel.ack(
|
18
|
+
@channel.ack(delivery_tag, false)
|
19
|
+
end
|
20
|
+
|
21
|
+
def delivery_tag
|
22
|
+
@delivery_info.delivery_tag
|
19
23
|
end
|
20
24
|
|
21
25
|
def headers
|
@@ -117,6 +121,17 @@ module QueueingRabbit
|
|
117
121
|
end
|
118
122
|
end
|
119
123
|
|
124
|
+
def wait_while_for(proc, seconds, interval = 0.5)
|
125
|
+
end_time = Time.now.to_i + seconds
|
126
|
+
|
127
|
+
while Time.now.to_i < end_time do
|
128
|
+
return unless proc.call
|
129
|
+
sleep interval
|
130
|
+
end
|
131
|
+
|
132
|
+
yield
|
133
|
+
end
|
134
|
+
|
120
135
|
private
|
121
136
|
|
122
137
|
def initialize(connection)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'monitor'
|
2
|
+
|
1
3
|
module QueueingRabbit
|
2
4
|
class Worker
|
3
5
|
|
@@ -10,13 +12,44 @@ module QueueingRabbit
|
|
10
12
|
def initialize(*jobs)
|
11
13
|
self.jobs = jobs.map { |job| job.to_s.strip }
|
12
14
|
|
15
|
+
@messages_lock = Monitor.new
|
16
|
+
@messages = {}
|
17
|
+
@channels = []
|
18
|
+
|
13
19
|
sync_stdio
|
14
20
|
validate_jobs
|
15
21
|
constantize_jobs
|
16
22
|
end
|
17
23
|
|
24
|
+
def checked_messages_count
|
25
|
+
@messages_lock.synchronize do
|
26
|
+
@messages.count
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def checkin_message(delivery_tag)
|
31
|
+
return unless @working
|
32
|
+
|
33
|
+
@messages_lock.synchronize do
|
34
|
+
@messages[delivery_tag] = true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def checkout_message(delivery_tag)
|
39
|
+
@messages_lock.synchronize do
|
40
|
+
@messages.delete(delivery_tag)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def working?
|
45
|
+
@working
|
46
|
+
end
|
47
|
+
|
18
48
|
def work
|
19
|
-
|
49
|
+
return if working?
|
50
|
+
|
51
|
+
@working = true
|
52
|
+
@channels = []
|
20
53
|
|
21
54
|
QueueingRabbit.trigger_event(:worker_ready)
|
22
55
|
|
@@ -26,6 +59,10 @@ module QueueingRabbit
|
|
26
59
|
end
|
27
60
|
|
28
61
|
def work!
|
62
|
+
return if working?
|
63
|
+
|
64
|
+
trap_signals
|
65
|
+
|
29
66
|
info "starting a new queueing_rabbit worker #{self}"
|
30
67
|
|
31
68
|
QueueingRabbit.begin_worker_loop { work }
|
@@ -59,10 +96,12 @@ module QueueingRabbit
|
|
59
96
|
|
60
97
|
def stop(connection = QueueingRabbit.connection)
|
61
98
|
connection.next_tick do
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
99
|
+
@working = false
|
100
|
+
close_channels do
|
101
|
+
connection.close do
|
102
|
+
info "gracefully shutting down the worker #{self}"
|
103
|
+
remove_pidfile
|
104
|
+
end
|
66
105
|
end
|
67
106
|
end
|
68
107
|
end
|
@@ -85,6 +124,15 @@ module QueueingRabbit
|
|
85
124
|
|
86
125
|
private
|
87
126
|
|
127
|
+
def close_channels(connection = QueueingRabbit.connection)
|
128
|
+
connection.wait_while_for(Proc.new { checked_messages_count > 0 },
|
129
|
+
QueueingRabbit.jobs_wait_timeout) do
|
130
|
+
@channels.each(&:close)
|
131
|
+
QueueingRabbit.trigger_event(:consuming_done)
|
132
|
+
yield
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
88
136
|
def validate_jobs
|
89
137
|
if jobs.nil? || jobs.empty?
|
90
138
|
fatal "no jobs specified to work on."
|
@@ -104,9 +152,13 @@ module QueueingRabbit
|
|
104
152
|
end
|
105
153
|
|
106
154
|
def run_job(conn, job)
|
107
|
-
QueueingRabbit.follow_job_requirements(job) do |
|
155
|
+
QueueingRabbit.follow_job_requirements(job) do |ch, _, queue|
|
156
|
+
@channels << ch
|
108
157
|
conn.listen_queue(queue, job.listening_options) do |payload, metadata|
|
109
|
-
|
158
|
+
if checkin_message(metadata.object_id)
|
159
|
+
invoke_job(job, payload, metadata)
|
160
|
+
checkout_message(metadata.object_id)
|
161
|
+
end
|
110
162
|
end
|
111
163
|
end
|
112
164
|
end
|
data/lib/queueing_rabbit.rb
CHANGED
@@ -90,23 +90,27 @@ module QueueingRabbit
|
|
90
90
|
end
|
91
91
|
|
92
92
|
def follow_job_requirements(job)
|
93
|
+
ret = nil
|
93
94
|
follow_bus_requirements(job) do |ch, ex|
|
94
95
|
conn.define_queue(ch, job.queue_name, job.queue_options) do |q|
|
95
96
|
if job.bind_queue?
|
96
97
|
job.binding_declarations.each { |o| conn.bind_queue(q, ex, o) }
|
97
98
|
end
|
98
99
|
|
99
|
-
yield ch, ex, q
|
100
|
+
ret = yield ch, ex, q
|
100
101
|
end
|
101
102
|
end
|
103
|
+
ret
|
102
104
|
end
|
103
105
|
|
104
106
|
def follow_bus_requirements(bus)
|
107
|
+
ret = nil
|
105
108
|
conn.open_channel(bus.channel_options) do |ch, _|
|
106
109
|
conn.define_exchange(ch, bus.exchange_name, bus.exchange_options) do |ex|
|
107
|
-
yield ch, ex
|
110
|
+
ret = yield ch, ex
|
108
111
|
end
|
109
112
|
end
|
113
|
+
ret
|
110
114
|
end
|
111
115
|
|
112
116
|
def queue_size(job)
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Terminating a worker' do
|
4
|
+
|
5
|
+
include_context 'Auto-disconnect'
|
6
|
+
include_context 'StringIO logger'
|
7
|
+
|
8
|
+
let(:queue) { Queue.new }
|
9
|
+
let(:job_name) { 'SleepAndAckJob' }
|
10
|
+
let(:job) {
|
11
|
+
Class.new(QueueingRabbit::AbstractJob) {
|
12
|
+
queue 'sleep_and_ack'
|
13
|
+
listen :ack => true
|
14
|
+
|
15
|
+
def self.complete!
|
16
|
+
@complete = true
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.complete?
|
20
|
+
!!@complete
|
21
|
+
end
|
22
|
+
|
23
|
+
def perform
|
24
|
+
sleep 3
|
25
|
+
self.class.complete!
|
26
|
+
acknowledge
|
27
|
+
end
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
before do
|
32
|
+
QueueingRabbit.purge_queue(job)
|
33
|
+
stub_const(job_name, job)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "waits for currently running consumers" do
|
37
|
+
worker = QueueingRabbit::Worker.new(job_name)
|
38
|
+
worker.work
|
39
|
+
job.enqueue('')
|
40
|
+
sleep 1
|
41
|
+
worker.stop
|
42
|
+
expect(job).to be_complete
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -139,7 +139,7 @@ describe QueueingRabbit::Client::AMQP do
|
|
139
139
|
describe '#close' do
|
140
140
|
before do
|
141
141
|
subject.should_receive(:info)
|
142
|
-
connection.should_receive(:
|
142
|
+
connection.should_receive(:disconnect).and_yield
|
143
143
|
EM.should_receive(:stop)
|
144
144
|
end
|
145
145
|
|
@@ -197,6 +197,7 @@ describe QueueingRabbit::Worker do
|
|
197
197
|
|
198
198
|
it 'closes the connection, removes the pidfile and reports the event' do
|
199
199
|
connection.should_receive(:next_tick).and_yield
|
200
|
+
connection.should_receive(:wait_while_for).and_yield
|
200
201
|
connection.should_receive(:close).and_yield
|
201
202
|
File.stub(:exists?).with(file_name).and_return(true)
|
202
203
|
File.should_receive(:delete).with(file_name)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: queueing_rabbit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
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: 2014-
|
12
|
+
date: 2014-10-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: amqp
|
@@ -136,6 +136,7 @@ files:
|
|
136
136
|
- spec/integration/synchronous_publishing_and_consuming_spec.rb
|
137
137
|
- spec/integration/synchronous_publishing_and_threaded_consuming_spec.rb
|
138
138
|
- spec/integration/synchronous_publishing_spec.rb
|
139
|
+
- spec/integration/worker_termination_spec.rb
|
139
140
|
- spec/spec_helper.rb
|
140
141
|
- spec/support/shared_contexts.rb
|
141
142
|
- spec/unit/queueing_rabbit/buses/abstract_bus_spec.rb
|
@@ -171,7 +172,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
171
172
|
version: '0'
|
172
173
|
segments:
|
173
174
|
- 0
|
174
|
-
hash:
|
175
|
+
hash: 657465743539399174
|
175
176
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
176
177
|
none: false
|
177
178
|
requirements:
|
@@ -180,7 +181,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
180
181
|
version: '0'
|
181
182
|
segments:
|
182
183
|
- 0
|
183
|
-
hash:
|
184
|
+
hash: 657465743539399174
|
184
185
|
requirements: []
|
185
186
|
rubyforge_project:
|
186
187
|
rubygems_version: 1.8.23
|
@@ -205,6 +206,7 @@ test_files:
|
|
205
206
|
- spec/integration/synchronous_publishing_and_consuming_spec.rb
|
206
207
|
- spec/integration/synchronous_publishing_and_threaded_consuming_spec.rb
|
207
208
|
- spec/integration/synchronous_publishing_spec.rb
|
209
|
+
- spec/integration/worker_termination_spec.rb
|
208
210
|
- spec/spec_helper.rb
|
209
211
|
- spec/support/shared_contexts.rb
|
210
212
|
- spec/unit/queueing_rabbit/buses/abstract_bus_spec.rb
|