beetle 3.3.0.rc1 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/RELEASE_NOTES.rdoc +4 -2
- data/lib/beetle/configuration.rb +6 -8
- data/lib/beetle/deduplication_store.rb +6 -3
- data/lib/beetle/version.rb +1 -1
- data/test/beetle/message_test.rb +58 -1
- data/test/beetle/publisher_test.rb +22 -0
- 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: 3e1e8a0378a54fd5b151e8a85fe404d74b06bc0e33458e632676bb5b60b7b38d
|
4
|
+
data.tar.gz: 546a4383cdc3727eb9709ea6ef30647cfc647c803e5be9853b77b50b70c915c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d307e9c99eaafc64463e2fc5b21b3b9b4a04a831b3eb74d0330f86411412dc01f4f3e0a3e059695d5cfbd2b94b527352549fbaf4e5ebd4c8f28acdce79b25dcb
|
7
|
+
data.tar.gz: a285335c8023bda35630fbe01162d5cd5e196fc60576c827f3f05e099d9f5c3e35608d7819d996de849c9f25e3619a33de90a2cca3704fab11636f3ec6645d0f
|
data/RELEASE_NOTES.rdoc
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
= Release Notes
|
2
2
|
|
3
|
-
== Version 3.3.0
|
3
|
+
== Version 3.3.0
|
4
4
|
* protect against duplicate handler execution by keeping the status of
|
5
5
|
handler exectution for both redundant and non-redundant messages in
|
6
6
|
the dedup store for a configurable time window. The config option
|
7
7
|
is named redis_status_key_expiry_interval. Note that this will
|
8
8
|
significantly increase the cpu load and memory usage of the Redis
|
9
|
-
server for applications using a large number of non-redundant
|
9
|
+
server for applications using a large number of non-redundant
|
10
|
+
messages. This feature is turned off by default, but we will
|
11
|
+
activate it with the next major release (4.0.0).
|
10
12
|
|
11
13
|
== Version 3.2.0
|
12
14
|
* added currently processed message to the handler pre-processing step
|
data/lib/beetle/configuration.rb
CHANGED
@@ -37,13 +37,11 @@ module Beetle
|
|
37
37
|
# handler timeout.
|
38
38
|
attr_accessor :redis_failover_timeout
|
39
39
|
|
40
|
-
# how long we want status keys to survive after we have seen the second message of a
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
# and the RabbitMQ instance. This happens extremely seldom in our environment, but we cannot
|
46
|
-
# rule it out and we also don't quite understand (yet) why it happens.
|
40
|
+
# how long we want status keys to survive after we have seen the second message of a redundant
|
41
|
+
# message pair. Defaults to 0 seconds, but will be set to something non-zero with the next
|
42
|
+
# major beetle release. A recommended value would be 5 minutes (300 seconds). Setting this to a
|
43
|
+
# high value (hours) will reduce the likelihood of executing handler logic more than once, but
|
44
|
+
# can cause a higher redis database size with all associated problems.
|
47
45
|
attr_accessor :redis_status_key_expiry_interval
|
48
46
|
|
49
47
|
# how often heartbeat messages are exchanged between failover
|
@@ -151,7 +149,7 @@ module Beetle
|
|
151
149
|
self.redis_servers = ""
|
152
150
|
self.redis_db = 4
|
153
151
|
self.redis_failover_timeout = 180.seconds
|
154
|
-
self.redis_status_key_expiry_interval =
|
152
|
+
self.redis_status_key_expiry_interval = 0.seconds
|
155
153
|
self.redis_failover_client_heartbeat_interval = 10.seconds
|
156
154
|
self.redis_failover_client_dead_interval = 60.seconds
|
157
155
|
|
@@ -62,12 +62,14 @@ module Beetle
|
|
62
62
|
# store completion status for given <tt>msg_id</tt> if it doesn't exist yet. Returns whether the
|
63
63
|
# operation was successful.
|
64
64
|
def setnx_completed!(msg_id)
|
65
|
+
expiry = @config.redis_status_key_expiry_interval
|
66
|
+
return true if expiry == 0
|
65
67
|
with_failover do
|
66
68
|
redis.set(
|
67
69
|
key(msg_id, :status),
|
68
70
|
"completed",
|
69
71
|
:nx => true,
|
70
|
-
:ex =>
|
72
|
+
:ex => expiry,
|
71
73
|
)
|
72
74
|
end
|
73
75
|
end
|
@@ -107,11 +109,12 @@ module Beetle
|
|
107
109
|
|
108
110
|
# delete all keys associated with the given <tt>msg_id</tt>.
|
109
111
|
def del_keys(msg_id)
|
112
|
+
expiry = @config.redis_status_key_expiry_interval
|
110
113
|
keys = keys(msg_id)
|
111
|
-
status_key = keys.shift
|
114
|
+
status_key = keys.shift if expiry > 0
|
112
115
|
with_failover do
|
113
116
|
redis.del(*keys)
|
114
|
-
redis.expire(status_key,
|
117
|
+
redis.expire(status_key, expiry) if expiry > 0
|
115
118
|
end
|
116
119
|
end
|
117
120
|
|
data/lib/beetle/version.rb
CHANGED
data/test/beetle/message_test.rb
CHANGED
@@ -129,7 +129,24 @@ module Beetle
|
|
129
129
|
end
|
130
130
|
end
|
131
131
|
|
132
|
+
test "successful processing of a non redundant message should delete all keys from the database" do
|
133
|
+
header = header_with_params({})
|
134
|
+
header.expects(:ack)
|
135
|
+
message = Message.new("somequeue", header, 'foo', :store => @store)
|
136
|
+
message.stubs(:simple?).returns(false)
|
137
|
+
|
138
|
+
assert !message.expired?
|
139
|
+
assert !message.redundant?
|
140
|
+
|
141
|
+
message.process(@null_handler)
|
142
|
+
keys = @store.keys(message.msg_id)
|
143
|
+
keys.each do |key|
|
144
|
+
assert !@store.redis.exists(key)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
132
148
|
test "successful processing of a non redundant message should delete all keys from the database (except the status key, which should be set to expire)" do
|
149
|
+
@config.redis_status_key_expiry_interval = 1.minutes
|
133
150
|
header = header_with_params({})
|
134
151
|
header.expects(:ack)
|
135
152
|
message = Message.new("somequeue", header, 'foo', :store => @store)
|
@@ -148,7 +165,26 @@ module Beetle
|
|
148
165
|
end
|
149
166
|
end
|
150
167
|
|
168
|
+
test "successful processing of a redundant message twice should delete all keys from the database" do
|
169
|
+
header = header_with_params({:redundant => true})
|
170
|
+
header.expects(:ack).twice
|
171
|
+
message = Message.new("somequeue", header, 'foo', :store => @store)
|
172
|
+
|
173
|
+
assert !message.expired?
|
174
|
+
assert message.redundant?
|
175
|
+
assert !message.simple?
|
176
|
+
|
177
|
+
message.process(@null_handler)
|
178
|
+
message.process(@null_handler)
|
179
|
+
|
180
|
+
keys = @store.keys(message.msg_id)
|
181
|
+
keys.each do |key|
|
182
|
+
assert !@store.redis.exists(key)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
151
186
|
test "successful processing of a redundant message twice should delete all keys from the database (except the status key, which should be set to expire)" do
|
187
|
+
@config.redis_status_key_expiry_interval = 1.minutes
|
152
188
|
header = header_with_params({:redundant => true})
|
153
189
|
header.expects(:ack).twice
|
154
190
|
message = Message.new("somequeue", header, 'foo', :store => @store)
|
@@ -302,7 +338,8 @@ module Beetle
|
|
302
338
|
|
303
339
|
class SimpleMessageTest < Minitest::Test
|
304
340
|
def setup
|
305
|
-
@
|
341
|
+
@config = Configuration.new
|
342
|
+
@store = DeduplicationStore.new(@config)
|
306
343
|
@store.flushdb
|
307
344
|
end
|
308
345
|
|
@@ -333,6 +370,26 @@ module Beetle
|
|
333
370
|
assert_equal RC::AttemptsLimitReached, message.process(handler)
|
334
371
|
end
|
335
372
|
|
373
|
+
test "when processing a simple message, the handler should be executed only once if status keys are used" do
|
374
|
+
@config.redis_status_key_expiry_interval = 1.minute
|
375
|
+
header = header_with_params({})
|
376
|
+
message = Message.new("somequeue", header, 'foo', :attempts => 1, :store => @store)
|
377
|
+
|
378
|
+
handler = mock("handler")
|
379
|
+
s = sequence("s")
|
380
|
+
handler.expects(:pre_process).with(message).in_sequence(s)
|
381
|
+
header.expects(:ack).in_sequence(s)
|
382
|
+
handler.expects(:call).in_sequence(s)
|
383
|
+
assert_equal RC::OK, message.process(handler)
|
384
|
+
|
385
|
+
handler2 = mock("handler")
|
386
|
+
s2 = sequence("s2")
|
387
|
+
handler2.expects(:pre_process).with(message).in_sequence(s2)
|
388
|
+
header.expects(:ack).in_sequence(s2)
|
389
|
+
handler2.expects(:call).in_sequence(s2).never
|
390
|
+
assert_equal RC::OK, message.process(handler2)
|
391
|
+
end
|
392
|
+
|
336
393
|
end
|
337
394
|
|
338
395
|
class HandlerCrashTest < Minitest::Test
|
@@ -53,6 +53,17 @@ module Beetle
|
|
53
53
|
assert_nil @pub.instance_variable_get(:@bunnies)[@pub.server]
|
54
54
|
end
|
55
55
|
|
56
|
+
test "stop!(exception) should close the bunny socket if an exception is not nil" do
|
57
|
+
b = mock("bunny")
|
58
|
+
b.expects(:close_socket)
|
59
|
+
@pub.expects(:bunny?).returns(true)
|
60
|
+
@pub.expects(:bunny).returns(b)
|
61
|
+
@pub.send(:stop!, Exception.new)
|
62
|
+
assert_equal({}, @pub.send(:exchanges))
|
63
|
+
assert_equal({}, @pub.send(:queues))
|
64
|
+
assert_nil @pub.instance_variable_get(:@bunnies)[@pub.server]
|
65
|
+
end
|
66
|
+
|
56
67
|
test "stop! should not create a new bunny " do
|
57
68
|
@pub.expects(:bunny?).returns(false)
|
58
69
|
@pub.expects(:bunny).never
|
@@ -392,6 +403,17 @@ module Beetle
|
|
392
403
|
assert @pub.throttled?
|
393
404
|
end
|
394
405
|
|
406
|
+
test "refresh_throttling! logs a warning if an exception is raised during throttling" do
|
407
|
+
assert !@pub.throttled?
|
408
|
+
@pub.instance_variable_set :@next_throttle_refresh, Time.now - 1
|
409
|
+
options = { "test" => 100 }
|
410
|
+
@pub.throttle(options)
|
411
|
+
@pub.expects(:each_server).raises(StandardError.new("foo"))
|
412
|
+
@pub.logger.expects(:warn)
|
413
|
+
@pub.__send__ :refresh_throttling!
|
414
|
+
assert !@pub.throttled?
|
415
|
+
end
|
416
|
+
|
395
417
|
end
|
396
418
|
|
397
419
|
class PublisherExchangeManagementTest < Minitest::Test
|
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: 3.3.0
|
4
|
+
version: 3.3.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: 2019-07-
|
15
|
+
date: 2019-07-18 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: bunny
|