beetle 0.2.1 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|