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 +7 -6
- data/beetle.gemspec +2 -2
- data/lib/beetle/commands/configuration_client.rb +1 -1
- data/lib/beetle/commands/configuration_server.rb +1 -1
- data/lib/beetle/configuration.rb +15 -9
- data/lib/beetle/message.rb +1 -1
- data/lib/beetle/redis_configuration_server.rb +10 -0
- data/lib/beetle/redis_ext.rb +0 -26
- data/lib/beetle.rb +1 -0
- data/test/beetle/configuration_test.rb +14 -1
- data/test/beetle/redis_configuration_server_test.rb +18 -0
- data/test/beetle/redis_ext_test.rb +2 -8
- metadata +7 -7
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
|
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.
|
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.
|
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"])
|
data/lib/beetle/configuration.rb
CHANGED
@@ -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(
|
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)
|
data/lib/beetle/message.rb
CHANGED
@@ -279,7 +279,7 @@ module Beetle
|
|
279
279
|
end
|
280
280
|
|
281
281
|
def run_handler(handler)
|
282
|
-
|
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
|
data/lib/beetle/redis_ext.rb
CHANGED
@@ -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
@@ -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
|
59
|
+
test "should use a timer" do
|
60
60
|
r = Redis.new(:host => "localhost", :port => 6390, :timeout => 1)
|
61
|
-
|
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:
|
4
|
+
hash: 31
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
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-
|
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:
|
64
|
+
hash: 7
|
65
65
|
segments:
|
66
66
|
- 2
|
67
67
|
- 0
|
68
|
-
-
|
69
|
-
version: 2.0.
|
68
|
+
- 4
|
69
|
+
version: 2.0.4
|
70
70
|
type: :runtime
|
71
71
|
version_requirements: *id003
|
72
72
|
- !ruby/object:Gem::Dependency
|