beetle 3.5.4 → 3.5.6

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: 38849c0467ba80b057fa8bc659ad98b025dd1c6d9ce416a4f2c48dff91f50fac
4
- data.tar.gz: 791b45e82bcddf8bca2923db816475aa16bb81efa96d7c38381de12ea18fe65b
3
+ metadata.gz: 05c783e8ae2cd39837e587954e252f6f8cd772756536cb51de030fdebddfa808
4
+ data.tar.gz: 63403a3e7c70a2840daedfbb41f067c260ac6ae0b34920334f0e26bb999b936b
5
5
  SHA512:
6
- metadata.gz: cbd464c6759316b86ab5732029fefa39518360dc40f055e729d585b9304ad84c9597c7e37908826bfc0347c109c89e7729db8096b2bf51ec64c536c272c9b6b3
7
- data.tar.gz: c7ef92729c7d9cf38c7ec5e0a90fff5147fb4350d568c82c93e58c76b5c358d74929517b888bb8f96386230f0b2f50272488981668d183294fbda5ac86893ade
6
+ metadata.gz: c43c533f5946971f25cbc664809842498f0e52b0404e0a23b772940707adf53288be74d7ca1f8f3cae1943a1d311a19f15b2fc4e3458b6347597367002e65af0
7
+ data.tar.gz: ae915f36ce7d9e78a10421b17bca59710b87964b3904db14ea1064dc6d87147d3e9c2faf6b552982d73ed227e88b4bd8b2d06d4a9d8335654d6008c95eade00b
data/beetle.gemspec CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |s|
24
24
 
25
25
  s.specification_version = 3
26
26
  s.add_runtime_dependency "bunny", "~> 0.7.12"
27
- s.add_runtime_dependency "redis", [">= 4.2.1", "< 5.0"]
27
+ s.add_runtime_dependency "redis", ">= 4.2.1"
28
28
  s.add_runtime_dependency "hiredis", ">= 0.4.5"
29
29
  s.add_runtime_dependency "amq-protocol", "= 2.3.2"
30
30
  s.add_runtime_dependency "amqp", "= 1.8.0"
@@ -36,6 +36,7 @@ Gem::Specification.new do |s|
36
36
  s.add_development_dependency "daemons", ">= 1.2.0"
37
37
  s.add_development_dependency "i18n"
38
38
  s.add_development_dependency "minitest", "~> 5.1"
39
+ s.add_development_dependency "minitest-reporters"
39
40
  s.add_development_dependency "mocha", "~> 1.14"
40
41
  s.add_development_dependency "mysql2", "~> 0.5"
41
42
  s.add_development_dependency "rake", "~> 13.0"
@@ -46,4 +47,5 @@ Gem::Specification.new do |s|
46
47
  s.add_development_dependency 'redcarpet'
47
48
  s.add_development_dependency 'github-markup'
48
49
  s.add_development_dependency 'byebug'
50
+ s.add_development_dependency 'appraisal'
49
51
  end
@@ -46,7 +46,7 @@ end
46
46
 
47
47
  def system_notification_log_path
48
48
  log_path = tmp_path + "/system_notifications.log"
49
- `touch #{log_path}` unless File.exists?(log_path)
49
+ `touch #{log_path}` unless File.exist?(log_path)
50
50
  log_path
51
51
  end
52
52
 
@@ -131,11 +131,11 @@ module TestDaemons
131
131
  private
132
132
 
133
133
  def create_dir
134
- FileUtils.mkdir(dir) unless File.exists?(dir)
134
+ FileUtils.mkdir(dir) unless File.exist?(dir)
135
135
  end
136
136
 
137
137
  def remove_dir
138
- FileUtils.rm_r(dir) if File.exists?(dir)
138
+ FileUtils.rm_r(dir) if File.exist?(dir)
139
139
  end
140
140
 
141
141
  def create_config
@@ -145,11 +145,11 @@ module TestDaemons
145
145
  end
146
146
 
147
147
  def remove_config
148
- FileUtils.rm(config_filename) if File.exists?(config_filename)
148
+ FileUtils.rm(config_filename) if File.exist?(config_filename)
149
149
  end
150
150
 
151
151
  def remove_pid_file
152
- FileUtils.rm(pid_file) if File.exists?(pid_file)
152
+ FileUtils.rm(pid_file) if File.exist?(pid_file)
153
153
  end
154
154
 
155
155
  def tmp_path
@@ -33,6 +33,12 @@ module Beetle
33
33
  attr_accessor :redis_servers
34
34
  # redis database number to use for the message deduplication store (defaults to <tt>4</tt>)
35
35
  attr_accessor :redis_db
36
+ # redis connect timeout. defaults to 5 seconds.
37
+ attr_accessor :redis_connect_timeout
38
+ # redis read timeout. defaults to 5 seconds.
39
+ attr_accessor :redis_read_timeout
40
+ # redis write timeout. defaults to 5 seconds.
41
+ attr_accessor :redis_write_timeout
36
42
 
37
43
  # how long we should repeatedly retry a redis operation before giving up, with a one
38
44
  # second sleep between retries (defaults to <tt>180.seconds</tt>). this value needs to be
@@ -157,6 +163,9 @@ module Beetle
157
163
  self.redis_server = "localhost:6379"
158
164
  self.redis_servers = ""
159
165
  self.redis_db = 4
166
+ self.redis_connect_timeout = 5.0
167
+ self.redis_read_timeout = 5.0
168
+ self.redis_write_timeout = 5.0
160
169
  self.redis_failover_timeout = 180.seconds
161
170
  self.redis_status_key_expiry_interval = 0.seconds
162
171
  self.redis_failover_client_heartbeat_interval = 10.seconds
@@ -217,6 +226,17 @@ module Beetle
217
226
  end
218
227
  end
219
228
 
229
+ # redis optins to be passed to Redis.new
230
+ def redis_options
231
+ {
232
+ db: redis_db,
233
+ connect_timeout: redis_connect_timeout,
234
+ read_timeout: redis_read_timeout,
235
+ write_timeout: redis_write_timeout,
236
+ logger: redis_logger,
237
+ }
238
+ end
239
+
220
240
  private
221
241
  def load_config
222
242
  raw = ERB.new(IO.read(config_file)).result
@@ -62,7 +62,7 @@ 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
65
+ expiry = @config.redis_status_key_expiry_interval.to_i
66
66
  return true if expiry == 0
67
67
  with_failover do
68
68
  redis.set(
@@ -109,7 +109,7 @@ module Beetle
109
109
 
110
110
  # delete all keys associated with the given <tt>msg_id</tt>.
111
111
  def del_keys(msg_id)
112
- expiry = @config.redis_status_key_expiry_interval
112
+ expiry = @config.redis_status_key_expiry_interval.to_i
113
113
  keys = keys(msg_id)
114
114
  status_key = keys.shift if expiry > 0
115
115
  with_failover do
@@ -150,7 +150,7 @@ module Beetle
150
150
 
151
151
  # set current redis master instance (as specified in the Beetle::Configuration)
152
152
  def redis_master_from_server_string
153
- @current_master ||= Redis.from_server_string(@config.redis_server, :db => @config.redis_db, :logger => @config.redis_logger)
153
+ @current_master ||= Redis.from_server_string(@config.redis_server, @config.redis_options)
154
154
  end
155
155
 
156
156
  # set current redis master from master file
@@ -168,7 +168,7 @@ module Beetle
168
168
  def set_current_redis_master_from_master_file
169
169
  @last_time_master_file_changed = File.mtime(@config.redis_server)
170
170
  server_string = extract_redis_master(read_master_file)
171
- @current_master = !server_string.blank? ? Redis.from_server_string(server_string, :db => @config.redis_db, :logger => @config.redis_logger) : nil
171
+ @current_master = !server_string.blank? ? Redis.from_server_string(server_string, @config.redis_options ) : nil
172
172
  end
173
173
 
174
174
  # extract redis master from file content and return the server for our system
@@ -72,15 +72,15 @@ module Beetle
72
72
 
73
73
  def setup(opts) #:nodoc:
74
74
  @server = opts[:server]
75
- @timeout = opts[:timeout] || DEFAULT_HANDLER_TIMEOUT
76
- @delay = opts[:delay] || DEFAULT_HANDLER_EXECUTION_ATTEMPTS_DELAY
75
+ @timeout = opts[:timeout] || DEFAULT_HANDLER_TIMEOUT.to_i
76
+ @delay = (opts[:delay] || DEFAULT_HANDLER_EXECUTION_ATTEMPTS_DELAY).ceil
77
77
  @attempts_limit = opts[:attempts] || DEFAULT_HANDLER_EXECUTION_ATTEMPTS
78
78
  @exceptions_limit = opts[:exceptions] || DEFAULT_EXCEPTION_LIMIT
79
79
  @attempts_limit = @exceptions_limit + 1 if @attempts_limit <= @exceptions_limit
80
80
  @retry_on = opts[:retry_on] || nil
81
81
  @store = opts[:store]
82
82
  max_delay = opts[:max_delay] || @delay
83
- @max_delay = max_delay if max_delay >= 2*@delay
83
+ @max_delay = max_delay.ceil if max_delay >= 2*@delay
84
84
  end
85
85
 
86
86
  # extracts various values from the AMQP header properties
@@ -101,7 +101,7 @@ module Beetle
101
101
  def self.publishing_options(opts = {}) #:nodoc:
102
102
  flags = 0
103
103
  flags |= FLAG_REDUNDANT if opts[:redundant]
104
- expires_at = now + (opts[:ttl] || DEFAULT_TTL)
104
+ expires_at = now + (opts[:ttl] || DEFAULT_TTL).to_i
105
105
  opts = opts.slice(*PUBLISHING_KEYS)
106
106
  opts[:message_id] = generate_uuid.to_s
107
107
  opts[:timestamp] = now
@@ -165,7 +165,7 @@ module Beetle
165
165
 
166
166
  # store handler timeout timestamp in the deduplication store
167
167
  def set_timeout!
168
- @store.set(msg_id, :timeout, now + timeout)
168
+ @store.set(msg_id, :timeout, (now + timeout).ceil)
169
169
  end
170
170
 
171
171
  # handler timed out?
@@ -230,7 +230,7 @@ module Beetle
230
230
  # have we already seen this message? if not, set the status to "incomplete" and store
231
231
  # the message exipration timestamp in the deduplication store.
232
232
  def key_exists?
233
- old_message = !@store.msetnx(msg_id, :status =>"incomplete", :expires => @expires_at, :timeout => now + timeout)
233
+ old_message = !@store.msetnx(msg_id, :status =>"incomplete", :expires => @expires_at.to_i, :timeout => (now + timeout).to_i)
234
234
  if old_message
235
235
  logger.debug "Beetle: received duplicate message: #{msg_id} on queue: #{@queue}"
236
236
  end
@@ -3,6 +3,7 @@ class Redis #:nodoc:
3
3
  def self.from_server_string(server_string, options = {})
4
4
  host, port = server_string.split(':')
5
5
  options = {:host => host, :port => port}.update(options)
6
+ options.delete(:logger) if Redis::VERSION >= "5.0"
6
7
  new(options)
7
8
  end
8
9
 
@@ -79,6 +80,19 @@ class Redis #:nodoc:
79
80
  super != 0
80
81
  end
81
82
 
83
+ elsif Redis::VERSION >= "5.0.0"
84
+
85
+ # redis 5.0.0 has a shutdown method which raises if a connection to the redis server
86
+ # cannot be established.
87
+ module SaneShutdown
88
+ def shutdown
89
+ super
90
+ rescue RedisClient::CannotConnectError
91
+ nil
92
+ end
93
+ end
94
+ prepend SaneShutdown
95
+
82
96
  elsif Redis::VERSION >= "4.0.0"
83
97
 
84
98
  # redis 4.0.0 has a shutdown method which raises if a connection to the redis server
@@ -1,3 +1,3 @@
1
1
  module Beetle
2
- VERSION = "3.5.4"
2
+ VERSION = "3.5.6"
3
3
  end
data/lib/beetle.rb CHANGED
@@ -1,8 +1,19 @@
1
1
  $:.unshift(File.expand_path('..', __FILE__))
2
2
  require 'bunny' # which bunny picks up
3
3
  require 'qrack/errors' # needed by the publisher
4
- require 'redis/connection/hiredis' # require *before* redis as specified in the redis-rb gem docs
5
- require 'redis'
4
+
5
+ if Gem::Version.new(Bunny::VERSION) <= Gem::Version.new("0.7.12") && !defined?(::Fixnum)
6
+ require 'qrack/transport/buffer09'
7
+ Qrack::Transport09::Buffer.class_eval "Fixnum = Integer"
8
+ end
9
+
10
+ begin
11
+ require 'redis/connection/hiredis' # require *before* redis as specified in the redis-rb gem docs
12
+ require 'redis'
13
+ rescue LoadError
14
+ require 'redis'
15
+ require 'hiredis-client'
16
+ end
6
17
  require 'active_support/all'
7
18
  require 'set'
8
19
  require 'socket'
@@ -0,0 +1,32 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class BunnyBehaviorTest < Minitest::Test
4
+ test "publishing fixnums and hashes works in amqp headers" do
5
+ client = Beetle::Client.new
6
+ client.register_queue(:test)
7
+ client.register_message(:test)
8
+
9
+ # purge the test queue
10
+ client.purge(:test)
11
+
12
+ # empty the dedup store
13
+ client.deduplication_store.flushdb
14
+
15
+ # register our handler to the message, check out the message.rb for more stuff you can get from the message object
16
+ message = nil
17
+ client.register_handler(:test) {|msg| message = msg; client.stop_listening }
18
+
19
+ # publish our message (NOTE: empty message bodies don't work, most likely due to bugs in bunny/amqp)
20
+ published = client.publish(:test, 'bam', headers: { foo: 1, table: {bar: "baz"}})
21
+
22
+ # start listening
23
+ client.listen
24
+ client.stop_publishing
25
+
26
+ assert_equal 1, published
27
+ assert_equal "bam", message.data
28
+ headers = message.header.attributes[:headers]
29
+ assert_equal 1, headers["foo"]
30
+ assert_equal({"bar" => "baz"}, headers["table"])
31
+ end
32
+ end
@@ -57,7 +57,11 @@ module Beetle
57
57
 
58
58
  class HiredisLoadedTest < Minitest::Test
59
59
  test "should be using hiredis instead of the redis ruby backend" do
60
- assert defined?(Hiredis)
60
+ if Redis::VERSION < "5.0"
61
+ assert defined?(Hiredis)
62
+ else
63
+ assert_equal RedisClient.default_driver, RedisClient::HiredisConnection
64
+ end
61
65
  end
62
66
  end
63
67
 
data/test/test_helper.rb CHANGED
@@ -7,9 +7,15 @@ end
7
7
 
8
8
  require 'minitest/autorun'
9
9
  require 'minitest/unit'
10
- require 'minitest/pride' if ENV['RAINBOW_COLORED_TESTS'] == "1" && $stdout.tty?
11
10
  require 'mocha/minitest'
12
11
 
12
+ require 'minitest/reporters'
13
+ if ENV['MINITEST_REPORTER']
14
+ Minitest::Reporters.use!
15
+ else
16
+ Minitest::Reporters.use!([Minitest::Reporters::DefaultReporter.new])
17
+ end
18
+
13
19
  require File.expand_path(File.dirname(__FILE__) + '/../lib/beetle')
14
20
  require 'eventmachine'
15
21
 
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.5.4
4
+ version: 3.5.6
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: 2022-08-30 00:00:00.000000000 Z
15
+ date: 2023-03-23 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: bunny
@@ -35,9 +35,6 @@ dependencies:
35
35
  - - ">="
36
36
  - !ruby/object:Gem::Version
37
37
  version: 4.2.1
38
- - - "<"
39
- - !ruby/object:Gem::Version
40
- version: '5.0'
41
38
  type: :runtime
42
39
  prerelease: false
43
40
  version_requirements: !ruby/object:Gem::Requirement
@@ -45,9 +42,6 @@ dependencies:
45
42
  - - ">="
46
43
  - !ruby/object:Gem::Version
47
44
  version: 4.2.1
48
- - - "<"
49
- - !ruby/object:Gem::Version
50
- version: '5.0'
51
45
  - !ruby/object:Gem::Dependency
52
46
  name: hiredis
53
47
  requirement: !ruby/object:Gem::Requirement
@@ -188,6 +182,20 @@ dependencies:
188
182
  - - "~>"
189
183
  - !ruby/object:Gem::Version
190
184
  version: '5.1'
185
+ - !ruby/object:Gem::Dependency
186
+ name: minitest-reporters
187
+ requirement: !ruby/object:Gem::Requirement
188
+ requirements:
189
+ - - ">="
190
+ - !ruby/object:Gem::Version
191
+ version: '0'
192
+ type: :development
193
+ prerelease: false
194
+ version_requirements: !ruby/object:Gem::Requirement
195
+ requirements:
196
+ - - ">="
197
+ - !ruby/object:Gem::Version
198
+ version: '0'
191
199
  - !ruby/object:Gem::Dependency
192
200
  name: mocha
193
201
  requirement: !ruby/object:Gem::Requirement
@@ -328,6 +336,20 @@ dependencies:
328
336
  - - ">="
329
337
  - !ruby/object:Gem::Version
330
338
  version: '0'
339
+ - !ruby/object:Gem::Dependency
340
+ name: appraisal
341
+ requirement: !ruby/object:Gem::Requirement
342
+ requirements:
343
+ - - ">="
344
+ - !ruby/object:Gem::Version
345
+ version: '0'
346
+ type: :development
347
+ prerelease: false
348
+ version_requirements: !ruby/object:Gem::Requirement
349
+ requirements:
350
+ - - ">="
351
+ - !ruby/object:Gem::Version
352
+ version: '0'
331
353
  description: A highly available, reliable messaging infrastructure
332
354
  email: opensource@xing.com
333
355
  executables: []
@@ -385,6 +407,7 @@ files:
385
407
  - test/beetle/amqp_gem_behavior_test.rb
386
408
  - test/beetle/base_test.rb
387
409
  - test/beetle/beetle_test.rb
410
+ - test/beetle/bunny_behavior_test.rb
388
411
  - test/beetle/client_test.rb
389
412
  - test/beetle/configuration_test.rb
390
413
  - test/beetle/deduplication_store_test.rb
@@ -418,7 +441,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
418
441
  - !ruby/object:Gem::Version
419
442
  version: 1.3.7
420
443
  requirements: []
421
- rubygems_version: 3.3.19
444
+ rubygems_version: 3.4.6
422
445
  signing_key:
423
446
  specification_version: 3
424
447
  summary: High Availability AMQP Messaging with Redundant Queues
@@ -426,6 +449,7 @@ test_files:
426
449
  - test/beetle/amqp_gem_behavior_test.rb
427
450
  - test/beetle/base_test.rb
428
451
  - test/beetle/beetle_test.rb
452
+ - test/beetle/bunny_behavior_test.rb
429
453
  - test/beetle/client_test.rb
430
454
  - test/beetle/configuration_test.rb
431
455
  - test/beetle/deduplication_store_test.rb