pwwka 0.12.0 → 0.13.0.RC1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +4 -4
- data/README.md +75 -0
- data/lib/pwwka.rb +1 -1
- data/lib/pwwka/configuration.rb +26 -2
- data/lib/pwwka/error_handlers.rb +5 -0
- data/lib/pwwka/error_handlers/base_error_handler.rb +33 -0
- data/lib/pwwka/error_handlers/chain.rb +28 -0
- data/lib/pwwka/error_handlers/crash.rb +11 -0
- data/lib/pwwka/error_handlers/nack_and_ignore.rb +13 -0
- data/lib/pwwka/error_handlers/nack_and_requeue_once.rb +17 -0
- data/lib/pwwka/receiver.rb +10 -25
- data/lib/pwwka/version.rb +1 -1
- data/spec/integration/unhandled_errors_in_receivers_spec.rb +109 -53
- metadata +10 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c804b87530f9d0b29e22b2a10131c8e7ef122cf2
|
4
|
+
data.tar.gz: 0a7b10536a20463505d055ac9797664320a58dbf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c68568f681edce5f795676d3ed340f1d2ae5f52f333c1546c967cc3fa788f71b568b7abfe94b670013c825f0a8cbe8b6399574e9ebc7eddaada252c98f045fc
|
7
|
+
data.tar.gz: 0b61ce8f1fa5c070d11f09b41cf494aaa4e3e32a1793395f498237dfea94feedc267f449ce4b6a31d97bc0fd34592e029cd4b89c4e24849f534fbd28542998b3
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
pwwka (0.
|
4
|
+
pwwka (0.13.0.RC1)
|
5
5
|
activemodel
|
6
6
|
activesupport
|
7
7
|
bunny
|
@@ -10,9 +10,9 @@ PATH
|
|
10
10
|
GEM
|
11
11
|
remote: https://www.rubygems.org/
|
12
12
|
specs:
|
13
|
-
activemodel (5.1.
|
14
|
-
activesupport (= 5.1.
|
15
|
-
activesupport (5.1.
|
13
|
+
activemodel (5.1.4)
|
14
|
+
activesupport (= 5.1.4)
|
15
|
+
activesupport (5.1.4)
|
16
16
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
17
17
|
i18n (~> 0.7)
|
18
18
|
minitest (~> 5.1)
|
data/README.md
CHANGED
@@ -282,6 +282,81 @@ these messages. Some day Pwwka might have code to allow that. Today is not tha
|
|
282
282
|
|
283
283
|
**You should configure `requeue_on_error`**. It's not the default for backwards compatibility.
|
284
284
|
|
285
|
+
#### Advanced Error Handling
|
286
|
+
|
287
|
+
The underlying implementation of how errors are handled is via a [chain of responsibility-ish](https://en.wikipedia.org/wiki/Chain-of-responsibility_pattern) implementation. When an unhandled exception occurs, pwwka's `Receiver`
|
288
|
+
defers to the configurations `error_handling_chain`, which is a list of classes that can handle errors. `requeue_on_error` and `keep_alive_on_handler_klass_exceptions` control which classes are in the chain.
|
289
|
+
|
290
|
+
If you want to handle errors differently, for example crashing on some exceptions, but not others, or requeing messages on failures always (instead of just once), you can do that by subclassing `Pwwka::ErrorHandlers::BaseHandler`.
|
291
|
+
It defines a method `handle_error` that is given the `Receiver` instance, queue name, payload, delivery info, and the uncaught exception. If the method returns `true`, Pwwka calls the remaining handlers. If false, it stops processing.
|
292
|
+
|
293
|
+
Your subclass can be inserted into the chain in two ways. Way #1 is to override the entire chain by setting `Pwwka.configuration.error_handling_chain` to an array of handlers, including yours. Way #2 is to have your specific
|
294
|
+
message handler implement `self.error_handler` to return the class to be used for just that message handler.
|
295
|
+
|
296
|
+
**When you do this**, be careful to ensure you ack or nack. If you fail to do either, your messages will build up and bad things will happen.
|
297
|
+
|
298
|
+
For example, suppose you want to catch an ActiveRecord error, unwrap it to see if it's a problem with the connection, and reconnect before trying again.
|
299
|
+
|
300
|
+
First, implement your custom error handler:
|
301
|
+
|
302
|
+
```ruby
|
303
|
+
class PostgresReconnectHandler < Pwwka::ErrorHandlers::BaseHandler
|
304
|
+
def handle_error(receiver,queue_name,payload,delivery_info,exception)
|
305
|
+
if exception.cause.is_a?(PG::ConnectionBad)
|
306
|
+
ActiveRecord::Base.connection.reconnect!
|
307
|
+
end
|
308
|
+
keep_going
|
309
|
+
end
|
310
|
+
end
|
311
|
+
```
|
312
|
+
|
313
|
+
In your pwwka initializer:
|
314
|
+
|
315
|
+
```ruby
|
316
|
+
require 'pwwka'
|
317
|
+
Pwwka.configure do |config|
|
318
|
+
config.rabbit_mq_host = ENV['RABBITMQ_URL']
|
319
|
+
config.topic_exchange_name = "mycompany-topics-#{Rails.env}"
|
320
|
+
config.delayed_exchange_name = "mycompany-topics-#{Rails.env}"
|
321
|
+
config.options = {allow_delayed: true}
|
322
|
+
config.error_handling_chain = [
|
323
|
+
PostgresReconnectHandler,
|
324
|
+
Pwwka::ErrorHandlers::NackAndRequeueOnce,
|
325
|
+
Pwwka::ErrorHandlers::Crash
|
326
|
+
]
|
327
|
+
end
|
328
|
+
```
|
329
|
+
|
330
|
+
This says:
|
331
|
+
|
332
|
+
* If the error was a `PG::ConnectionBad`, reconnect
|
333
|
+
* If the message has not been retried, nack it and requeue it, otherwise ignore it (`NackAndRequeueOnce`)
|
334
|
+
* Crash the handler
|
335
|
+
|
336
|
+
You might not want to crash the handler in the case of `PG::ConnectionBad`. And, you might want to always retry the job, even if it's been retried before so you don't lose it.
|
337
|
+
|
338
|
+
In that case, your handler could work like this:
|
339
|
+
|
340
|
+
|
341
|
+
```ruby
|
342
|
+
class PostgresReconnectHandler < Pwwka::ErrorHandlers::BaseHandler
|
343
|
+
def handle_error(receiver,queue_name,payload,delivery_info,exception)
|
344
|
+
if exception.cause.is_a?(PG::ConnectionBad)
|
345
|
+
ActiveRecord::Base.connection.reconnect!
|
346
|
+
log("Retrying an Error Processing Message",queue_name,payload,delivery_info,exception)
|
347
|
+
receiver.nack_requeue(delivery_info.delivery_tag)
|
348
|
+
abort_chain
|
349
|
+
else
|
350
|
+
keep_going
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
```
|
355
|
+
|
356
|
+
Now, if we get a `PG::ConnectionBad`, we reconnect, nack with requeue and stop processing the error (`abort_chain` is an alias for `false`, and `keep_going` is an alias for `true`, but they keep you from having to remember what to return).
|
357
|
+
|
358
|
+
**When making your own handlers** it's important to make sure that the message is nacked or acked.**
|
359
|
+
|
285
360
|
#### Handling Messages with Resque
|
286
361
|
|
287
362
|
If you use [Resque][resque], and you wish to handle messages in a resque job, you can use `Pwwka::QueueResqueJobHandler`, which is an adapter between the standard `handle!` method provided by pwwka and your Resque job.
|
data/lib/pwwka.rb
CHANGED
data/lib/pwwka/configuration.rb
CHANGED
@@ -11,9 +11,18 @@ module Pwwka
|
|
11
11
|
attr_accessor :options
|
12
12
|
attr_accessor :async_job_klass
|
13
13
|
attr_accessor :send_message_resque_backoff_strategy
|
14
|
-
|
14
|
+
attr_reader :requeue_on_error
|
15
15
|
attr_writer :app_id
|
16
|
-
attr_writer :
|
16
|
+
attr_writer :error_handling_chain
|
17
|
+
|
18
|
+
def keep_alive_on_handler_klass_exceptions=(val)
|
19
|
+
@keep_alive_on_handler_klass_exceptions = val
|
20
|
+
@error_handling_chain = nil
|
21
|
+
end
|
22
|
+
def requeue_on_error=(val)
|
23
|
+
@requeue_on_error = val
|
24
|
+
@error_handling_chain = nil
|
25
|
+
end
|
17
26
|
|
18
27
|
def initialize
|
19
28
|
@rabbit_mq_host = nil
|
@@ -61,5 +70,20 @@ module Pwwka
|
|
61
70
|
options[:allow_delayed]
|
62
71
|
end
|
63
72
|
|
73
|
+
def error_handling_chain
|
74
|
+
@error_handling_chain ||= begin
|
75
|
+
klasses = []
|
76
|
+
if requeue_on_error
|
77
|
+
klasses << Pwwka::ErrorHandlers::NackAndRequeueOnce
|
78
|
+
else
|
79
|
+
klasses << Pwwka::ErrorHandlers::NackAndIgnore
|
80
|
+
end
|
81
|
+
unless Pwwka.configuration.keep_alive_on_handler_klass_exceptions?
|
82
|
+
klasses << Pwwka::ErrorHandlers::Crash
|
83
|
+
end
|
84
|
+
klasses
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
64
88
|
end
|
65
89
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Pwwka
|
2
|
+
module ErrorHandlers
|
3
|
+
class BaseErrorHandler
|
4
|
+
include Pwwka::Logging
|
5
|
+
def handle_error(receiver,queue_name,payload,delivery_info,exception)
|
6
|
+
raise "subclass must implement"
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def log(message,queue_name,payload,delivery_info,exception)
|
12
|
+
logf "%{message} on %{queue_name} -> %{payload}, %{routing_key}: %{exception}: %{backtrace}", {
|
13
|
+
message: message,
|
14
|
+
queue_name: queue_name,
|
15
|
+
payload: payload,
|
16
|
+
routing_key: delivery_info.routing_key,
|
17
|
+
exception: exception,
|
18
|
+
backtrace: exception.backtrace.join(";"),
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
# Subclasses can call these methods instead of
|
23
|
+
# using true/false to more clearly indicate their intent
|
24
|
+
def keep_going
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
def abort_chain
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Pwwka
|
2
|
+
module ErrorHandlers
|
3
|
+
# Given a chain of error handlers, calls them until either
|
4
|
+
# one returns false/aborts or we exhaust the chain of handlers
|
5
|
+
class Chain
|
6
|
+
include Pwwka::Logging
|
7
|
+
def initialize(default_handler_chain=[])
|
8
|
+
@error_handlers = default_handler_chain
|
9
|
+
end
|
10
|
+
def handle_error(message_handler_klass,receiver,queue_name,payload,delivery_info,exception)
|
11
|
+
if message_handler_klass.respond_to?(:error_handler)
|
12
|
+
@error_handlers.unshift(message_handler_klass.send(:error_handler))
|
13
|
+
end
|
14
|
+
@error_handlers.reduce(true) { |keep_going,error_handler|
|
15
|
+
if keep_going
|
16
|
+
keep_going = error_handler.new.handle_error(receiver,queue_name,payload,delivery_info,exception)
|
17
|
+
unless keep_going
|
18
|
+
logf "%{error_handler_class} has halted to error-handling chain", error_handler_class: error_handler.class
|
19
|
+
end
|
20
|
+
else
|
21
|
+
logf "Skipping %{error_handler_class} as we were asked to abort previously", error_handler_class: error_handler.class
|
22
|
+
end
|
23
|
+
keep_going
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require_relative "base_error_handler"
|
2
|
+
module Pwwka
|
3
|
+
module ErrorHandlers
|
4
|
+
class Crash < BaseErrorHandler
|
5
|
+
def handle_error(receiver,queue_name,payload,delivery_info,e)
|
6
|
+
raise Interrupt,"Exiting due to exception #{e.inspect}"
|
7
|
+
abort_chain
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative "base_error_handler"
|
2
|
+
module Pwwka
|
3
|
+
module ErrorHandlers
|
4
|
+
class NackAndIgnore < BaseErrorHandler
|
5
|
+
def handle_error(receiver,queue_name,payload,delivery_info,exception)
|
6
|
+
log("Error Processing Message",queue_name,payload,delivery_info,exception)
|
7
|
+
receiver.nack(delivery_info.delivery_tag)
|
8
|
+
keep_going
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative "base_error_handler"
|
2
|
+
module Pwwka
|
3
|
+
module ErrorHandlers
|
4
|
+
class NackAndRequeueOnce < BaseErrorHandler
|
5
|
+
def handle_error(receiver,queue_name,payload,delivery_info,exception)
|
6
|
+
if delivery_info.redelivered
|
7
|
+
log("Error Processing Message",queue_name,payload,delivery_info,exception)
|
8
|
+
receiver.nack(delivery_info.delivery_tag)
|
9
|
+
else
|
10
|
+
log("Retrying an Error Processing Message",queue_name,payload,delivery_info,exception)
|
11
|
+
receiver.nack_requeue(delivery_info.delivery_tag)
|
12
|
+
end
|
13
|
+
keep_going
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/pwwka/receiver.rb
CHANGED
@@ -28,23 +28,16 @@ module Pwwka
|
|
28
28
|
handler_klass.handle!(delivery_info, properties, payload)
|
29
29
|
receiver.ack(delivery_info.delivery_tag)
|
30
30
|
logf "Processed Message on %{queue_name} -> %{payload}, %{routing_key}", queue_name: queue_name, payload: payload, routing_key: delivery_info.routing_key
|
31
|
-
rescue =>
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
else
|
42
|
-
log_error "Error Processing Message", error_options
|
43
|
-
receiver.nack(delivery_info.delivery_tag)
|
44
|
-
end
|
45
|
-
unless Pwwka.configuration.keep_alive_on_handler_klass_exceptions?
|
46
|
-
raise Interrupt,"Exiting due to exception #{e.inspect}"
|
47
|
-
end
|
31
|
+
rescue => exception
|
32
|
+
Pwwka::ErrorHandlers::Chain.new(
|
33
|
+
Pwwka.configuration.error_handling_chain
|
34
|
+
).handle_error(
|
35
|
+
handler_klass,
|
36
|
+
receiver,
|
37
|
+
queue_name,
|
38
|
+
payload,
|
39
|
+
delivery_info,
|
40
|
+
exception)
|
48
41
|
end
|
49
42
|
end
|
50
43
|
rescue Interrupt => _
|
@@ -86,13 +79,5 @@ module Pwwka
|
|
86
79
|
channel_connector.connection_close
|
87
80
|
end
|
88
81
|
|
89
|
-
private
|
90
|
-
|
91
|
-
def self.log_error(message,options)
|
92
|
-
options[:message] = message
|
93
|
-
options[:backtrace] = options.fetch(:exception).backtrace.join(';')
|
94
|
-
logf "%{message} on %{queue_name} -> %{payload}, %{routing_key}: %{exception}: %{backtrace}", options
|
95
|
-
end
|
96
|
-
|
97
82
|
end
|
98
83
|
end
|
data/lib/pwwka/version.rb
CHANGED
@@ -8,88 +8,126 @@ describe "receivers with unhandled errors", :integration do
|
|
8
8
|
|
9
9
|
before do
|
10
10
|
@testing_setup = IntegrationTestSetup.new
|
11
|
-
setup_receivers
|
12
11
|
Pwwka.configure do |c|
|
13
12
|
c.requeue_on_error = false
|
14
13
|
c.keep_alive_on_handler_klass_exceptions = false
|
15
14
|
end
|
16
15
|
end
|
17
16
|
|
18
|
-
before :each do
|
19
|
-
WellBehavedReceiver.reset!
|
20
|
-
ExceptionThrowingReceiver.reset!
|
21
|
-
IntermittentErrorReceiver.reset!
|
22
|
-
end
|
23
|
-
|
24
17
|
after do
|
25
18
|
@testing_setup.kill_threads_and_clear_queues
|
26
19
|
end
|
27
20
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
21
|
+
context "default configuration to crash on errors" do
|
22
|
+
before do
|
23
|
+
setup_receivers
|
24
|
+
WellBehavedReceiver.reset!
|
25
|
+
ExceptionThrowingReceiver.reset!
|
26
|
+
IntermittentErrorReceiver.reset!
|
27
|
+
ExceptionThrowingReceiverWithErrorHook.reset!
|
28
|
+
end
|
32
29
|
|
33
|
-
|
34
|
-
|
35
|
-
|
30
|
+
it "an error in one receiver doesn't prevent others from getting messages" do
|
31
|
+
Pwwka::Transmitter.send_message!({ sample: "payload", has: { deeply: true, nested: 4 }},
|
32
|
+
"pwwka.testing.foo")
|
33
|
+
allow_receivers_to_process_queues
|
36
34
|
|
37
|
-
|
38
|
-
|
39
|
-
c.requeue_on_error = true
|
40
|
-
c.keep_alive_on_handler_klass_exceptions = true # only so we can check that the requeued message got sent; otherwise the receiver crashes and we can't test that
|
35
|
+
expect(WellBehavedReceiver.messages_received.size).to eq(1)
|
36
|
+
expect(ExceptionThrowingReceiver.messages_received.size).to eq(1)
|
41
37
|
end
|
42
|
-
|
43
|
-
|
44
|
-
|
38
|
+
it "crashes the receiver that received an error" do
|
39
|
+
Pwwka::Transmitter.send_message!({ sample: "payload", has: { deeply: true, nested: 4 }},
|
40
|
+
"pwwka.testing.foo")
|
41
|
+
allow_receivers_to_process_queues
|
45
42
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
43
|
+
expect(@testing_setup.threads[ExceptionThrowingReceiver].alive?).to eq(false)
|
44
|
+
end
|
45
|
+
it "does not crash the receiver that successfully processed a message" do
|
46
|
+
Pwwka::Transmitter.send_message!({ sample: "payload", has: { deeply: true, nested: 4 }},
|
47
|
+
"pwwka.testing.foo")
|
48
|
+
allow_receivers_to_process_queues
|
49
|
+
|
50
|
+
expect(@testing_setup.threads[WellBehavedReceiver].alive?).to eq(true)
|
51
|
+
end
|
51
52
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
it "crashes the receiver if it gets a failure that we retry" do
|
54
|
+
Pwwka.configure do |c|
|
55
|
+
c.requeue_on_error = true
|
56
|
+
end
|
57
|
+
Pwwka::Transmitter.send_message!({ sample: "payload", has: { deeply: true, nested: 4 }},
|
58
|
+
"pwwka.testing.foo")
|
59
|
+
allow_receivers_to_process_queues
|
56
60
|
|
57
|
-
|
61
|
+
expect(@testing_setup.threads[IntermittentErrorReceiver].alive?).to eq(false)
|
62
|
+
end
|
58
63
|
end
|
59
64
|
|
60
|
-
|
61
|
-
|
62
|
-
|
65
|
+
context "configured not to crash on error" do
|
66
|
+
before do
|
67
|
+
setup_receivers
|
68
|
+
WellBehavedReceiver.reset!
|
69
|
+
ExceptionThrowingReceiver.reset!
|
70
|
+
IntermittentErrorReceiver.reset!
|
71
|
+
ExceptionThrowingReceiverWithErrorHook.reset!
|
63
72
|
end
|
64
|
-
|
65
|
-
|
66
|
-
|
73
|
+
it "does not crash the receiver that received an error" do
|
74
|
+
Pwwka.configure do |c|
|
75
|
+
c.keep_alive_on_handler_klass_exceptions = true
|
76
|
+
end
|
77
|
+
Pwwka::Transmitter.send_message!({ sample: "payload", has: { deeply: true, nested: 4 }},
|
78
|
+
"pwwka.testing.foo")
|
79
|
+
allow_receivers_to_process_queues
|
67
80
|
|
68
|
-
|
81
|
+
expect(@testing_setup.threads[ExceptionThrowingReceiver].alive?).to eq(true)
|
82
|
+
end
|
69
83
|
end
|
70
84
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
85
|
+
context "configured to requeue failed messages" do
|
86
|
+
before do
|
87
|
+
setup_receivers
|
88
|
+
WellBehavedReceiver.reset!
|
89
|
+
ExceptionThrowingReceiver.reset!
|
90
|
+
IntermittentErrorReceiver.reset!
|
91
|
+
ExceptionThrowingReceiverWithErrorHook.reset!
|
92
|
+
end
|
93
|
+
it "requeues the message exactly once" do
|
94
|
+
Pwwka.configure do |c|
|
95
|
+
c.requeue_on_error = true
|
96
|
+
c.keep_alive_on_handler_klass_exceptions = true # only so we can check that the requeued message got sent; otherwise the receiver crashes and we can't test that
|
97
|
+
end
|
98
|
+
Pwwka::Transmitter.send_message!({ sample: "payload", has: { deeply: true, nested: 4 }},
|
99
|
+
"pwwka.testing.foo")
|
100
|
+
allow_receivers_to_process_queues
|
101
|
+
|
102
|
+
expect(WellBehavedReceiver.messages_received.size).to eq(1)
|
103
|
+
expect(ExceptionThrowingReceiver.messages_received.size).to eq(2)
|
104
|
+
expect(ExceptionThrowingReceiver.messages_received[1][0].redelivered).to eq(true)
|
105
|
+
expect(ExceptionThrowingReceiver.messages_received[1][2]).to eq(ExceptionThrowingReceiver.messages_received[0][2])
|
106
|
+
end
|
77
107
|
end
|
78
108
|
|
79
|
-
|
80
|
-
|
81
|
-
|
109
|
+
context "handler with a custom error handler that ignores the exception" do
|
110
|
+
before do
|
111
|
+
setup_receivers(ExceptionThrowingReceiverWithErrorHook)
|
112
|
+
WellBehavedReceiver.reset!
|
113
|
+
ExceptionThrowingReceiver.reset!
|
114
|
+
IntermittentErrorReceiver.reset!
|
115
|
+
ExceptionThrowingReceiverWithErrorHook.reset!
|
82
116
|
end
|
83
|
-
Pwwka::Transmitter.send_message!({ sample: "payload", has: { deeply: true, nested: 4 }},
|
84
|
-
"pwwka.testing.foo")
|
85
|
-
allow_receivers_to_process_queues
|
86
117
|
|
87
|
-
|
118
|
+
it "does not crash the receiver" do
|
119
|
+
Pwwka::Transmitter.send_message!({ sample: "payload", has: { deeply: true, nested: 4 }},
|
120
|
+
"pwwka.testing.foo")
|
121
|
+
allow_receivers_to_process_queues
|
122
|
+
|
123
|
+
expect(ExceptionThrowingReceiverWithErrorHook.messages_received.size).to eq(1)
|
124
|
+
expect(@testing_setup.threads[ExceptionThrowingReceiverWithErrorHook].alive?).to eq(true)
|
125
|
+
end
|
88
126
|
end
|
89
127
|
|
90
|
-
def setup_receivers
|
128
|
+
def setup_receivers(exception_throwing_receiver_klass=ExceptionThrowingReceiver)
|
91
129
|
[
|
92
|
-
[
|
130
|
+
[exception_throwing_receiver_klass, "exception_throwing_receiver_pwwkatesting"],
|
93
131
|
[WellBehavedReceiver, "well_behaved_receiver_pwwkatesting"],
|
94
132
|
[IntermittentErrorReceiver, "intermittent_error_receiver_pwwkatesting"],
|
95
133
|
].each do |(klass, queue_name)|
|
@@ -102,6 +140,24 @@ describe "receivers with unhandled errors", :integration do
|
|
102
140
|
raise "OH NOES!"
|
103
141
|
end
|
104
142
|
end
|
143
|
+
class NoOpHandler < Pwwka::ErrorHandlers::BaseErrorHandler
|
144
|
+
def initialize(*)
|
145
|
+
end
|
146
|
+
def handle_error(receiver,queue_name,payload,delivery_info,exception)
|
147
|
+
receiver.nack(delivery_info.delivery_tag)
|
148
|
+
abort_chain
|
149
|
+
end
|
150
|
+
end
|
151
|
+
class ExceptionThrowingReceiverWithErrorHook < LoggingReceiver
|
152
|
+
def self.error_handler
|
153
|
+
NoOpHandler
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.handle!(delivery_info,properties,payload)
|
157
|
+
super(delivery_info,properties,payload)
|
158
|
+
raise "OH NOES!"
|
159
|
+
end
|
160
|
+
end
|
105
161
|
class IntermittentErrorReceiver < LoggingReceiver
|
106
162
|
def self.handle!(delivery_info,properties,payload)
|
107
163
|
super(delivery_info,properties,payload)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pwwka
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.13.0.RC1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stitch Fix Engineering
|
@@ -15,7 +15,7 @@ authors:
|
|
15
15
|
autorequire:
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
|
-
date: 2017-09-
|
18
|
+
date: 2017-09-21 00:00:00.000000000 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: bunny
|
@@ -206,6 +206,12 @@ files:
|
|
206
206
|
- lib/pwwka.rb
|
207
207
|
- lib/pwwka/channel_connector.rb
|
208
208
|
- lib/pwwka/configuration.rb
|
209
|
+
- lib/pwwka/error_handlers.rb
|
210
|
+
- lib/pwwka/error_handlers/base_error_handler.rb
|
211
|
+
- lib/pwwka/error_handlers/chain.rb
|
212
|
+
- lib/pwwka/error_handlers/crash.rb
|
213
|
+
- lib/pwwka/error_handlers/nack_and_ignore.rb
|
214
|
+
- lib/pwwka/error_handlers/nack_and_requeue_once.rb
|
209
215
|
- lib/pwwka/handling.rb
|
210
216
|
- lib/pwwka/logging.rb
|
211
217
|
- lib/pwwka/message_queuer.rb
|
@@ -254,9 +260,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
254
260
|
version: '0'
|
255
261
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
256
262
|
requirements:
|
257
|
-
- - "
|
263
|
+
- - ">"
|
258
264
|
- !ruby/object:Gem::Version
|
259
|
-
version:
|
265
|
+
version: 1.3.1
|
260
266
|
requirements: []
|
261
267
|
rubyforge_project:
|
262
268
|
rubygems_version: 2.6.13
|