RingyDingy 1.0.0
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/CHANGES +4 -0
- data/LICENSE +26 -0
- data/Manifest.txt +7 -0
- data/README +38 -0
- data/Rakefile +56 -0
- data/lib/ringy_dingy.rb +120 -0
- data/test/test_ringy_dingy.rb +156 -0
- metadata +52 -0
data/CHANGES
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Copyright 2006, Eric Hodel. All rights reserved.
|
2
|
+
|
3
|
+
Redistribution and use in source and binary forms, with or without
|
4
|
+
modification, are permitted provided that the following conditions
|
5
|
+
are met:
|
6
|
+
|
7
|
+
1. Redistributions of source code must retain the above copyright
|
8
|
+
notice, this list of conditions and the following disclaimer.
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright
|
10
|
+
notice, this list of conditions and the following disclaimer in the
|
11
|
+
documentation and/or other materials provided with the distribution.
|
12
|
+
3. Neither the names of the authors nor the names of their contributors
|
13
|
+
may be used to endorse or promote products derived from this software
|
14
|
+
without specific prior written permission.
|
15
|
+
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
|
17
|
+
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
19
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
|
20
|
+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
21
|
+
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
22
|
+
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
23
|
+
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
24
|
+
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
25
|
+
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
26
|
+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/Manifest.txt
ADDED
data/README
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
= RingyDingy
|
2
|
+
|
3
|
+
RingyDingy is a little boat that keeps your DRb service afloat!
|
4
|
+
|
5
|
+
Rubyforge Project:
|
6
|
+
|
7
|
+
http://rubyforge.org/projects/seattlerb
|
8
|
+
|
9
|
+
Documentation:
|
10
|
+
|
11
|
+
ri RingyDingy
|
12
|
+
|
13
|
+
== About
|
14
|
+
|
15
|
+
RingyDingy automatically registers a service with a RingServer. If
|
16
|
+
communication between the RingServer and the RingyDingy is lost, RingyDingy
|
17
|
+
will re-register its service with the RingServer when it reappears.
|
18
|
+
|
19
|
+
Similarly, the RingServer will automatically drop registrations by a RingyDingy
|
20
|
+
that it can't communicate with after a short timeout.
|
21
|
+
|
22
|
+
== Installing RingyDingy
|
23
|
+
|
24
|
+
Just install the gem:
|
25
|
+
|
26
|
+
$ sudo gem install RingyDingy
|
27
|
+
|
28
|
+
== Using RingyDingy
|
29
|
+
|
30
|
+
require 'rubygems'
|
31
|
+
require 'ringy_dingy'
|
32
|
+
require 'my_drb_service'
|
33
|
+
|
34
|
+
my_drb_service = MyDRbService.new
|
35
|
+
|
36
|
+
RingyDingy.new(my_drb_service).run
|
37
|
+
|
38
|
+
DRb.thread.join
|
data/Rakefile
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
|
7
|
+
$VERBOSE = nil
|
8
|
+
|
9
|
+
spec = Gem::Specification.new do |s|
|
10
|
+
s.name = 'RingyDingy'
|
11
|
+
s.version = '1.0.0'
|
12
|
+
s.summary = 'RingyDingy is a little boat that keeps your DRb service afloat!'
|
13
|
+
s.description = 'RingyDingy automatically re-registers your DRb service with a RingServer should communication with the RingServer stop.'
|
14
|
+
s.author = 'Eric Hodel'
|
15
|
+
s.email = 'drbrain@segment7.net'
|
16
|
+
|
17
|
+
s.has_rdoc = true
|
18
|
+
s.files = File.read('Manifest.txt').split($/)
|
19
|
+
s.require_path = 'lib'
|
20
|
+
end
|
21
|
+
|
22
|
+
desc 'Run tests'
|
23
|
+
task :default => [ :test ]
|
24
|
+
|
25
|
+
Rake::TestTask.new('test') do |t|
|
26
|
+
t.libs << 'test'
|
27
|
+
t.pattern = 'test/test_*.rb'
|
28
|
+
t.verbose = true
|
29
|
+
end
|
30
|
+
|
31
|
+
desc 'Update Manifest.txt'
|
32
|
+
task :update_manifest do
|
33
|
+
sh "find . -type f | sed -e 's%./%%' | egrep -v 'svn|swp|~' | egrep -v '^(doc|pkg)/' | sort > Manifest.txt"
|
34
|
+
end
|
35
|
+
|
36
|
+
desc 'Generate RDoc'
|
37
|
+
Rake::RDocTask.new :rdoc do |rd|
|
38
|
+
rd.rdoc_dir = 'doc'
|
39
|
+
rd.rdoc_files.add 'lib', 'README', 'LICENSE', 'CHANGES'
|
40
|
+
rd.main = 'README'
|
41
|
+
rd.options << '-d' if `which dot` =~ /\/dot/
|
42
|
+
rd.options << '-t RingyDingy Documentation'
|
43
|
+
end
|
44
|
+
|
45
|
+
desc 'Build Gem'
|
46
|
+
Rake::GemPackageTask.new spec do |pkg|
|
47
|
+
pkg.need_tar = true
|
48
|
+
end
|
49
|
+
|
50
|
+
desc 'Clean up'
|
51
|
+
task :clean => [ :clobber_rdoc, :clobber_package ]
|
52
|
+
|
53
|
+
desc 'Clean up'
|
54
|
+
task :clobber => [ :clean ]
|
55
|
+
|
56
|
+
# vim: syntax=Ruby
|
data/lib/ringy_dingy.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'English'
|
2
|
+
require 'drb'
|
3
|
+
require 'rinda/ring'
|
4
|
+
|
5
|
+
##
|
6
|
+
# RingyDingy registers a DRb service with a Rinda::RingServer and re-registers
|
7
|
+
# the service if communication with the Rinda::RingServer is ever lost.
|
8
|
+
#
|
9
|
+
# Similarly, if the Rinda::RingServer should ever lose contact with the
|
10
|
+
# service the registration will be automatically dropped after a short
|
11
|
+
# timeout.
|
12
|
+
#
|
13
|
+
# = Example
|
14
|
+
#
|
15
|
+
# my_service = MyService.new
|
16
|
+
# rd = RingyDingy.new my_service, :MyService
|
17
|
+
# rd.run
|
18
|
+
# DRb.thread.join
|
19
|
+
|
20
|
+
class RingyDingy
|
21
|
+
|
22
|
+
##
|
23
|
+
# Interval to check the RingServer for our registration information.
|
24
|
+
|
25
|
+
attr_accessor :check_every
|
26
|
+
|
27
|
+
##
|
28
|
+
# RingyDingy service identifier. Use this to distinguish between
|
29
|
+
# RingyDingys registering the same service.
|
30
|
+
|
31
|
+
attr_reader :identifier
|
32
|
+
|
33
|
+
##
|
34
|
+
# RingyDingy run loop thread.
|
35
|
+
|
36
|
+
attr_reader :thread
|
37
|
+
|
38
|
+
if $TESTING then
|
39
|
+
attr_accessor :ring_finger, :renewer, :thread # :nodoc:
|
40
|
+
attr_writer :ring_server # :nodoc:
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Creates a new RingyDingy that registers +object+ as +service+ with
|
45
|
+
# optional identifier +name+.
|
46
|
+
|
47
|
+
def initialize(object, service = :RingyDingy, name = nil)
|
48
|
+
DRb.start_service
|
49
|
+
|
50
|
+
@identifier = [Socket.gethostname.downcase, $PID, name].compact.join '_'
|
51
|
+
@object = object
|
52
|
+
@service = service || :RingyDingy
|
53
|
+
|
54
|
+
@check_every = 180
|
55
|
+
@renewer = Rinda::SimpleRenewer.new
|
56
|
+
|
57
|
+
@ring_finger = Rinda::RingFinger.new
|
58
|
+
@ring_server = nil
|
59
|
+
|
60
|
+
@thread = nil
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Registers this service with the primary Rinda::RingServer.
|
65
|
+
|
66
|
+
def register
|
67
|
+
ring_server.write [:name, @service, DRbObject.new(@object), @identifier],
|
68
|
+
@renewer
|
69
|
+
return nil
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# Looks for a registration tuple in the primary Rinda::RingServer. If a
|
74
|
+
# RingServer can't be found or contacted, returns false.
|
75
|
+
|
76
|
+
def registered?
|
77
|
+
registrations = ring_server.read_all [:name, :RingyDingy, nil, @identifier]
|
78
|
+
registrations.any? { |registration| registration[2] == @object }
|
79
|
+
rescue DRb::DRbConnError
|
80
|
+
@ring_server = nil
|
81
|
+
return false
|
82
|
+
end
|
83
|
+
|
84
|
+
##
|
85
|
+
# Looks up the primary Rinde::RingServer.
|
86
|
+
|
87
|
+
def ring_server
|
88
|
+
return @ring_server unless @ring_server.nil?
|
89
|
+
@ring_server = @ring_finger.lookup_ring_any
|
90
|
+
end
|
91
|
+
|
92
|
+
##
|
93
|
+
# Starts a thread that checks for a registration tuple every #check_every
|
94
|
+
# seconds.
|
95
|
+
|
96
|
+
def run
|
97
|
+
@thread = Thread.start do
|
98
|
+
loop do
|
99
|
+
begin
|
100
|
+
register unless registered?
|
101
|
+
rescue DRb::DRbConnError
|
102
|
+
@ring_server = nil
|
103
|
+
rescue RuntimeError => e
|
104
|
+
raise unless e.message == 'RingNotFound'
|
105
|
+
end
|
106
|
+
sleep @check_every
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
##
|
112
|
+
# Stops checking for registration tuples.
|
113
|
+
|
114
|
+
def stop
|
115
|
+
@thread.kill
|
116
|
+
return nil
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
$TESTING = true
|
4
|
+
|
5
|
+
require 'ringy_dingy'
|
6
|
+
|
7
|
+
class StubRingFinger
|
8
|
+
|
9
|
+
attr_accessor :ring_server
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@ring_server = nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def lookup_ring_any
|
16
|
+
raise RuntimeError, 'RingNotFound' if @ring_server.nil?
|
17
|
+
@ring_server
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
class StubRingServer
|
23
|
+
|
24
|
+
attr_accessor :tuples
|
25
|
+
|
26
|
+
def initialize
|
27
|
+
@tuples = []
|
28
|
+
end
|
29
|
+
|
30
|
+
def write(*args)
|
31
|
+
@tuples << args
|
32
|
+
end
|
33
|
+
|
34
|
+
def read_all(*args)
|
35
|
+
@tuples.map { |t,r| t }
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
class Rinda::SimpleRenewer
|
41
|
+
|
42
|
+
attr_reader :sec
|
43
|
+
|
44
|
+
def ==(other)
|
45
|
+
self.class === other and sec == other.sec
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
class TestRingyDingy < Test::Unit::TestCase
|
51
|
+
|
52
|
+
def setup
|
53
|
+
@identifier = "#{Socket.gethostname.downcase}_#{$PID}"
|
54
|
+
@object = ""
|
55
|
+
@ringy_dingy = RingyDingy.new @object
|
56
|
+
|
57
|
+
@stub_ring_server = StubRingServer.new
|
58
|
+
@ringy_dingy.ring_server = @stub_ring_server
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_identifier
|
62
|
+
assert_equal @identifier, @ringy_dingy.identifier
|
63
|
+
|
64
|
+
@ringy_dingy = RingyDingy.new @object, nil, 'blah'
|
65
|
+
|
66
|
+
assert_equal "#{@identifier}_blah", @ringy_dingy.identifier
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_register
|
70
|
+
@ringy_dingy.register
|
71
|
+
|
72
|
+
expected = [
|
73
|
+
[[:name, :RingyDingy, DRbObject.new(@object), @identifier],
|
74
|
+
Rinda::SimpleRenewer.new]
|
75
|
+
]
|
76
|
+
|
77
|
+
assert_equal expected, @stub_ring_server.tuples
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_register_service
|
81
|
+
@ringy_dingy = RingyDingy.new @object, :MyDRbService
|
82
|
+
@ringy_dingy.ring_server = @stub_ring_server
|
83
|
+
@ringy_dingy.register
|
84
|
+
|
85
|
+
expected = [
|
86
|
+
[[:name, :MyDRbService, DRbObject.new(@object), @identifier],
|
87
|
+
Rinda::SimpleRenewer.new]
|
88
|
+
]
|
89
|
+
|
90
|
+
assert_equal expected, @stub_ring_server.tuples
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_registered_eh
|
94
|
+
@stub_ring_server.tuples << [
|
95
|
+
[:name, :RingyDingy, @object, @identifier], nil]
|
96
|
+
|
97
|
+
assert_equal true, @ringy_dingy.registered?
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_registered_eh_not_registered
|
101
|
+
assert_equal false, @ringy_dingy.registered?
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_registered_eh_no_ring_server
|
105
|
+
def @stub_ring_server.read_all(*args)
|
106
|
+
raise DRb::DRbConnError
|
107
|
+
end
|
108
|
+
|
109
|
+
assert_equal false, @ringy_dingy.registered?
|
110
|
+
|
111
|
+
assert_equal nil, @ringy_dingy.instance_variable_get(:@ring_server)
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_registered_eh_service
|
115
|
+
@ringy_dingy = RingyDingy.new @object, :MyDRbService
|
116
|
+
@ringy_dingy.ring_server = @stub_ring_server
|
117
|
+
|
118
|
+
@stub_ring_server.tuples << [
|
119
|
+
[:name, :MyDRbService, @object, @identifier], nil]
|
120
|
+
|
121
|
+
assert_equal true, @ringy_dingy.registered?
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_renewer
|
125
|
+
assert_equal Rinda::SimpleRenewer.new, @ringy_dingy.renewer
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_ring_server
|
129
|
+
util_create_stub_ring_finger :server
|
130
|
+
|
131
|
+
assert_equal :server, @ringy_dingy.ring_server
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_ring_server_not_found
|
135
|
+
util_create_stub_ring_finger
|
136
|
+
|
137
|
+
assert_raise RuntimeError do @ringy_dingy.ring_server end
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_stop
|
141
|
+
@ringy_dingy.thread = Thread.start do sleep end
|
142
|
+
assert_equal nil, @ringy_dingy.stop
|
143
|
+
end
|
144
|
+
|
145
|
+
def util_create_stub_ring_finger(rs = nil)
|
146
|
+
@ringy_dingy.ring_server = nil
|
147
|
+
|
148
|
+
ring_finger = StubRingFinger.new
|
149
|
+
|
150
|
+
ring_finger.ring_server = rs unless rs.nil?
|
151
|
+
|
152
|
+
@ringy_dingy.ring_finger = ring_finger
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
metadata
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.99
|
3
|
+
specification_version: 1
|
4
|
+
name: RingyDingy
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 1.0.0
|
7
|
+
date: 2006-09-09 00:00:00 -07:00
|
8
|
+
summary: RingyDingy is a little boat that keeps your DRb service afloat!
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: drbrain@segment7.net
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description: RingyDingy automatically re-registers your DRb service with a RingServer should communication with the RingServer stop.
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Eric Hodel
|
31
|
+
files:
|
32
|
+
- CHANGES
|
33
|
+
- LICENSE
|
34
|
+
- Manifest.txt
|
35
|
+
- README
|
36
|
+
- Rakefile
|
37
|
+
- lib/ringy_dingy.rb
|
38
|
+
- test/test_ringy_dingy.rb
|
39
|
+
test_files: []
|
40
|
+
|
41
|
+
rdoc_options: []
|
42
|
+
|
43
|
+
extra_rdoc_files: []
|
44
|
+
|
45
|
+
executables: []
|
46
|
+
|
47
|
+
extensions: []
|
48
|
+
|
49
|
+
requirements: []
|
50
|
+
|
51
|
+
dependencies: []
|
52
|
+
|