proletariat 0.0.6 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|