beetle 2.1.2 → 2.2.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/RELEASE_NOTES.rdoc +6 -0
- data/lib/beetle/message.rb +14 -3
- data/lib/beetle/r_c.rb +1 -0
- data/lib/beetle/version.rb +1 -1
- data/test/beetle/message_test.rb +38 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 136ef3ee13c61c833081834cca6ad34323af71328f3ec1f21b6aa412167cf1a2
|
4
|
+
data.tar.gz: 026b2705d3b6d202b756ff6da3b56a385da5dc16453e2099419fe69c7f69905f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 40233f2af492cccd37792173a1541dc6f3bb55c59a1709fec2d2fb437ff62d12e3ff6d0243284a142dd0b8d51dacf2e5d2b45afd2bd244e8f5eae6dbdbd81257
|
7
|
+
data.tar.gz: 4dc724d9f5566102642191bc0628b83fc9b933f6a03418b5f9e5dbb0433e66ec8d6450d91d3ba7593d4436b91d5511a297287db393970d4aba30d5856cd269fb
|
data/RELEASE_NOTES.rdoc
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
= Release Notes
|
2
2
|
|
3
|
+
== Version 2.2.0
|
4
|
+
|
5
|
+
* Support specifying a whitelist of retriable exceptions when registering a
|
6
|
+
message handler. Exceptions which are not on the list will be regarded as
|
7
|
+
irrecoverable failures.
|
8
|
+
|
3
9
|
== Version 2.1.2
|
4
10
|
|
5
11
|
* Fixed that redis key GC would never complete when a key scheduled
|
data/lib/beetle/message.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require "timeout"
|
2
2
|
|
3
3
|
module Beetle
|
4
|
-
# Instances of class Message are created when a
|
4
|
+
# Instances of class Message are created when a subscription callback fires. Class
|
5
5
|
# Message contains the code responsible for message deduplication and determining if it
|
6
6
|
# should retry executing the message handler after a handler has crashed (or forcefully
|
7
7
|
# aborted).
|
@@ -52,6 +52,8 @@ module Beetle
|
|
52
52
|
attr_reader :attempts_limit
|
53
53
|
# how many exceptions we should tolerate before giving up
|
54
54
|
attr_reader :exceptions_limit
|
55
|
+
# array of exceptions accepted to be rescued and retried
|
56
|
+
attr_reader :retry_on
|
55
57
|
# exception raised by handler execution
|
56
58
|
attr_reader :exception
|
57
59
|
# value returned by handler execution
|
@@ -72,6 +74,7 @@ module Beetle
|
|
72
74
|
@attempts_limit = opts[:attempts] || DEFAULT_HANDLER_EXECUTION_ATTEMPTS
|
73
75
|
@exceptions_limit = opts[:exceptions] || DEFAULT_EXCEPTION_LIMIT
|
74
76
|
@attempts_limit = @exceptions_limit + 1 if @attempts_limit <= @exceptions_limit
|
77
|
+
@retry_on = opts[:retry_on] || nil
|
75
78
|
@store = opts[:store]
|
76
79
|
max_delay = opts[:max_delay] || @delay
|
77
80
|
@max_delay = max_delay if max_delay >= 2*@delay
|
@@ -79,7 +82,6 @@ module Beetle
|
|
79
82
|
|
80
83
|
# extracts various values from the AMQP header properties
|
81
84
|
def decode #:nodoc:
|
82
|
-
# p header.attributes
|
83
85
|
amqp_headers = header.attributes
|
84
86
|
@uuid = amqp_headers[:message_id]
|
85
87
|
@timestamp = amqp_headers[:timestamp]
|
@@ -138,7 +140,7 @@ module Beetle
|
|
138
140
|
Time.now.to_i
|
139
141
|
end
|
140
142
|
|
141
|
-
# a message has expired if the header expiration timestamp is
|
143
|
+
# a message has expired if the header expiration timestamp is smaller than the current time
|
142
144
|
def expired?
|
143
145
|
@expires_at < now
|
144
146
|
end
|
@@ -218,6 +220,10 @@ module Beetle
|
|
218
220
|
@store.get(msg_id, :exceptions).to_i > exceptions_limit
|
219
221
|
end
|
220
222
|
|
223
|
+
def exception_accepted?
|
224
|
+
@exception.nil? || retry_on.nil? || retry_on.any?{ |klass| @exception.is_a? klass}
|
225
|
+
end
|
226
|
+
|
221
227
|
# have we already seen this message? if not, set the status to "incomplete" and store
|
222
228
|
# the message exipration timestamp in the deduplication store.
|
223
229
|
def key_exists?
|
@@ -347,6 +353,11 @@ module Beetle
|
|
347
353
|
ack!
|
348
354
|
logger.debug "Beetle: reached the handler exceptions limit: #{exceptions_limit} on #{msg_id}"
|
349
355
|
RC::ExceptionsLimitReached
|
356
|
+
elsif !exception_accepted?
|
357
|
+
completed!
|
358
|
+
ack!
|
359
|
+
logger.debug "Beetle: `#{@exception.class.name}` not accepted: `retry_on`=[#{retry_on.join(',')}] on #{msg_id}"
|
360
|
+
RC::ExceptionNotAccepted
|
350
361
|
else
|
351
362
|
delete_mutex!
|
352
363
|
timed_out!
|
data/lib/beetle/r_c.rb
CHANGED
data/lib/beetle/version.rb
CHANGED
data/test/beetle/message_test.rb
CHANGED
@@ -345,7 +345,7 @@ module Beetle
|
|
345
345
|
assert_equal "52", @store.get(message.msg_id, :delay)
|
346
346
|
end
|
347
347
|
|
348
|
-
test "a message should delete the mutex before resetting the timer if attempts and exception limits
|
348
|
+
test "a message should delete the mutex before resetting the timer if attempts and exception limits haven't been reached" do
|
349
349
|
Message.stubs(:now).returns(9)
|
350
350
|
header = header_with_params({})
|
351
351
|
message = Message.new("somequeue", header, 'foo', :delay => 42, :timeout => 10.seconds, :exceptions => 1, :store => @store)
|
@@ -377,6 +377,41 @@ module Beetle
|
|
377
377
|
assert_equal RC::ExceptionsLimitReached, message.__send__(:process_internal, proc)
|
378
378
|
end
|
379
379
|
|
380
|
+
test "a message should not be acked if the handler crashes and the exception has been registered" do
|
381
|
+
header = header_with_params({})
|
382
|
+
RegisteredException = Class.new(StandardError)
|
383
|
+
message = Message.new("somequeue", header, 'foo', :timeout => 10.seconds, :exceptions => 2,
|
384
|
+
:retry_on => [RegisteredException], :store => @store)
|
385
|
+
assert !message.attempts_limit_reached?
|
386
|
+
assert !message.exceptions_limit_reached?
|
387
|
+
assert !message.timed_out?
|
388
|
+
assert !message.simple?
|
389
|
+
assert message.exception_accepted? # @exception yet nil, hence 'accepted'
|
390
|
+
|
391
|
+
proc = lambda {|_| raise RegisteredException, "crash"}
|
392
|
+
message.expects(:completed!).never
|
393
|
+
header.expects(:ack).never
|
394
|
+
assert_equal RC::HandlerCrash, message.__send__(:process_internal, proc)
|
395
|
+
end
|
396
|
+
|
397
|
+
test "a message should be acked if the handler crashes and the exception has not been registered" do
|
398
|
+
header = header_with_params({})
|
399
|
+
RegisteredException = Class.new(StandardError)
|
400
|
+
OtherException = Class.new(StandardError)
|
401
|
+
message = Message.new("somequeue", header, 'foo', :timeout => 10.seconds, :exceptions => 2,
|
402
|
+
:retry_on => [RegisteredException], :store => @store)
|
403
|
+
assert !message.attempts_limit_reached?
|
404
|
+
assert !message.exceptions_limit_reached?
|
405
|
+
assert !message.timed_out?
|
406
|
+
assert !message.simple?
|
407
|
+
assert message.exception_accepted? # @exception yet nil, hence 'accepted'
|
408
|
+
|
409
|
+
proc = lambda {|_| raise OtherException, "crash"}
|
410
|
+
message.expects(:completed!).once
|
411
|
+
header.expects(:ack)
|
412
|
+
assert_equal RC::ExceptionNotAccepted, message.__send__(:process_internal, proc)
|
413
|
+
end
|
414
|
+
|
380
415
|
test "a message should be acked if the handler crashes and the attempts limit has been reached" do
|
381
416
|
header = header_with_params({})
|
382
417
|
message = Message.new("somequeue", header, 'foo', :timeout => 10.seconds, :attempts => 2, :store => @store)
|
@@ -647,8 +682,8 @@ module Beetle
|
|
647
682
|
adapter: "mysql2",
|
648
683
|
username: "root",
|
649
684
|
encoding: "utf8",
|
650
|
-
host: "127.0.0.1",
|
651
|
-
port: 3306
|
685
|
+
host: ENV['MYSQL_HOST'] || "127.0.0.1",
|
686
|
+
port: ENV['MYSQL_PORT'] || 3306
|
652
687
|
)
|
653
688
|
end
|
654
689
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: beetle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stefan Kaes
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2018-
|
15
|
+
date: 2018-07-31 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: uuid4r
|