beetle 0.3.0.rc.8 → 0.3.0.rc.9

Sign up to get free protection for your applications and to get access to all the features.
data/RELEASE_NOTES.rdoc CHANGED
@@ -1,9 +1,15 @@
1
1
  = Release Notes
2
2
 
3
- == Version 0.3.0.rc.3
3
+ == Version 0.3.0
4
4
 
5
+ * allow accelerating master switch via POST to redis configuration server
6
+ * embedded http server into the redis configuration server (port 8080)
7
+ * fixed a problem with redis shutdown command
8
+ * upgraded to redis 2.2.2
9
+ * upgraded to amqp gem version 0.8 line
5
10
  * use hiredis as the redis backend, which overcomes lack of proper time-outs in the "generic" redis-rb
6
11
  gem for Ruby 1.9
12
+ * use fully qualified hostnames to identify redis configuration clients
7
13
 
8
14
  == Version 0.2.9.8
9
15
 
data/beetle.gemspec CHANGED
@@ -36,9 +36,9 @@ Gem::Specification.new do |s|
36
36
  s.add_runtime_dependency("bunny", ["= 0.7.8"])
37
37
  s.add_runtime_dependency("redis", ["= 2.2.2"])
38
38
  s.add_runtime_dependency("hiredis", ["= 0.3.2"])
39
- s.add_runtime_dependency("amq-client", ["= 0.8.3"])
40
- s.add_runtime_dependency("amq-protocol", ["= 0.8.1"])
41
- s.add_runtime_dependency("amqp", ["= 0.8.0"])
39
+ s.add_runtime_dependency("amq-client", ["= 0.8.5"])
40
+ s.add_runtime_dependency("amq-protocol", ["= 0.8.3"])
41
+ s.add_runtime_dependency("amqp", ["= 0.8.2"])
42
42
  s.add_runtime_dependency("activesupport", [">= 2.3.4"])
43
43
  s.add_runtime_dependency("eventmachine_httpserver", [">= 0.2.1"])
44
44
  s.add_runtime_dependency("daemons", [">= 1.0.10"])
@@ -0,0 +1,32 @@
1
+ # attempts.rb
2
+ # this example shows you how to use the exception limiting feature of beetle
3
+ # it allows you to control the number of retries your handler will go through
4
+ # with one message before giving up on it
5
+ #
6
+ # ! check the examples/README.rdoc for information on starting your redis/rabbit !
7
+ #
8
+ # start it with ruby attempts.rb
9
+
10
+ require "rubygems"
11
+ require File.expand_path("../lib/beetle", File.dirname(__FILE__))
12
+ require "eventmachine"
13
+
14
+ # set Beetle log level to info, less noisy than debug
15
+ Beetle.config.logger.level = Logger::INFO
16
+
17
+ # setup client
18
+ client = Beetle::Client.new
19
+ client.register_message(:test)
20
+
21
+ n = 0
22
+ EM.run do
23
+ EM.add_periodic_timer(0.1) do
24
+ data = (n+=1)
25
+ client.logger.info "publishing #{data}"
26
+ client.publish(:test, data)
27
+ end
28
+ trap("INT") do
29
+ client.stop_publishing
30
+ EM.stop_event_loop
31
+ end
32
+ end
@@ -107,3 +107,42 @@ Feature: Redis auto failover
107
107
  Scenario: Redis configuation server should embed a http server
108
108
  Given a redis configuration server using redis servers "redis-1,redis-2" with clients "rc-client-1,rc-client-2" exists
109
109
  Then the redis configuration server should answer http requests
110
+
111
+ Scenario: Accelerated redis master switch when master is down
112
+ Given a redis configuration server using redis servers "redis-1,redis-2" with clients "rc-client-1,rc-client-2" exists
113
+ And a redis configuration client "rc-client-1" using redis servers "redis-1,redis-2" exists
114
+ And a redis configuration client "rc-client-2" using redis servers "redis-1,redis-2" exists
115
+ And a beetle handler using the redis-master file from "rc-client-1" exists
116
+ And redis server "redis-1" is down
117
+ And an immediate master switch is initiated and responds with 201
118
+ Then a system notification for "redis-1" not being available should be sent
119
+ And the role of redis server "redis-2" should be "master"
120
+ And the redis master of "rc-client-1" should be "redis-2"
121
+ And the redis master of "rc-client-2" should be "redis-2"
122
+ And the redis master of the beetle handler should be "redis-2"
123
+ And a system notification for switching from "redis-1" to "redis-2" should be sent
124
+ Given a redis server "redis-1" exists as master
125
+ Then the role of redis server "redis-1" should be "slave"
126
+
127
+ Scenario: Accelerated redis master switch when master is up
128
+ Given a redis configuration server using redis servers "redis-1,redis-2" with clients "rc-client-1,rc-client-2" exists
129
+ And a redis configuration client "rc-client-1" using redis servers "redis-1,redis-2" exists
130
+ And a redis configuration client "rc-client-2" using redis servers "redis-1,redis-2" exists
131
+ And a beetle handler using the redis-master file from "rc-client-1" exists
132
+ And an immediate master switch is initiated and responds with 200
133
+ Then the role of redis server "redis-1" should be "master"
134
+ And the redis master of "rc-client-1" should be "redis-1"
135
+ And the redis master of "rc-client-2" should be "redis-1"
136
+ And the redis master of the beetle handler should be "redis-1"
137
+ And the role of redis server "redis-2" should be "slave"
138
+
139
+ # Scenario: Running the system for a few seconds to perform manual testing
140
+ # Given a redis configuration server using redis servers "redis-1,redis-2" with clients "rc-client-1,rc-client-2" exists
141
+ # And a redis configuration client "rc-client-1" using redis servers "redis-1,redis-2" exists
142
+ # And a redis configuration client "rc-client-2" using redis servers "redis-1,redis-2" exists
143
+ # And a beetle handler using the redis-master file from "rc-client-1" exists
144
+ # And the redis master of "rc-client-1" should be "redis-1"
145
+ # And the redis master of "rc-client-2" should be "redis-1"
146
+ # And the redis master of the beetle handler should be "redis-1"
147
+ # And the role of redis server "redis-2" should be "slave"
148
+ # Then the system can run for a while without dying
@@ -134,7 +134,17 @@ Then /^a system notification for no slave available to become new master should
134
134
  end
135
135
 
136
136
  Then /^the redis configuration server should answer http requests$/ do
137
- TestDaemons::RedisConfigurationServer.answers_text_requests?
138
- TestDaemons::RedisConfigurationServer.answers_html_requests?
139
- TestDaemons::RedisConfigurationServer.answers_json_requests?
137
+ assert TestDaemons::RedisConfigurationServer.answers_text_requests?
138
+ assert TestDaemons::RedisConfigurationServer.answers_html_requests?
139
+ assert TestDaemons::RedisConfigurationServer.answers_json_requests?
140
+ end
141
+
142
+ Given /^an immediate master switch is initiated and responds with (\d+)$/ do |response_code|
143
+ response = TestDaemons::RedisConfigurationServer.initiate_master_switch
144
+ assert_equal response_code, response.code
145
+ sleep 1
146
+ end
147
+
148
+ Then /^the system can run for a while without dying$/ do
149
+ sleep 60
140
150
  end
@@ -66,9 +66,10 @@ module TestDaemons
66
66
  end
67
67
 
68
68
  def self.answers_html_requests?
69
- response = get_status("/", "text/html")
70
- response.code == '200' &&
71
- response.content_type == "txt/html"
69
+ response1 = get_status("/", "text/html")
70
+ response2 = get_status("/.html", "text/html")
71
+ response1.code == '200' && response2.code == '200' &&
72
+ response1.content_type == "text/html" && response2.content_type == "text/html"
72
73
  rescue
73
74
  false
74
75
  end
@@ -79,9 +80,14 @@ module TestDaemons
79
80
  request = Net::HTTP::Get.new(uri.request_uri)
80
81
  request['Accept'] = content_type
81
82
  response = http.request(request)
82
- # $stderr.puts response.content_type
83
- # $stderr.puts response.body
84
83
  response
85
84
  end
85
+
86
+ def self.initiate_master_switch
87
+ http = Net::HTTP.new('127.0.0.1', 8080)
88
+ response = http.post '/initiate_master_switch', ''
89
+ response
90
+ end
91
+
86
92
  end
87
93
  end
@@ -24,6 +24,7 @@ module Beetle
24
24
  # @http_post_content
25
25
  # @http_headers
26
26
  response = EM::DelegatedHttpResponse.new(self)
27
+ response.headers['Refresh'] = '3; url=/'
27
28
  # headers = @http_headers.split("\0").inject({}){|h, s| (s =~ /^([^:]+): (.*)$/ && (h[$1] = $2)); h }
28
29
 
29
30
  case @http_request_uri
@@ -36,6 +37,8 @@ module Beetle
36
37
  when "/.txt"
37
38
  response.content_type 'text/plain'
38
39
  server_status(response, "plain")
40
+ when '/initiate_master_switch'
41
+ initiate_master_switch(response)
39
42
  else
40
43
  not_found(response)
41
44
  end
@@ -74,7 +77,13 @@ module Beetle
74
77
  row =~/(^[^:]+): (.*)$/
75
78
  b << "<tr><td>#{$1}</td><td>#{$2}</td></tr>\n"
76
79
  end
77
- b << "</table></body></html>"
80
+ b << "</table>"
81
+ unless status[:redis_master_available?]
82
+ b << "<form name='masterswitch' method='post' action='/initiate_master_switch'>"
83
+ b << "<a href='javascript: document.masterswitch.submit();'>Initiate master switch</a>"
84
+ b << "</form>"
85
+ end
86
+ b << "</body></html>"
78
87
  end
79
88
 
80
89
  def html_styles(status)
@@ -86,10 +95,32 @@ body { margin: 1em; }
86
95
  table tr:nth-child(2n+1){ background:#fff; }
87
96
  td { padding: 0.1em 0.2em; }
88
97
  h1 { color: #{warn_color}; margin-bottom: 0.2em;}
98
+ a:link, a:visited {text-decoration:none; color:#A52A2A;}
99
+ a:hover, a:active {text-decoration:none; color:#FF0000;}
100
+ a {
101
+ font-size: 2em; padding: 10px; background: #cdcdcd;
102
+ -moz-border-radius: 5px;
103
+ border-radius: 5px;
104
+ -moz-box-shadow: 2px 2px 2px #bbb;
105
+ -webkit-box-shadow: 2px 2px 2px #bbb;
106
+ box-shadow: 2px 2px 2px #bbb;
107
+ }
108
+ form { margin-top: 1em; }
89
109
  </style>
90
110
  EOS
91
111
  end
92
112
 
113
+ def initiate_master_switch(response)
114
+ response.content_type 'text/plain'
115
+ if config_server.initiate_master_switch
116
+ response.status = 201
117
+ response.content = "Master switch initiated"
118
+ else
119
+ response.status = 200
120
+ response.content = "No master switch necessary"
121
+ end
122
+ end
123
+
93
124
  def not_found(response)
94
125
  response.content_type 'text/plain'
95
126
  response.status = 404
@@ -56,6 +56,7 @@ module Beetle
56
56
  :redis_master => current_master.try(:server).to_s,
57
57
  :redis_master_available? => master_available?,
58
58
  :redis_slaves_available => available_slaves.map(&:server),
59
+ :switch_in_progress => paused?,
59
60
  }
60
61
  end
61
62
 
@@ -147,6 +148,17 @@ module Beetle
147
148
  redis.slaves
148
149
  end
149
150
 
151
+ # initiate a master switch if the current master is not available and no switch is in progress
152
+ def initiate_master_switch
153
+ redis.refresh
154
+ available, switch_in_progress = master_available?, paused?
155
+ logger.debug "initiating master switch: already in progress = #{switch_in_progress}"
156
+ unless available || switch_in_progress
157
+ master_unavailable!
158
+ end
159
+ !available || switch_in_progress
160
+ end
161
+
150
162
  private
151
163
 
152
164
  def check_redis_configuration
@@ -1,3 +1,3 @@
1
1
  module Beetle
2
- VERSION = "0.3.0.rc.8"
2
+ VERSION = "0.3.0.rc.9"
3
3
  end
@@ -63,6 +63,28 @@ module Beetle
63
63
  test "should be able to report current status" do
64
64
  assert @server.status.is_a?(Hash)
65
65
  end
66
+
67
+ test "should not execute a conditional master switch if the current master is available" do
68
+ @server.expects(:master_available?).returns(true)
69
+ @server.expects(:paused?).returns(false)
70
+ @server.expects(:master_unavailable!).never
71
+ assert !@server.initiate_master_switch
72
+ end
73
+
74
+ test "should not execute a conditional master switch if a switch is already in progress" do
75
+ @server.expects(:master_available?).returns(false)
76
+ @server.expects(:paused?).returns(true)
77
+ @server.expects(:master_unavailable!).never
78
+ assert @server.initiate_master_switch
79
+ end
80
+
81
+ test "should execute a conditional master switch if the current master is unavailable and no switch is in progress yet" do
82
+ @server.expects(:master_available?).returns(false)
83
+ @server.expects(:master_unavailable!).once
84
+ @server.expects(:paused?).returns(false)
85
+ assert @server.initiate_master_switch
86
+ end
87
+
66
88
  end
67
89
 
68
90
  class RedisConfigurationServerInvalidationTest < Test::Unit::TestCase
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: beetle
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15424053
4
+ hash: 15424055
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 0
8
8
  - 3
9
9
  - 0
10
10
  - rc
11
- - 8
12
- version: 0.3.0.rc.8
11
+ - 9
12
+ version: 0.3.0.rc.9
13
13
  platform: ruby
14
14
  authors:
15
15
  - Stefan Kaes
@@ -21,7 +21,7 @@ autorequire:
21
21
  bindir: bin
22
22
  cert_chain: []
23
23
 
24
- date: 2011-10-29 00:00:00 +02:00
24
+ date: 2011-10-31 00:00:00 +01:00
25
25
  default_executable: beetle
26
26
  dependencies:
27
27
  - !ruby/object:Gem::Dependency
@@ -96,12 +96,12 @@ dependencies:
96
96
  requirements:
97
97
  - - "="
98
98
  - !ruby/object:Gem::Version
99
- hash: 57
99
+ hash: 53
100
100
  segments:
101
101
  - 0
102
102
  - 8
103
- - 3
104
- version: 0.8.3
103
+ - 5
104
+ version: 0.8.5
105
105
  type: :runtime
106
106
  version_requirements: *id005
107
107
  - !ruby/object:Gem::Dependency
@@ -112,12 +112,12 @@ dependencies:
112
112
  requirements:
113
113
  - - "="
114
114
  - !ruby/object:Gem::Version
115
- hash: 61
115
+ hash: 57
116
116
  segments:
117
117
  - 0
118
118
  - 8
119
- - 1
120
- version: 0.8.1
119
+ - 3
120
+ version: 0.8.3
121
121
  type: :runtime
122
122
  version_requirements: *id006
123
123
  - !ruby/object:Gem::Dependency
@@ -128,12 +128,12 @@ dependencies:
128
128
  requirements:
129
129
  - - "="
130
130
  - !ruby/object:Gem::Version
131
- hash: 63
131
+ hash: 59
132
132
  segments:
133
133
  - 0
134
134
  - 8
135
- - 0
136
- version: 0.8.0
135
+ - 2
136
+ version: 0.8.2
137
137
  type: :runtime
138
138
  version_requirements: *id007
139
139
  - !ruby/object:Gem::Dependency
@@ -282,6 +282,7 @@ files:
282
282
  - examples/redundant.rb
283
283
  - examples/rpc.rb
284
284
  - examples/simple.rb
285
+ - examples/test_publisher.rb
285
286
  - lib/beetle/base.rb
286
287
  - lib/beetle/client.rb
287
288
  - lib/beetle/commands/configuration_client.rb
@@ -314,7 +315,6 @@ files:
314
315
  - features/support/test_daemons/redis_configuration_client.rb
315
316
  - features/support/test_daemons/redis_configuration_server.rb
316
317
  - script/console
317
- - script/console~
318
318
  - script/start_rabbit
319
319
  - beetle.gemspec
320
320
  - Rakefile
data/script/console~ DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env ruby
2
- $:.unshift(File.expand_path("../lib",__FILE__))