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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: df35415e0cf7a4d4915a56aa594fe4aa1e63be2d536eab5589a5b80c349fdb96
4
- data.tar.gz: 6f621ab1501f71cdc7ee84d8989dd446ebd17676d53f9e23ba9d8278206908ed
3
+ metadata.gz: 3e1e8a0378a54fd5b151e8a85fe404d74b06bc0e33458e632676bb5b60b7b38d
4
+ data.tar.gz: 546a4383cdc3727eb9709ea6ef30647cfc647c803e5be9853b77b50b70c915c0
5
5
  SHA512:
6
- metadata.gz: 51e61e992d734f636b5a86b176ab1150530c8e7c18dbbaf8c4f8e685eaf48b2531133bb0770b9b8f50bea45e95588cad6b892866a6cd6644dc8d5a3e67e71b7d
7
- data.tar.gz: 4ef44c5608cfe93adc0bf9fefea0cfdfda59f358323b5ed93158fb57e0122241c45a4deff76a8a098664a4e027ff1394e135541857a4682286ab135481c012a9
6
+ metadata.gz: d307e9c99eaafc64463e2fc5b21b3b9b4a04a831b3eb74d0330f86411412dc01f4f3e0a3e059695d5cfbd2b94b527352549fbaf4e5ebd4c8f28acdce79b25dcb
7
+ data.tar.gz: a285335c8023bda35630fbe01162d5cd5e196fc60576c827f3f05e099d9f5c3e35608d7819d996de849c9f25e3619a33de90a2cca3704fab11636f3ec6645d0f
@@ -1,12 +1,14 @@
1
1
  = Release Notes
2
2
 
3
- == Version 3.3.0.rc1
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 messages.
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
@@ -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
- # redundant message pair. Defaults to 5 minutes. Setting this to a high value (hours)
42
- # will reduce the likelihood of executing handler logic more than once, but can cause
43
- # a higher redis database size with all associated problems. A handler can be
44
- # executed more than once if the ack to the RabbitMQ server gets lost between the consumer
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 = 5.minutes
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 => @config.redis_status_key_expiry_interval,
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, @config.redis_status_key_expiry_interval)
117
+ redis.expire(status_key, expiry) if expiry > 0
115
118
  end
116
119
  end
117
120
 
@@ -1,3 +1,3 @@
1
1
  module Beetle
2
- VERSION = "3.3.0.rc1"
2
+ VERSION = "3.3.0"
3
3
  end
@@ -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
- @store = DeduplicationStore.new
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.rc1
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-17 00:00:00.000000000 Z
15
+ date: 2019-07-18 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: bunny