beetle 0.2.1 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -54,12 +54,11 @@ windows and execute the following commands:
54
54
  rake redis:start1
55
55
  rake redis:start2
56
56
 
57
-
58
57
  == Prerequisites
59
58
 
60
59
  To set up a redundant messaging system you will need
61
60
  * at least 2 AMQP servers (we use {RabbitMQ}[http://www.rabbitmq.com/])
62
- * at least one Redis server (better are two in a master/slave setup)
61
+ * at least one {Redis}[http://github.com/antirez/redis] server (better are two in a master/slave setup)
63
62
 
64
63
  == Gem Dependencies
65
64
 
@@ -67,15 +66,17 @@ At runtime, Beetle will use
67
66
  * {uuid4r}[http://github.com/skaes/uuid4r]
68
67
  (which needs ossp-uuid)
69
68
  * {bunny}[http://github.com/celldee/bunny]
70
- * {redis-rb}[http://github.com/ezmobius/redis-rb]
71
- (which needs {redis}[http://github.com/antirez/redis])
69
+ * {redis}[http://github.com/ezmobius/redis-rb]
72
70
  * {amqp}[http://github.com/tmm1/amqp]
73
71
  (which is based on {eventmachine}[http://github.com/eventmachine/eventmachine])
72
+ * {daemons}[http://daemons.rubyforge.org/]
74
73
  * activesupport
75
74
 
76
75
  For development, you'll need
77
- * mocha
78
- * rcov
76
+ * {mocha}[http://github.com/floehopper/mocha]
77
+ * {rcov}[http://github.com/relevance/rcov]
78
+ * {cucumber}[http://github.com/aslakhellesoy/cucumber]
79
+ * {daemon_controller}[http://github.com/FooBarWidget/daemon_controller]
79
80
 
80
81
  == Authors
81
82
 
data/beetle.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "beetle"
3
- s.version = "0.2.1"
3
+ s.version = "0.2.4"
4
4
 
5
5
  s.required_rubygems_version = ">= 1.3.1"
6
6
  s.authors = ["Stefan Kaes", "Pascal Friederich", "Ali Jelveh", "Sebastian Roebke"]
@@ -31,7 +31,7 @@ Gem::Specification.new do |s|
31
31
  s.specification_version = 3
32
32
  s.add_runtime_dependency("uuid4r", [">= 0.1.1"])
33
33
  s.add_runtime_dependency("bunny", [">= 0.6.0"])
34
- s.add_runtime_dependency("redis", [">= 2.0.3"])
34
+ s.add_runtime_dependency("redis", [">= 2.0.4"])
35
35
  s.add_runtime_dependency("amqp", [">= 0.6.7"])
36
36
  s.add_runtime_dependency("activesupport", [">= 2.3.4"])
37
37
  s.add_runtime_dependency("daemons", [">= 1.0.10"])
@@ -46,7 +46,7 @@ module Beetle
46
46
 
47
47
  dir_mode = nil
48
48
  dir = nil
49
- opts.on("--pid-dir DIR", String, "Write pid and log to DIR") do |val|
49
+ opts.on("--pid-dir DIR", String, "Write pid and output to DIR") do |val|
50
50
  dir_mode = :normal
51
51
  dir = val
52
52
  end
@@ -55,7 +55,7 @@ module Beetle
55
55
 
56
56
  dir_mode = nil
57
57
  dir = nil
58
- opts.on("--pid-dir DIR", String, "Write pid and log to DIR") do |val|
58
+ opts.on("--pid-dir DIR", String, "Write pid and output to DIR") do |val|
59
59
  dir_mode = :normal
60
60
  dir = val
61
61
  end
@@ -4,8 +4,10 @@ module Beetle
4
4
  class Configuration
5
5
  # system name (used for redis cluster partitioning) (defaults to <tt>system</tt>)
6
6
  attr_accessor :system_name
7
- # default logger (defaults to <tt>Logger.new(STDOUT)</tt>)
7
+ # default logger (defaults to <tt>Logger.new(log_file)</tt>)
8
8
  attr_accessor :logger
9
+ # defaults to <tt>STDOUT</tt>
10
+ attr_accessor :log_file
9
11
  # number of seconds after which keys are removed form the message deduplication store (defaults to <tt>3.days</tt>)
10
12
  attr_accessor :gc_threshold
11
13
  # the redis server to use for deduplication
@@ -49,14 +51,6 @@ module Beetle
49
51
  def initialize #:nodoc:
50
52
  self.system_name = "system"
51
53
 
52
- self.logger = begin
53
- logger = Logger.new(STDOUT)
54
- logger.formatter = Logger::Formatter.new
55
- logger.level = Logger::INFO
56
- logger.datetime_format = "%Y-%m-%d %H:%M:%S"
57
- logger
58
- end
59
-
60
54
  self.gc_threshold = 3.days
61
55
  self.redis_server = "localhost:6379"
62
56
  self.redis_servers = ""
@@ -72,6 +66,8 @@ module Beetle
72
66
  self.vhost = "/"
73
67
  self.user = "guest"
74
68
  self.password = "guest"
69
+
70
+ self.log_file = STDOUT
75
71
  end
76
72
 
77
73
  # setting the external config file will load it on assignment
@@ -80,6 +76,16 @@ module Beetle
80
76
  load_config
81
77
  end
82
78
 
79
+ def logger
80
+ @logger ||= begin
81
+ l = Logger.new(log_file)
82
+ l.formatter = Logger::Formatter.new
83
+ l.level = Logger::INFO
84
+ l.datetime_format = "%Y-%m-%d %H:%M:%S"
85
+ l
86
+ end
87
+ end
88
+
83
89
  private
84
90
  def load_config
85
91
  hash = YAML::load(ERB.new(IO.read(config_file)).result)
@@ -279,7 +279,7 @@ module Beetle
279
279
  end
280
280
 
281
281
  def run_handler(handler)
282
- Redis::Timer.timeout(@timeout.to_f) { @handler_result = handler.call(self) }
282
+ Timer.timeout(@timeout.to_f) { @handler_result = handler.call(self) }
283
283
  RC::OK
284
284
  rescue Exception => @exception
285
285
  Beetle::reraise_expectation_errors!
@@ -64,6 +64,7 @@ module Beetle
64
64
  def pong(payload)
65
65
  id = payload["id"]
66
66
  token = payload["token"]
67
+ return unless validate_pong_client_id(id)
67
68
  logger.info "Received pong message from id '#{id}' with token '#{token}'"
68
69
  return unless redeem_token(token)
69
70
  @client_pong_ids_received << id
@@ -164,6 +165,15 @@ module Beetle
164
165
  redis.unknowns.include?(current_master) ? redis.slaves_of(current_master).first : current_master
165
166
  end
166
167
 
168
+ def validate_pong_client_id(client_id)
169
+ unless known_client = @client_ids.include?(client_id)
170
+ msg = "Received pong message from unknown client '#{client_id}'"
171
+ logger.error(msg)
172
+ beetle.publish(:system_notification, {"message" => msg}.to_json)
173
+ end
174
+ known_client
175
+ end
176
+
167
177
  def redeem_token(token)
168
178
  valid_token = token == @current_token
169
179
  logger.info "Ignored message (token was '#{token.inspect}', but expected '#{@current_token.inspect}')" unless valid_token
@@ -51,29 +51,3 @@ class Redis #:nodoc:
51
51
  info["role"] == "slave" && info["master_host"] == host && info["master_port"] == port.to_s
52
52
  end
53
53
  end
54
-
55
- class Redis::Client #:nodoc:
56
- protected
57
- def connect_to(host, port)
58
- if @timeout != 0 and Redis::Timer
59
- begin
60
- Redis::Timer.timeout(@timeout){ @sock = TCPSocket.new(host, port) }
61
- rescue Timeout::Error
62
- @sock = nil
63
- raise Timeout::Error, "Timeout connecting to the server"
64
- end
65
- else
66
- @sock = TCPSocket.new(host, port)
67
- end
68
-
69
- @sock.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
70
-
71
- # If the timeout is set we set the low level socket options in order
72
- # to make sure a blocking read will return after the specified number
73
- # of seconds. This hack is from memcached ruby client.
74
- self.timeout = @timeout
75
-
76
- rescue Errno::ECONNREFUSED
77
- raise Errno::ECONNREFUSED, "Unable to connect to Redis on #{host}:#{port}"
78
- end
79
- end
data/lib/beetle.rb CHANGED
@@ -54,4 +54,5 @@ module Beetle
54
54
  end
55
55
  end
56
56
 
57
+ Timer = RUBY_VERSION < "1.9" ? SystemTimer : Timeout
57
58
  end
@@ -1,5 +1,4 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
- require 'tempfile'
3
2
 
4
3
  module Beetle
5
4
  class ConfigurationTest < Test::Unit::TestCase
@@ -13,5 +12,19 @@ module Beetle
13
12
  config.config_file = "some/path/to/a/file"
14
13
  assert_equal new_value, config.gc_threshold
15
14
  end
15
+
16
+ test "should log to STDOUT if no log_file given" do
17
+ config = Configuration.new
18
+ Logger.expects(:new).with(STDOUT).returns(stub_everything)
19
+ config.logger
20
+ end
21
+
22
+ test "should log to file if log_file given" do
23
+ file = '/path/to/file'
24
+ config = Configuration.new
25
+ config.log_file = file
26
+ Logger.expects(:new).with(file).returns(stub_everything)
27
+ config.logger
28
+ end
16
29
  end
17
30
  end
@@ -275,4 +275,22 @@ module Beetle
275
275
  info
276
276
  end
277
277
  end
278
+
279
+ class RedisConfigurationServerSystemNotificationAndLoggingTest < Test::Unit::TestCase
280
+ def setup
281
+ Beetle.config.redis_configuration_client_ids = "rc-client-1,rc-client-2"
282
+ @server = RedisConfigurationServer.new
283
+ @server.stubs(:beetle).returns(stub(:publish))
284
+ @server.stubs(:logger).returns(stub)
285
+ EventMachine.stubs(:add_timer).yields
286
+ end
287
+
288
+ test "should log and send a system notification when pong message from unknown client received" do
289
+ payload = {"id" => "unknown-client", "token" => @server.current_token}
290
+ msg = "Received pong message from unknown client 'unknown-client'"
291
+ @server.beetle.expects(:publish).with(:system_notification, ({:message => msg}).to_json)
292
+ @server.logger.expects(:error).with(msg)
293
+ @server.pong(payload)
294
+ end
295
+ end
278
296
  end
@@ -56,15 +56,9 @@ module Beetle
56
56
  end
57
57
 
58
58
  class RedisTimeoutTest < Test::Unit::TestCase
59
- test "should use Redis::Timer if timeout is greater 0" do
59
+ test "should use a timer" do
60
60
  r = Redis.new(:host => "localhost", :port => 6390, :timeout => 1)
61
- Redis::Timer.expects(:timeout).with(1).raises(Timeout::Error)
62
- assert_equal({}, r.info_with_rescue)
63
- end
64
-
65
- test "should not use Redis::Timer if timeout 0" do
66
- r = Redis.new(:host => "localhost", :port => 6390, :timeout => 0)
67
- Redis::Timer.expects(:timeout).never
61
+ r.client.expects(:with_timeout).with(1).raises(Timeout::Error)
68
62
  assert_equal({}, r.info_with_rescue)
69
63
  end
70
64
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: beetle
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 31
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 1
10
- version: 0.2.1
9
+ - 4
10
+ version: 0.2.4
11
11
  platform: ruby
12
12
  authors:
13
13
  - Stefan Kaes
@@ -18,7 +18,7 @@ autorequire:
18
18
  bindir: bin
19
19
  cert_chain: []
20
20
 
21
- date: 2010-07-22 00:00:00 +02:00
21
+ date: 2010-08-06 00:00:00 +02:00
22
22
  default_executable: beetle
23
23
  dependencies:
24
24
  - !ruby/object:Gem::Dependency
@@ -61,12 +61,12 @@ dependencies:
61
61
  requirements:
62
62
  - - ">="
63
63
  - !ruby/object:Gem::Version
64
- hash: 9
64
+ hash: 7
65
65
  segments:
66
66
  - 2
67
67
  - 0
68
- - 3
69
- version: 2.0.3
68
+ - 4
69
+ version: 2.0.4
70
70
  type: :runtime
71
71
  version_requirements: *id003
72
72
  - !ruby/object:Gem::Dependency