proletariat 0.0.6 → 0.1.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.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/README.md +2 -1
- data/lib/proletariat.rb +15 -2
- data/lib/proletariat/concurrency/actor.rb +12 -67
- data/lib/proletariat/concurrency/actor_common.rb +30 -0
- data/lib/proletariat/concurrency/poolable_actor.rb +25 -0
- data/lib/proletariat/configuration.rb +15 -0
- data/lib/proletariat/cucumber.rb +2 -4
- data/lib/proletariat/exception_handler.rb +45 -0
- data/lib/proletariat/exception_handler/drop.rb +15 -0
- data/lib/proletariat/exception_handler/exponential_backoff.rb +130 -0
- data/lib/proletariat/manager.rb +30 -28
- data/lib/proletariat/message.rb +9 -0
- data/lib/proletariat/publisher.rb +19 -41
- data/lib/proletariat/runner.rb +18 -30
- data/lib/proletariat/subscriber.rb +91 -177
- data/lib/proletariat/tasks.rb +1 -1
- data/lib/proletariat/testing/expectation_guarantor.rb +36 -30
- data/lib/proletariat/version.rb +1 -1
- data/lib/proletariat/worker.rb +47 -34
- data/proletariat.gemspec +3 -3
- data/spec/lib/proletariat_spec.rb +18 -7
- data/spec/lib/testing/expectation_guarantor_spec.rb +0 -32
- data/spec/lib/worker_spec.rb +13 -15
- metadata +15 -12
- data/lib/proletariat/concurrency/supervisor.rb +0 -31
- data/spec/lib/publisher_spec.rb +0 -36
data/lib/proletariat/manager.rb
CHANGED
@@ -2,35 +2,22 @@ module Proletariat
|
|
2
2
|
# Public: Maintains a pool of worker threads and a RabbitMQ subscriber
|
3
3
|
# thread. Uses information from the worker class to generate queue
|
4
4
|
# config.
|
5
|
-
class Manager
|
5
|
+
class Manager < Concurrent::Actor::RestartingContext
|
6
6
|
# Public: Creates a new Manager instance.
|
7
7
|
#
|
8
8
|
# worker_class - A subclass of Proletariat::Worker to handle messages.
|
9
9
|
def initialize(worker_class)
|
10
|
-
@
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
# Delegate lifecycle calls to supervisor. Cannot use Forwardable due to
|
22
|
-
# concurrent-ruby API checking implementation.
|
23
|
-
%w(run stop running?).each do |method|
|
24
|
-
define_method(method) { supervisor.send method }
|
25
|
-
end
|
26
|
-
|
27
|
-
# Public: Purge the RabbitMQ queue.
|
28
|
-
#
|
29
|
-
# Returns nil.
|
30
|
-
def purge
|
31
|
-
subscriber.purge
|
32
|
-
|
33
|
-
nil
|
10
|
+
@workers = worker_class.pool(Proletariat.worker_threads, object_id)
|
11
|
+
|
12
|
+
@subscriber = Subscriber.spawn!(
|
13
|
+
name: "#{worker_class.to_s}_subscriber_#{object_id}",
|
14
|
+
supervise: true,
|
15
|
+
args: [
|
16
|
+
workers,
|
17
|
+
generate_queue_config(worker_class),
|
18
|
+
get_exception_handler_class(worker_class)
|
19
|
+
]
|
20
|
+
)
|
34
21
|
end
|
35
22
|
|
36
23
|
private
|
@@ -38,8 +25,22 @@ module Proletariat
|
|
38
25
|
# Internal: Returns the Subscriber actor for this Manager.
|
39
26
|
attr_reader :subscriber
|
40
27
|
|
41
|
-
# Internal:
|
42
|
-
attr_reader :
|
28
|
+
# Internal: Returns an Array of Worker actors.
|
29
|
+
attr_reader :workers
|
30
|
+
|
31
|
+
def get_exception_handler_class(worker_class)
|
32
|
+
if worker_class.exception_handler.is_a?(ExceptionHandler)
|
33
|
+
worker_class.exception_handler
|
34
|
+
else
|
35
|
+
name = worker_class.exception_handler
|
36
|
+
.to_s
|
37
|
+
.split('_')
|
38
|
+
.map(&:capitalize)
|
39
|
+
.join
|
40
|
+
|
41
|
+
Proletariat.const_get(name)
|
42
|
+
end
|
43
|
+
end
|
43
44
|
|
44
45
|
# Internal: Builds a new QueueConfig from a given Worker subclass.
|
45
46
|
#
|
@@ -47,7 +48,8 @@ module Proletariat
|
|
47
48
|
#
|
48
49
|
# Returns a new QueueConfig instance.
|
49
50
|
def generate_queue_config(worker_class)
|
50
|
-
QueueConfig.new(worker_class.name, worker_class.routing_keys,
|
51
|
+
QueueConfig.new(worker_class.name, worker_class.routing_keys,
|
52
|
+
Proletariat.test_mode?)
|
51
53
|
end
|
52
54
|
end
|
53
55
|
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# Internal: Struct to store message details for passing around.
|
2
|
+
#
|
3
|
+
# to - The routing key for the message to as a String. In accordance
|
4
|
+
# with the RabbitMQ convention you can use the '*' character to
|
5
|
+
# replace one word and the '#' to replace many words.
|
6
|
+
# body - The message as a String.
|
7
|
+
# headers - Hash of message headers.
|
8
|
+
class Message < Struct.new(:to, :body, :headers)
|
9
|
+
end
|
@@ -2,64 +2,42 @@ require 'proletariat/concerns/logging'
|
|
2
2
|
|
3
3
|
module Proletariat
|
4
4
|
# Public: Receives messages and publishes them to a RabbitMQ topic exchange.
|
5
|
-
class Publisher
|
5
|
+
class Publisher < PoolableActor
|
6
6
|
include Concerns::Logging
|
7
7
|
|
8
|
-
# Public:
|
9
|
-
def initialize
|
10
|
-
@channel = Proletariat.connection.create_channel
|
11
|
-
@exchange = channel.topic(Proletariat.exchange_name, durable: true)
|
12
|
-
end
|
13
|
-
|
14
|
-
# Public: Logs the 'online' status of the publisher.
|
15
|
-
#
|
16
|
-
# Returns nil.
|
17
|
-
def started
|
18
|
-
log_info 'Now online'
|
19
|
-
|
20
|
-
nil
|
21
|
-
end
|
22
|
-
|
23
|
-
# Public: Logs the 'offline' status of the publisher.
|
24
|
-
#
|
25
|
-
# Returns nil.
|
26
|
-
def stopped
|
27
|
-
log_info 'Now offline'
|
28
|
-
|
29
|
-
nil
|
30
|
-
end
|
31
|
-
|
32
|
-
# Public: Logs the 'shutting down' status of the publisher.
|
8
|
+
# Public: Closes the Bunny::Channel if open.
|
33
9
|
#
|
34
10
|
# Returns nil.
|
35
|
-
def
|
36
|
-
|
11
|
+
def cleanup
|
12
|
+
@channel.close if @channel
|
37
13
|
|
38
14
|
nil
|
39
15
|
end
|
40
16
|
|
41
|
-
# Public: Push a
|
17
|
+
# Public: Push a Message to a RabbitMQ topic exchange.
|
42
18
|
#
|
43
|
-
#
|
44
|
-
# with the RabbitMQ convention you can use the '*' character to
|
45
|
-
# replace one word and the '#' to replace many words.
|
46
|
-
# message - The message as a String.
|
47
|
-
# headers - Hash of message headers.
|
19
|
+
# message - A Message to send.
|
48
20
|
#
|
49
21
|
# Returns nil.
|
50
|
-
def work(
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
22
|
+
def work(message)
|
23
|
+
if message.is_a?(Message)
|
24
|
+
exchange.publish(message.body, routing_key: message.to,
|
25
|
+
persistent: !Proletariat.test_mode?,
|
26
|
+
headers: message.headers)
|
27
|
+
end
|
55
28
|
end
|
56
29
|
|
57
30
|
private
|
58
31
|
|
59
32
|
# Internal: Returns the Bunny::Channel in use.
|
60
|
-
|
33
|
+
def channel
|
34
|
+
@channel ||= Proletariat.connection.create_channel
|
35
|
+
end
|
61
36
|
|
62
37
|
# Internal: Returns the Bunny::Exchange in use.
|
63
|
-
|
38
|
+
def exchange
|
39
|
+
@exchange ||= channel.topic(Proletariat.exchange_name,
|
40
|
+
durable: !Proletariat.test_mode?)
|
41
|
+
end
|
64
42
|
end
|
65
43
|
end
|
data/lib/proletariat/runner.rb
CHANGED
@@ -4,41 +4,32 @@ module Proletariat
|
|
4
4
|
class Runner
|
5
5
|
extend Forwardable
|
6
6
|
|
7
|
-
# Public:
|
8
|
-
def_delegators :supervisor, :run, :run!, :stop, :running?
|
9
|
-
|
10
|
-
# Public: Creates a new Runner instance.
|
11
|
-
def initialize
|
12
|
-
@supervisor = Supervisor.new
|
13
|
-
@managers = Proletariat.worker_classes.map do |worker_class|
|
14
|
-
Manager.new(worker_class)
|
15
|
-
end
|
16
|
-
|
17
|
-
supervisor.supervise_pool('publishers', Proletariat.publisher_threads,
|
18
|
-
Publisher)
|
19
|
-
managers.each { |manager| supervisor.add_supervisor manager }
|
20
|
-
end
|
21
|
-
|
22
|
-
# Public: Publishes a message to RabbitMQ via the publisher pool.
|
23
|
-
#
|
24
|
-
# to - The routing key for the message to as a String. In accordance
|
25
|
-
# with the RabbitMQ convention you can use the '*' character to
|
26
|
-
# replace one word and the '#' to replace many words.
|
27
|
-
# message - The message as a String.
|
28
|
-
# headers - Hash of message headers.
|
7
|
+
# Public: Start the workers.
|
29
8
|
#
|
30
9
|
# Returns nil.
|
31
|
-
def
|
32
|
-
|
10
|
+
def run
|
11
|
+
@managers = Proletariat.worker_classes.map do |worker_class|
|
12
|
+
Manager.spawn!(name: "manager_#{worker_class.to_s}_#{object_id}",
|
13
|
+
supervise: true,
|
14
|
+
args: [worker_class])
|
15
|
+
end
|
16
|
+
|
17
|
+
managers.each { |manager| manager << :run }
|
33
18
|
|
34
19
|
nil
|
35
20
|
end
|
36
21
|
|
37
|
-
# Public:
|
22
|
+
# Public: Check whether the workers are currently running.
|
23
|
+
def running?
|
24
|
+
!!managers
|
25
|
+
end
|
26
|
+
|
27
|
+
# Public: Stop the workers.
|
38
28
|
#
|
39
29
|
# Returns nil.
|
40
|
-
def
|
41
|
-
managers.each { |manager| manager
|
30
|
+
def stop
|
31
|
+
managers.each { |manager| manager << :terminate! } if managers
|
32
|
+
@managers = nil
|
42
33
|
|
43
34
|
nil
|
44
35
|
end
|
@@ -47,8 +38,5 @@ module Proletariat
|
|
47
38
|
|
48
39
|
# Internal: Returns an Array of the currently supervised Managers.
|
49
40
|
attr_reader :managers
|
50
|
-
|
51
|
-
# Internal: Returns the supervisor instance.
|
52
|
-
attr_reader :supervisor
|
53
41
|
end
|
54
42
|
end
|
@@ -1,86 +1,42 @@
|
|
1
1
|
module Proletariat
|
2
2
|
# Internal: Creates, binds and listens on a RabbitMQ queue. Forwards
|
3
3
|
# messages to a given listener.
|
4
|
-
class Subscriber
|
5
|
-
include Concurrent::Runnable
|
6
|
-
|
4
|
+
class Subscriber < Actor
|
7
5
|
include Concerns::Logging
|
8
6
|
|
9
7
|
# Public: Creates a new Subscriber instance.
|
10
8
|
#
|
11
9
|
# listener - Object to delegate new messages to.
|
12
10
|
# queue_config - A QueueConfig value object.
|
13
|
-
def initialize(listener, queue_config)
|
14
|
-
@listener
|
15
|
-
@queue_config
|
16
|
-
|
17
|
-
@channel = Proletariat.connection.create_channel
|
18
|
-
|
19
|
-
@channel.prefetch Proletariat.worker_threads
|
20
|
-
|
21
|
-
@exchange = @channel.topic Proletariat.exchange_name, durable: true
|
22
|
-
@bunny_queue = @channel.queue queue_config.queue_name,
|
23
|
-
durable: true,
|
24
|
-
auto_delete: queue_config.auto_delete
|
11
|
+
def initialize(listener, queue_config, exception_handler_class)
|
12
|
+
@listener = listener
|
13
|
+
@queue_config = queue_config
|
14
|
+
@exception_handler_class = exception_handler_class
|
25
15
|
|
26
16
|
bind_queue
|
27
|
-
end
|
28
|
-
|
29
|
-
# Internal: Called by the Concurrent framework on run. Used here to start
|
30
|
-
# consumption of the queue and to log the status of the
|
31
|
-
# subscriber.
|
32
|
-
#
|
33
|
-
# Returns nil.
|
34
|
-
def on_run
|
35
17
|
start_consumer
|
36
|
-
log_info 'Now online'
|
37
|
-
|
38
|
-
nil
|
39
|
-
end
|
40
18
|
|
41
|
-
|
42
|
-
|
43
|
-
# subscriber.
|
44
|
-
#
|
45
|
-
# Returns nil.
|
46
|
-
def on_stop
|
47
|
-
log_info 'Attempting graceful shutdown.'
|
48
|
-
stop_consumer
|
49
|
-
log_info 'Now offline'
|
50
|
-
end
|
51
|
-
|
52
|
-
# Internal: Called by the Concurrent framework to perform work. Used here
|
53
|
-
# acknowledge RabbitMQ messages.
|
54
|
-
#
|
55
|
-
# Returns nil.
|
56
|
-
def on_task
|
57
|
-
ready_acknowledgers.each do |acknowledger|
|
58
|
-
acknowledger.acknowledge_on_channel channel
|
59
|
-
acknowledgers.delete acknowledger
|
19
|
+
@ticker = Concurrent::TimerTask.execute(execution: 5, timeout: 2) do
|
20
|
+
acknowledge_messages
|
60
21
|
end
|
61
|
-
|
62
|
-
completed_retries.each { |r| scheduled_retries.delete r }
|
63
22
|
end
|
64
23
|
|
65
|
-
#
|
24
|
+
# Internal: Called on actor termination. Used to stop consumption off the
|
25
|
+
# queue and end the ticker.
|
66
26
|
#
|
67
27
|
# Returns nil.
|
68
|
-
def
|
69
|
-
|
28
|
+
def cleanup
|
29
|
+
@ticker.kill if @ticker
|
30
|
+
stop_consumer if @consumer
|
31
|
+
@channel.close if @channel && channel.open?
|
70
32
|
|
71
33
|
nil
|
72
34
|
end
|
73
35
|
|
74
36
|
private
|
75
37
|
|
76
|
-
# Internal: Returns the
|
77
|
-
attr_reader :
|
78
|
-
|
79
|
-
# Internal: Returns the Bunny::Channel in use.
|
80
|
-
attr_reader :channel
|
81
|
-
|
82
|
-
# Internal: Returns the Bunny::Exchange in use.
|
83
|
-
attr_reader :exchange
|
38
|
+
# Internal: Returns the ExceptionHandler class.
|
39
|
+
attr_reader :exception_handler_class
|
84
40
|
|
85
41
|
# Internal: Returns the listener object.
|
86
42
|
attr_reader :listener
|
@@ -88,6 +44,20 @@ module Proletariat
|
|
88
44
|
# Internal: Returns the queue_config in use.
|
89
45
|
attr_reader :queue_config
|
90
46
|
|
47
|
+
# Internal: Acknowledge processed messages.
|
48
|
+
#
|
49
|
+
# Returns nil.
|
50
|
+
def acknowledge_messages
|
51
|
+
ready_acknowledgers.each do |acknowledger|
|
52
|
+
acknowledger.acknowledge_on_channel channel
|
53
|
+
acknowledgers.delete acknowledger
|
54
|
+
end
|
55
|
+
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
|
59
|
+
# Internal: Returns array of Acknowledgers which haven't acknowledged their
|
60
|
+
# messages.
|
91
61
|
def acknowledgers
|
92
62
|
@acknowledgers ||= []
|
93
63
|
end
|
@@ -104,11 +74,31 @@ module Proletariat
|
|
104
74
|
nil
|
105
75
|
end
|
106
76
|
|
107
|
-
# Internal:
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
77
|
+
# Internal: Returns the Bunny::Queue in use.
|
78
|
+
def bunny_queue
|
79
|
+
@bunny_queue ||= channel.queue(queue_config.queue_name,
|
80
|
+
durable: !Proletariat.test_mode?,
|
81
|
+
auto_delete: Proletariat.test_mode?)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Internal: Returns the Bunny::Channel in use.
|
85
|
+
def channel
|
86
|
+
@channel ||= Proletariat.connection.create_channel.tap do |channel|
|
87
|
+
channel.prefetch Proletariat.worker_threads + 1
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def exception_handler
|
92
|
+
@exception_handler ||= exception_handler_class.spawn!(
|
93
|
+
name: "#{queue_config.worker_name}_exception_handler",
|
94
|
+
supervise: true, args: [queue_config.queue_name]
|
95
|
+
)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Internal: Returns the Bunny::Exchange in use.
|
99
|
+
def exchange
|
100
|
+
@exchange ||= channel.topic(Proletariat.exchange_name,
|
101
|
+
durable: !Proletariat.test_mode?)
|
112
102
|
end
|
113
103
|
|
114
104
|
# Internal: Forwards all message bodies to listener#post. Auto-acks
|
@@ -117,12 +107,12 @@ module Proletariat
|
|
117
107
|
# Returns nil.
|
118
108
|
def handle_message(info, properties, body)
|
119
109
|
if handles_worker_type? properties.headers['worker']
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
110
|
+
message = Message.new(info.routing_key, body, properties.headers)
|
111
|
+
ivar = listener.ask(message)
|
112
|
+
acknowledgers << Acknowledger.new(ivar, info.delivery_tag, message,
|
113
|
+
exception_handler)
|
124
114
|
else
|
125
|
-
channel.
|
115
|
+
channel.ack info.delivery_tag
|
126
116
|
end
|
127
117
|
|
128
118
|
nil
|
@@ -146,18 +136,16 @@ module Proletariat
|
|
146
136
|
end
|
147
137
|
end
|
148
138
|
|
149
|
-
def scheduled_retries
|
150
|
-
@scheduled_retries ||= []
|
151
|
-
end
|
152
|
-
|
153
139
|
# Internal: Starts a consumer on the queue. The consumer forwards all
|
154
140
|
# message bodies to listener#post. Auto-acks messages not meant
|
155
141
|
# for this subscriber's workers.
|
156
142
|
#
|
157
143
|
# Returns nil.
|
158
144
|
def start_consumer
|
159
|
-
@consumer = bunny_queue.subscribe
|
160
|
-
|
145
|
+
@consumer = bunny_queue.subscribe manual_ack: true do |info, props, body|
|
146
|
+
acknowledge_messages
|
147
|
+
|
148
|
+
handle_message info, props, body
|
161
149
|
|
162
150
|
nil
|
163
151
|
end
|
@@ -172,7 +160,6 @@ module Proletariat
|
|
172
160
|
def stop_consumer
|
173
161
|
@consumer.cancel if @consumer
|
174
162
|
wait_for_acknowledgers if acknowledgers.any?
|
175
|
-
scheduled_retries.each { |r| r.expedite }
|
176
163
|
|
177
164
|
nil
|
178
165
|
end
|
@@ -194,34 +181,36 @@ module Proletariat
|
|
194
181
|
# Internal: Used to watch the state of dispatched Work and send ack/nack
|
195
182
|
# to a RabbitMQ channel.
|
196
183
|
class Acknowledger
|
184
|
+
include Concerns::Logging
|
185
|
+
|
197
186
|
# Public: Maximum time in seconds to wait synchronously for an
|
198
187
|
# acknowledgement.
|
199
188
|
MAX_BLOCK_TIME = 5
|
200
189
|
|
201
190
|
# Public: Creates a new Acknowledger instance.
|
202
191
|
#
|
203
|
-
#
|
192
|
+
# ivar - A ivar-like object holding the Worker response.
|
204
193
|
# delivery_tag - The RabbitMQ delivery tag for ack/nacking.
|
205
|
-
#
|
206
|
-
#
|
207
|
-
def initialize(
|
208
|
-
@
|
194
|
+
# message - The original message; for exception handling.
|
195
|
+
# exception_handler - A reference to an ExceptionHandler.
|
196
|
+
def initialize(ivar, delivery_tag, message, exception_handler)
|
197
|
+
@ivar = ivar
|
209
198
|
@delivery_tag = delivery_tag
|
210
|
-
@
|
211
|
-
@
|
199
|
+
@message = message
|
200
|
+
@exception_handler = exception_handler
|
212
201
|
end
|
213
202
|
|
214
|
-
# Public: Retrieves the value from the
|
203
|
+
# Public: Retrieves the value from the ivar and sends the relevant
|
215
204
|
# acknowledgement on a given channel. Logs a warning if the
|
216
|
-
#
|
205
|
+
# ivar value is unexpected.
|
217
206
|
#
|
218
207
|
# channel - The Bunny::Channel to receive the acknowledgement.
|
219
208
|
#
|
220
209
|
# Returns nil.
|
221
210
|
def acknowledge_on_channel(channel)
|
222
|
-
if
|
211
|
+
if ivar.fulfilled?
|
223
212
|
acknowledge_success(channel)
|
224
|
-
elsif
|
213
|
+
elsif ivar.rejected?
|
225
214
|
acknowledge_error(channel)
|
226
215
|
end
|
227
216
|
|
@@ -234,17 +223,17 @@ module Proletariat
|
|
234
223
|
#
|
235
224
|
# Returns nil.
|
236
225
|
def block_until_acknowledged(channel)
|
237
|
-
|
226
|
+
ivar.wait(MAX_BLOCK_TIME)
|
238
227
|
acknowledge_on_channel(channel)
|
239
228
|
|
240
229
|
nil
|
241
230
|
end
|
242
231
|
|
243
|
-
# Public: Gets the readiness of the
|
232
|
+
# Public: Gets the readiness of the ivar for acknowledgement use.
|
244
233
|
#
|
245
|
-
# Returns true if
|
234
|
+
# Returns true if ivar is fulfilled or rejected.
|
246
235
|
def ready_to_acknowledge?
|
247
|
-
|
236
|
+
ivar.completed?
|
248
237
|
end
|
249
238
|
|
250
239
|
private
|
@@ -256,8 +245,8 @@ module Proletariat
|
|
256
245
|
#
|
257
246
|
# Returns nil.
|
258
247
|
def acknowledge_success(channel)
|
259
|
-
case
|
260
|
-
when :ok then channel.
|
248
|
+
case ivar.value
|
249
|
+
when :ok then channel.ack delivery_tag
|
261
250
|
when :drop then channel.reject delivery_tag, false
|
262
251
|
when :requeue then channel.reject delivery_tag, true
|
263
252
|
else
|
@@ -275,10 +264,10 @@ module Proletariat
|
|
275
264
|
#
|
276
265
|
# Returns nil.
|
277
266
|
def acknowledge_error(channel)
|
278
|
-
Proletariat.logger.error
|
267
|
+
Proletariat.logger.error ivar.reason
|
279
268
|
|
280
|
-
|
281
|
-
channel.
|
269
|
+
exception_handler << message
|
270
|
+
channel.ack delivery_tag
|
282
271
|
|
283
272
|
nil
|
284
273
|
end
|
@@ -286,89 +275,14 @@ module Proletariat
|
|
286
275
|
# Internal: Returns the RabbitMQ delivery tag.
|
287
276
|
attr_reader :delivery_tag
|
288
277
|
|
289
|
-
# Internal: Returns the
|
290
|
-
attr_reader :
|
291
|
-
|
292
|
-
# Internal: Returns the original message properties.
|
293
|
-
attr_reader :properties
|
294
|
-
|
295
|
-
# Internal: Returns the Array of Retrys.
|
296
|
-
attr_reader :scheduled_retries
|
297
|
-
|
298
|
-
# Internal: Used publish an exponential delayed requeue for failures.
|
299
|
-
class Retry
|
300
|
-
# Public: Creates a new Retry instance. Sets appropriate headers for
|
301
|
-
# requeue message.
|
302
|
-
#
|
303
|
-
# properties - The original message properties.
|
304
|
-
def initialize(properties)
|
305
|
-
@properties = properties
|
278
|
+
# Internal: Returns the ExceptionHandler reference.
|
279
|
+
attr_reader :exception_handler
|
306
280
|
|
307
|
-
|
308
|
-
|
281
|
+
# Internal: Returns the ivar-like object holding the Worker response.
|
282
|
+
attr_reader :ivar
|
309
283
|
|
310
|
-
|
311
|
-
|
312
|
-
end
|
313
|
-
|
314
|
-
@scheduled_task.execute
|
315
|
-
end
|
316
|
-
|
317
|
-
# Public: Attempt to requeue the message immediately if pending or
|
318
|
-
# wait for natural completion.
|
319
|
-
#
|
320
|
-
# Returns nil.
|
321
|
-
def expedite
|
322
|
-
if scheduled_task.cancel
|
323
|
-
requeue_message
|
324
|
-
else
|
325
|
-
scheduled_task.value
|
326
|
-
end
|
327
|
-
|
328
|
-
nil
|
329
|
-
end
|
330
|
-
|
331
|
-
# Public: Tests whether the message has been requeued.
|
332
|
-
#
|
333
|
-
# Returns a Boolean.
|
334
|
-
def requeued?
|
335
|
-
scheduled_task.fulfilled?
|
336
|
-
end
|
337
|
-
|
338
|
-
private
|
339
|
-
|
340
|
-
# Internal: Returns the original message properties.
|
341
|
-
attr_reader :properties
|
342
|
-
|
343
|
-
# Internal: Returns the ScheduledTask which will requeue the message.
|
344
|
-
attr_reader :scheduled_task
|
345
|
-
|
346
|
-
# Internal: Fetches the current number of message failures from the
|
347
|
-
# headers. Defaults to 1.
|
348
|
-
#
|
349
|
-
# Returns a Fixnum.
|
350
|
-
def failures
|
351
|
-
@failures ||= (properties[:headers]['failures'] || 0) + 1
|
352
|
-
end
|
353
|
-
|
354
|
-
# Internal: Performs the actual message requeue.
|
355
|
-
#
|
356
|
-
# Returns nil.
|
357
|
-
def requeue_message
|
358
|
-
Proletariat.publish(properties[:key], properties[:message],
|
359
|
-
properties[:headers])
|
360
|
-
|
361
|
-
nil
|
362
|
-
end
|
363
|
-
|
364
|
-
# Internal: Calculates an exponential retry delay based on the previous
|
365
|
-
# number of failures. Capped with configuration setting.
|
366
|
-
#
|
367
|
-
# Returns the delay in seconds as a Fixnum.
|
368
|
-
def retry_delay
|
369
|
-
[2**failures, Proletariat.max_retry_delay].min
|
370
|
-
end
|
371
|
-
end
|
284
|
+
# Internal: Returns the original message.
|
285
|
+
attr_reader :message
|
372
286
|
end
|
373
287
|
end
|
374
288
|
end
|