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

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/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__))