fraggle 4.0.0.pre.3 → 4.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/README.md +88 -71
- data/bench/gs.rb +57 -47
- data/example/getdir.rb +18 -18
- data/example/readme.rb +56 -56
- data/example/walk.rb +21 -17
- data/example/watch.rb +8 -4
- data/lib/fraggle.rb +20 -7
- data/lib/fraggle/client.rb +11 -6
- data/lib/fraggle/version.rb +1 -1
- data/test/fraggle_client_test.rb +7 -10
- data/test/fraggle_test.rb +3 -2
- data/test/fraggle_transaction_test.rb +10 -10
- data/test/helper.rb +2 -8
- metadata +8 -12
data/README.md
CHANGED
@@ -31,78 +31,78 @@ addresses with IP 127.0.0.1 and ports 8046, 8041, 8042, 8043.
|
|
31
31
|
# other doozers until one accepts or it runs out of options; A NoAddrs
|
32
32
|
# exception will be raised if that later happens.
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
c.get(v, "/foo") do |e, err|
|
38
|
-
if err
|
39
|
-
err.code # => nil
|
40
|
-
err.detail # => nil
|
41
|
-
else
|
42
|
-
e.value # => nil
|
43
|
-
e.rev # => 0
|
44
|
-
e.missing? # => true
|
45
|
-
end
|
46
|
-
|
47
|
-
p [:get, e, err]
|
34
|
+
Fraggle.connect do |c, err|
|
35
|
+
if err
|
36
|
+
raise err.message
|
48
37
|
end
|
49
38
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
e
|
62
|
-
e.set? # => true
|
63
|
-
e.del? # => false
|
39
|
+
c.rev do |v|
|
40
|
+
c.get(v, "/foo") do |e, err|
|
41
|
+
if err
|
42
|
+
err.code # => nil
|
43
|
+
err.detail # => nil
|
44
|
+
else
|
45
|
+
e.value # => nil
|
46
|
+
e.rev # => 0
|
47
|
+
e.missing? # => true
|
48
|
+
end
|
49
|
+
|
50
|
+
p [:get, e, err]
|
64
51
|
end
|
65
52
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
#
|
85
|
-
# See High-Availability in the README for more information about this.
|
86
|
-
#
|
87
|
-
c.set(0, "/foo", "zomg!", &f)
|
88
|
-
next
|
53
|
+
## Obtain the current revision the store is at and watch from then on for
|
54
|
+
## any SET or DEL to /foo.
|
55
|
+
c.wait(v, "/foo") do |e, err|
|
56
|
+
# The event has:
|
57
|
+
# ------------------------
|
58
|
+
if err
|
59
|
+
err.code # => nil
|
60
|
+
err.detail # => nil
|
61
|
+
else
|
62
|
+
e.path # => "/foo"
|
63
|
+
e.value # => "zomg!"
|
64
|
+
e.rev # => 123
|
65
|
+
e.set? # => true
|
66
|
+
e.del? # => false
|
67
|
+
end
|
68
|
+
|
69
|
+
p [:wait, e, err]
|
70
|
+
end
|
89
71
|
end
|
90
72
|
|
91
|
-
|
92
|
-
|
93
|
-
|
73
|
+
## Setting a key (this will trigger the watch above)
|
74
|
+
f = Proc.new do |e, err|
|
75
|
+
p [:e, e, err]
|
76
|
+
|
77
|
+
# This case statement is undesirable. We're working
|
78
|
+
# on better error handling.
|
79
|
+
case (err && err.code rescue err)
|
80
|
+
when Fraggle::Connection::DisconnectedError
|
81
|
+
# Fraggle (for now) does not attempt a non-idempotent request. This means
|
82
|
+
# Fraggle will hand off the error to the user if there is a SET or DEL
|
83
|
+
# with rev 0 (missing) and delete it during the time we may be
|
84
|
+
# disconnected.
|
85
|
+
#
|
86
|
+
# In this scenario, there are no other clients that can exist that will
|
87
|
+
# attempt to set this "lock" if it's missing then delete it. It is safe
|
88
|
+
# for us to resend the request if we were disconnected from the previous
|
89
|
+
# server before a response.
|
90
|
+
#
|
91
|
+
# See High-Availability in the README for more information about this.
|
92
|
+
#
|
93
|
+
c.set(0, "/foo", "zomg!", &f)
|
94
94
|
when Fraggle::REV_MISMATCH
|
95
95
|
p :not_it
|
96
96
|
when nil
|
97
|
-
|
97
|
+
# Success!
|
98
98
|
p [:it, e]
|
99
99
|
else
|
100
|
-
fail "something bad happened: " +
|
100
|
+
fail "something bad happened: " + err.inspect
|
101
101
|
end
|
102
102
|
end
|
103
|
-
end
|
104
103
|
|
105
|
-
|
104
|
+
c.set(0, "/foo", "zomg!", &f)
|
105
|
+
end
|
106
106
|
end
|
107
107
|
|
108
108
|
## Consistency
|
@@ -128,22 +128,39 @@ stores history as far back as it is configured to hold it. The default is
|
|
128
128
|
|
129
129
|
## High Availability
|
130
130
|
|
131
|
-
|
131
|
+
Fraggle has mechanisms to gracefully deal with connection loss. They are:
|
132
132
|
|
133
133
|
*Resend / Connection loss*
|
134
134
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
135
|
+
When a connection is lost and Fraggle successfully reconnects to another
|
136
|
+
Doozer node, Fraggle will resend most pending requests to the new connection.
|
137
|
+
This means you will not miss events; Even events that happened while you were
|
138
|
+
disconnected! All read commands will pick up where they left off. This is
|
139
|
+
valuable to understand because it means you don't need to code for failure on
|
140
|
+
reads; Fraggle gracefully handles it for you.
|
141
|
+
|
142
|
+
Write commands will be resent if their `rev` is greater than 0. These are
|
143
|
+
idempotent requests. A rev of 0 will cause that request's error
|
144
|
+
callback to be invoked with a Fraggle::Connection::Disconnected response.
|
145
|
+
You will have to handle these yourself because Fraggle cannot know whether or
|
146
|
+
not it's safe to retry on your behalf.
|
147
|
+
|
148
|
+
**attempt**
|
149
|
+
|
150
|
+
Before fraggle will attempt a new address after connection loss, it calls the
|
151
|
+
block given to `Fraggle::Client#attempt`. If the block returns `false`,
|
152
|
+
Fraggle will not attempt that address or anymore. The block is called with on
|
153
|
+
parameter `addr`, which is the address being attempted.
|
154
|
+
|
155
|
+
Example:
|
156
|
+
|
157
|
+
c = Fraggle.connect
|
158
|
+
|
159
|
+
c.attempt do |addr|
|
160
|
+
addr =~ /^127\.*$/ # don't connect to localhost doozers
|
161
|
+
end
|
162
|
+
|
163
|
+
The default `attempt` is `Proc.new {|_| true }`
|
147
164
|
|
148
165
|
## Commands
|
149
166
|
|
data/bench/gs.rb
CHANGED
@@ -10,7 +10,7 @@ require "statsample"
|
|
10
10
|
|
11
11
|
$stdout.sync = true
|
12
12
|
|
13
|
-
abort("
|
13
|
+
abort("gs <[get|set]> <total> <width> [verbose]") if (ARGV.size < 2)
|
14
14
|
op = ARGV.shift.to_sym
|
15
15
|
total = ARGV.shift.to_i
|
16
16
|
width = ARGV.shift.to_i
|
@@ -19,59 +19,69 @@ latencies = []
|
|
19
19
|
sent_at = nil
|
20
20
|
|
21
21
|
EM.run do
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
Fraggle.connect do |c, err|
|
23
|
+
if err
|
24
|
+
raise err.message
|
25
|
+
end
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
latency = received_at - sent_at
|
27
|
+
sent = 0
|
28
|
+
received = 0
|
29
|
+
start = Time.now
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
38
|
-
if (received == total)
|
39
|
-
EM.stop
|
40
|
-
elapsed = Time.now - start
|
41
|
-
vector = latencies.to_scale
|
42
|
-
$stdout.puts
|
43
|
-
$stdout.puts("total=#{total}")
|
44
|
-
$stdout.puts("elapsed=#{elapsed}")
|
45
|
-
$stdout.puts("rate=#{total / elapsed}")
|
46
|
-
$stdout.puts("mean=#{vector.mean}")
|
47
|
-
$stdout.puts("sd=#{vector.sd}")
|
48
|
-
$stdout.puts("perc90=#{vector.percentil(90)}")
|
49
|
-
$stdout.puts("perc99=#{vector.percentil(99)}")
|
50
|
-
$stdout.puts("max=#{vector.max}")
|
51
|
-
end
|
52
|
-
end
|
31
|
+
f = Proc.new do |r, err|
|
32
|
+
if err
|
33
|
+
p [:err, err]
|
34
|
+
next
|
35
|
+
end
|
53
36
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
sent_at = Time.now
|
60
|
-
sent += 1
|
37
|
+
received_at = Time.now
|
38
|
+
received +=1
|
39
|
+
latency = received_at - sent_at
|
40
|
+
|
41
|
+
latencies << latency
|
61
42
|
if verbose
|
62
|
-
$stdout.puts("
|
43
|
+
$stdout.puts("received=#{received} ok=#{r.ok?} rev=#{r.rev} latency=#{latency}")
|
44
|
+
elsif (received % 10 == 0)
|
45
|
+
$stdout.print(".")
|
46
|
+
end
|
47
|
+
if (received == total)
|
48
|
+
EM.stop
|
49
|
+
elapsed = Time.now - start
|
50
|
+
vector = latencies.to_scale
|
51
|
+
$stdout.puts
|
52
|
+
$stdout.puts("total=#{total}")
|
53
|
+
$stdout.puts("elapsed=#{elapsed}")
|
54
|
+
$stdout.puts("rate=#{total / elapsed}")
|
55
|
+
$stdout.puts("mean=#{vector.mean}")
|
56
|
+
$stdout.puts("sd=#{vector.sd}")
|
57
|
+
$stdout.puts("perc90=#{vector.percentil(90)}")
|
58
|
+
$stdout.puts("perc99=#{vector.percentil(99)}")
|
59
|
+
$stdout.puts("max=#{vector.max}")
|
63
60
|
end
|
61
|
+
end
|
62
|
+
|
63
|
+
tick = Proc.new do
|
64
|
+
if (sent == total)
|
65
|
+
# done sending
|
66
|
+
elsif ((sent - received) < width)
|
67
|
+
# pipe open
|
68
|
+
sent_at = Time.now
|
69
|
+
sent += 1
|
70
|
+
if verbose
|
71
|
+
$stdout.puts("sent=#{sent}")
|
72
|
+
end
|
64
73
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
74
|
+
case op
|
75
|
+
when :get
|
76
|
+
c.get(nil, "/processes/#{sent}", &f)
|
77
|
+
when :set
|
78
|
+
c.set(Fraggle::Clobber, "/processes/#{sent}", "1", &f)
|
79
|
+
end
|
80
|
+
else
|
81
|
+
# pipe closed
|
70
82
|
end
|
71
|
-
|
72
|
-
# pipe closed
|
83
|
+
EM.next_tick(&tick)
|
73
84
|
end
|
74
|
-
|
85
|
+
tick.call
|
75
86
|
end
|
76
|
-
tick.call
|
77
87
|
end
|
data/example/getdir.rb
CHANGED
@@ -2,28 +2,28 @@ require 'rubygems'
|
|
2
2
|
require 'fraggle'
|
3
3
|
|
4
4
|
EM.run do
|
5
|
-
c = Fraggle.connect
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
c = Fraggle.connect do |c, err|
|
6
|
+
c.rev do |v|
|
7
|
+
# Valid
|
8
|
+
req = c.getdir(v, "/ctl/node") do |ents, err|
|
9
|
+
if err
|
10
|
+
p [:err, err]
|
11
|
+
else
|
12
|
+
ents.each do |e|
|
13
|
+
puts File.join(req.path, e.path)
|
14
|
+
end
|
15
15
|
end
|
16
16
|
end
|
17
|
-
end
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
# Limit 0 return nothing
|
19
|
+
c.getdir(v, "/ctl/node", 0, 0) do |ents, err|
|
20
|
+
p [:ret, ents, err]
|
21
|
+
end
|
23
22
|
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
# Error
|
24
|
+
c.getdir(v, "/nothere") do |ents, err|
|
25
|
+
p [:ret, ents, err]
|
26
|
+
end
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
data/example/readme.rb
CHANGED
@@ -7,76 +7,76 @@ EM.run do
|
|
7
7
|
# other doozers until one accepts or it runs out of options; A NoAddrs
|
8
8
|
# exception will be raised if that later happens.
|
9
9
|
|
10
|
-
|
10
|
+
Fraggle.connect do |c, err|
|
11
|
+
if err
|
12
|
+
raise err.message
|
13
|
+
end
|
11
14
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
15
|
+
c.rev do |v|
|
16
|
+
c.get(v, "/foo") do |e, err|
|
17
|
+
if err
|
18
|
+
err.code # => nil
|
19
|
+
err.detail # => nil
|
20
|
+
else
|
21
|
+
e.value # => nil
|
22
|
+
e.rev # => 0
|
23
|
+
e.missing? # => true
|
24
|
+
end
|
25
|
+
|
26
|
+
p [:get, e, err]
|
21
27
|
end
|
22
28
|
|
23
|
-
|
24
|
-
|
29
|
+
## Obtain the current revision the store is at and watch from then on for
|
30
|
+
## any SET or DEL to /foo.
|
31
|
+
c.wait(v, "/foo") do |e, err|
|
32
|
+
# The event has:
|
33
|
+
# ------------------------
|
34
|
+
if err
|
35
|
+
err.code # => nil
|
36
|
+
err.detail # => nil
|
37
|
+
else
|
38
|
+
e.path # => "/foo"
|
39
|
+
e.value # => "zomg!"
|
40
|
+
e.rev # => 123
|
41
|
+
e.set? # => true
|
42
|
+
e.del? # => false
|
43
|
+
end
|
25
44
|
|
26
|
-
|
27
|
-
## any SET or DEL to /foo.
|
28
|
-
c.wait(v, "/foo") do |e, err|
|
29
|
-
# The event has:
|
30
|
-
# ------------------------
|
31
|
-
if err
|
32
|
-
err.code # => nil
|
33
|
-
err.detail # => nil
|
34
|
-
else
|
35
|
-
e.path # => "/foo"
|
36
|
-
e.value # => "zomg!"
|
37
|
-
e.rev # => 123
|
38
|
-
e.set? # => true
|
39
|
-
e.del? # => false
|
45
|
+
p [:wait, e, err]
|
40
46
|
end
|
41
|
-
|
42
|
-
p [:wait, e, err]
|
43
47
|
end
|
44
|
-
end
|
45
|
-
|
46
|
-
## Setting a key (this will trigger the watch above)
|
47
|
-
f = Proc.new do |e, err|
|
48
|
-
p [:e, e, err]
|
49
48
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
# with rev 0 (missing) and delete it during the time we may be
|
54
|
-
# disconnected.
|
55
|
-
#
|
56
|
-
# In this scenario, there are no other clients that can exist that will
|
57
|
-
# attempt to set this "lock" if it's missing then delete it. It is safe
|
58
|
-
# for us to resend the request if we were disconnected from the previous
|
59
|
-
# server before a response.
|
60
|
-
#
|
61
|
-
# See High-Availability in the README for more information about this.
|
62
|
-
#
|
63
|
-
c.set(0, "/foo", "zomg!", &f)
|
64
|
-
next
|
65
|
-
end
|
49
|
+
## Setting a key (this will trigger the watch above)
|
50
|
+
f = Proc.new do |e, err|
|
51
|
+
p [:e, e, err]
|
66
52
|
|
67
|
-
|
68
|
-
|
69
|
-
case err.code
|
53
|
+
# This case statement is undesirable. We're working
|
54
|
+
# on better error handling.
|
55
|
+
case (err && err.code rescue err)
|
56
|
+
when Fraggle::Connection::DisconnectedError
|
57
|
+
# Fraggle (for now) does not attempt a non-idempotent request. This means
|
58
|
+
# Fraggle will hand off the error to the user if there is a SET or DEL
|
59
|
+
# with rev 0 (missing) and delete it during the time we may be
|
60
|
+
# disconnected.
|
61
|
+
#
|
62
|
+
# In this scenario, there are no other clients that can exist that will
|
63
|
+
# attempt to set this "lock" if it's missing then delete it. It is safe
|
64
|
+
# for us to resend the request if we were disconnected from the previous
|
65
|
+
# server before a response.
|
66
|
+
#
|
67
|
+
# See High-Availability in the README for more information about this.
|
68
|
+
#
|
69
|
+
c.set(0, "/foo", "zomg!", &f)
|
70
70
|
when Fraggle::REV_MISMATCH
|
71
71
|
p :not_it
|
72
72
|
when nil
|
73
|
-
|
73
|
+
# Success!
|
74
74
|
p [:it, e]
|
75
75
|
else
|
76
|
-
fail "something bad happened: " +
|
76
|
+
fail "something bad happened: " + err.inspect
|
77
77
|
end
|
78
78
|
end
|
79
|
-
end
|
80
79
|
|
81
|
-
|
80
|
+
c.set(0, "/foo", "zomg!", &f)
|
81
|
+
end
|
82
82
|
end
|
data/example/walk.rb
CHANGED
@@ -2,28 +2,32 @@ require 'rubygems'
|
|
2
2
|
require 'fraggle'
|
3
3
|
|
4
4
|
EM.run do
|
5
|
-
c = Fraggle.connect
|
5
|
+
c = Fraggle.connect do |c, err|
|
6
|
+
if err
|
7
|
+
fail err.message
|
8
|
+
end
|
6
9
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
c.rev do |v|
|
11
|
+
# Valid
|
12
|
+
req = c.walk(v, "/ctl/node/**") do |ents, err|
|
13
|
+
if err
|
14
|
+
p [:err, err]
|
15
|
+
else
|
16
|
+
ents.each do |e|
|
17
|
+
puts File.join(req.path, e.path) + "=" + e.value
|
18
|
+
end
|
15
19
|
end
|
16
20
|
end
|
17
|
-
end
|
18
21
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
22
|
+
# Limit 0 return nothing
|
23
|
+
c.walk(v, "/ctl/node/**", 0, 0) do |ents, err|
|
24
|
+
p [:nothing, ents, err]
|
25
|
+
end
|
23
26
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
+
# Error
|
28
|
+
c.walk(v, "/nothere") do |ents, err|
|
29
|
+
p [:nothere, ents, err]
|
30
|
+
end
|
27
31
|
end
|
28
32
|
end
|
29
33
|
end
|
data/example/watch.rb
CHANGED
@@ -2,11 +2,15 @@ require 'rubygems'
|
|
2
2
|
require 'fraggle'
|
3
3
|
|
4
4
|
EM.run do
|
5
|
-
c = Fraggle.connect
|
5
|
+
c = Fraggle.connect do |c, err|
|
6
|
+
if err
|
7
|
+
fail err.message
|
8
|
+
end
|
6
9
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
+
c.rev do |v|
|
11
|
+
c.watch(v, "/ctl/node/**") do |e, err|
|
12
|
+
p [e, err]
|
13
|
+
end
|
10
14
|
end
|
11
15
|
end
|
12
16
|
end
|
data/lib/fraggle.rb
CHANGED
@@ -12,10 +12,10 @@ module Fraggle
|
|
12
12
|
"ca=127.0.0.1:8043"
|
13
13
|
].join("&")
|
14
14
|
|
15
|
-
def self.connect(uri=nil)
|
15
|
+
def self.connect(uri=nil, &blk)
|
16
16
|
uri = uri || ENV["DOOZER_URI"] || DEFAULT_URI
|
17
17
|
|
18
|
-
addrs = uri(uri)
|
18
|
+
addrs, sk = uri(uri)
|
19
19
|
|
20
20
|
if addrs.length == 0
|
21
21
|
raise ArgumentError, "there were no addrs supplied in the uri (#{uri.inspect})"
|
@@ -25,22 +25,35 @@ module Fraggle
|
|
25
25
|
host, port = addr.split(":")
|
26
26
|
|
27
27
|
cn = EM.connect(host, port, Connection, addr)
|
28
|
-
Client.new(cn, addrs)
|
28
|
+
c = Client.new(cn, addrs)
|
29
|
+
c.access(sk) do |_, err|
|
30
|
+
if err
|
31
|
+
blk.call(nil, err)
|
32
|
+
else
|
33
|
+
blk.call(c, nil)
|
34
|
+
end
|
35
|
+
end
|
29
36
|
end
|
30
37
|
|
31
38
|
def self.uri(u)
|
39
|
+
addrs, sk = [], ""
|
40
|
+
|
32
41
|
if u =~ /^doozer:\?(.*)$/
|
33
42
|
parts = $1.split("&")
|
34
|
-
parts.
|
43
|
+
parts.each do |pt|
|
35
44
|
k, v = pt.split("=")
|
36
|
-
|
37
|
-
|
45
|
+
case k
|
46
|
+
when "ca"
|
47
|
+
addrs << v
|
48
|
+
when "sk"
|
49
|
+
sk = v
|
38
50
|
end
|
39
|
-
m
|
40
51
|
end
|
41
52
|
else
|
42
53
|
raise ArgumentError, "invalid doozer uri"
|
43
54
|
end
|
55
|
+
|
56
|
+
[addrs, sk]
|
44
57
|
end
|
45
58
|
|
46
59
|
end
|
data/lib/fraggle/client.rb
CHANGED
@@ -7,13 +7,11 @@ module Fraggle
|
|
7
7
|
|
8
8
|
MaxInt64 = 1<<63 - 1
|
9
9
|
|
10
|
-
class NoMoreAddrs < StandardError
|
11
|
-
end
|
12
|
-
|
13
10
|
attr_reader :cn, :addrs
|
14
11
|
|
15
12
|
def initialize(cn, addrs)
|
16
13
|
@cn, @addrs = cn, addrs
|
14
|
+
@attempt = Proc.new {|_| true }
|
17
15
|
end
|
18
16
|
|
19
17
|
def addr
|
@@ -187,11 +185,18 @@ module Fraggle
|
|
187
185
|
end
|
188
186
|
end
|
189
187
|
|
188
|
+
##
|
189
|
+
# Setting `blk` will cause a client to call it before attempting to reconnect.
|
190
|
+
# `blk` is called with one parameter `addr`, which is the address that will be
|
191
|
+
# for reconnect.
|
192
|
+
def attempt(&blk)
|
193
|
+
@attempt = blk
|
194
|
+
end
|
195
|
+
|
190
196
|
def reconnect!
|
191
|
-
|
197
|
+
addr = @addrs.slice(rand(@addrs.length))
|
198
|
+
if @attempt.call(addr)
|
192
199
|
reconnect(addr)
|
193
|
-
else
|
194
|
-
raise NoMoreAddrs
|
195
200
|
end
|
196
201
|
end
|
197
202
|
|
data/lib/fraggle/version.rb
CHANGED
data/test/fraggle_client_test.rb
CHANGED
@@ -31,7 +31,7 @@ class FraggleClientTest < Test::Unit::TestCase
|
|
31
31
|
res = reply(req.tag, :err_code => E::OTHER)
|
32
32
|
c.cn.receive_response(res)
|
33
33
|
|
34
|
-
assert_equal [[nil, C::ResponseError.new(res)]], log
|
34
|
+
assert_equal [[nil, C::ResponseError.new(res)]], log
|
35
35
|
end
|
36
36
|
|
37
37
|
def test_reconnect_without_pending_requests
|
@@ -50,7 +50,7 @@ class FraggleClientTest < Test::Unit::TestCase
|
|
50
50
|
assert exp.include?(c.cn.addr), "#{c.cn.addr.inspect} not in #{exp.inspect}"
|
51
51
|
|
52
52
|
# If the client can handle an error, it should not mention it to the user.
|
53
|
-
assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], log
|
53
|
+
assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], log
|
54
54
|
end
|
55
55
|
|
56
56
|
def test_reconnect_with_pending_request
|
@@ -68,7 +68,7 @@ class FraggleClientTest < Test::Unit::TestCase
|
|
68
68
|
|
69
69
|
assert exp.include?(c.cn.addr), "#{c.cn.addr.inspect} not in #{exp.inspect}"
|
70
70
|
|
71
|
-
assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], log
|
71
|
+
assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], log
|
72
72
|
end
|
73
73
|
|
74
74
|
def test_reconnect_with_multiple_pending_requests
|
@@ -89,12 +89,9 @@ class FraggleClientTest < Test::Unit::TestCase
|
|
89
89
|
|
90
90
|
assert exp.include?(c.cn.addr), "#{c.cn.addr.inspect} not in #{exp.inspect}"
|
91
91
|
|
92
|
-
# Reconnect should only be called once.
|
93
|
-
assert_equal exp.length - 1, c.addrs.length
|
94
|
-
|
95
92
|
# If the client can handle an error, it should not mention it to the user.
|
96
|
-
assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], loga
|
97
|
-
assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], logb
|
93
|
+
assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], loga
|
94
|
+
assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], logb
|
98
95
|
end
|
99
96
|
|
100
97
|
def test_resend_pending_requests
|
@@ -117,7 +114,7 @@ class FraggleClientTest < Test::Unit::TestCase
|
|
117
114
|
|
118
115
|
assert_equal [one], c.cn.sent
|
119
116
|
|
120
|
-
assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], zlog
|
117
|
+
assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], zlog
|
121
118
|
end
|
122
119
|
|
123
120
|
def test_idemp_unhandled_error
|
@@ -127,7 +124,7 @@ class FraggleClientTest < Test::Unit::TestCase
|
|
127
124
|
res = reply(req.tag, :err_code => E::OTHER)
|
128
125
|
c.cn.receive_response(res)
|
129
126
|
|
130
|
-
assert_equal [[nil, C::ResponseError.new(res)]], log
|
127
|
+
assert_equal [[nil, C::ResponseError.new(res)]], log
|
131
128
|
end
|
132
129
|
|
133
130
|
###
|
data/test/fraggle_test.rb
CHANGED
@@ -3,9 +3,10 @@ require 'fraggle'
|
|
3
3
|
class FraggleTest < Test::Unit::TestCase
|
4
4
|
|
5
5
|
def test_uri
|
6
|
-
uri = "doozer:?ca=1:1&ca=2:2&ca=3:3&ignore=this"
|
7
|
-
addrs = Fraggle.uri(uri)
|
6
|
+
uri = "doozer:?ca=1:1&ca=2:2&ca=3:3&ignore=this&sk=foo"
|
7
|
+
addrs, sk = Fraggle.uri(uri)
|
8
8
|
assert_equal ["1:1", "2:2", "3:3"], addrs
|
9
|
+
assert_equal "foo", sk
|
9
10
|
end
|
10
11
|
|
11
12
|
end
|
@@ -18,7 +18,7 @@ class FraggleTransactionTest < Test::Unit::TestCase
|
|
18
18
|
assert_equal 2, cn.send_request(req, _).tag
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
21
|
+
def test
|
22
22
|
req, log = request(V::REV)
|
23
23
|
|
24
24
|
cn.send_request(req, log)
|
@@ -26,7 +26,7 @@ class FraggleTransactionTest < Test::Unit::TestCase
|
|
26
26
|
res = reply(req.tag)
|
27
27
|
cn.receive_response(res)
|
28
28
|
|
29
|
-
assert_equal [[res, nil]], log
|
29
|
+
assert_equal [[res, nil]], log
|
30
30
|
end
|
31
31
|
|
32
32
|
def test_error
|
@@ -38,10 +38,10 @@ class FraggleTransactionTest < Test::Unit::TestCase
|
|
38
38
|
cn.receive_response(res)
|
39
39
|
|
40
40
|
err = C::ResponseError.new(res)
|
41
|
-
assert_equal [[nil, err]], log
|
41
|
+
assert_equal [[nil, err]], log
|
42
42
|
end
|
43
43
|
|
44
|
-
def
|
44
|
+
def test_i_tag
|
45
45
|
res = reply(0, :err_code => E::OTHER)
|
46
46
|
|
47
47
|
assert_nothing_raised do
|
@@ -60,7 +60,7 @@ class FraggleTransactionTest < Test::Unit::TestCase
|
|
60
60
|
# This should be ignored
|
61
61
|
cn.receive_response(res)
|
62
62
|
|
63
|
-
assert_equal [[res, nil]], log
|
63
|
+
assert_equal [[res, nil]], log
|
64
64
|
end
|
65
65
|
|
66
66
|
def test_error_deletes_callback
|
@@ -74,7 +74,7 @@ class FraggleTransactionTest < Test::Unit::TestCase
|
|
74
74
|
# This should be ignored
|
75
75
|
cn.receive_response(res)
|
76
76
|
|
77
|
-
assert_equal [[nil, C::ResponseError.new(res)]], log
|
77
|
+
assert_equal [[nil, C::ResponseError.new(res)]], log
|
78
78
|
end
|
79
79
|
|
80
80
|
def test_cannot_reuse_sent_request
|
@@ -96,9 +96,9 @@ class FraggleTransactionTest < Test::Unit::TestCase
|
|
96
96
|
|
97
97
|
cn.unbind
|
98
98
|
|
99
|
-
assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], al
|
100
|
-
assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], bl
|
101
|
-
assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], cl
|
99
|
+
assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], al
|
100
|
+
assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], bl
|
101
|
+
assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], cl
|
102
102
|
end
|
103
103
|
|
104
104
|
def test_send_when_disconnected
|
@@ -111,6 +111,6 @@ class FraggleTransactionTest < Test::Unit::TestCase
|
|
111
111
|
|
112
112
|
cn.tick!
|
113
113
|
|
114
|
-
assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], log
|
114
|
+
assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], log
|
115
115
|
end
|
116
116
|
end
|
data/test/helper.rb
CHANGED
@@ -51,15 +51,9 @@ class Test::Unit::TestCase
|
|
51
51
|
F = Fraggle::Response
|
52
52
|
E = Fraggle::Response::Err
|
53
53
|
|
54
|
-
class Log
|
55
|
-
attr_reader :valid
|
56
|
-
|
57
|
-
def initialize
|
58
|
-
@valid = []
|
59
|
-
end
|
60
|
-
|
54
|
+
class Log < Array
|
61
55
|
def call(e, err)
|
62
|
-
|
56
|
+
self << [e, err]
|
63
57
|
end
|
64
58
|
|
65
59
|
def to_proc
|
metadata
CHANGED
@@ -1,15 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fraggle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 63
|
5
|
+
prerelease:
|
6
6
|
segments:
|
7
7
|
- 4
|
8
8
|
- 0
|
9
9
|
- 0
|
10
|
-
|
11
|
-
- 3
|
12
|
-
version: 4.0.0.pre.3
|
10
|
+
version: 4.0.0
|
13
11
|
platform: ruby
|
14
12
|
authors:
|
15
13
|
- Blake Mizerany
|
@@ -17,7 +15,7 @@ autorequire:
|
|
17
15
|
bindir: bin
|
18
16
|
cert_chain: []
|
19
17
|
|
20
|
-
date: 2011-
|
18
|
+
date: 2011-06-03 00:00:00 -07:00
|
21
19
|
default_executable:
|
22
20
|
dependencies:
|
23
21
|
- !ruby/object:Gem::Dependency
|
@@ -130,14 +128,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
130
128
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
129
|
none: false
|
132
130
|
requirements:
|
133
|
-
- - "
|
131
|
+
- - ">="
|
134
132
|
- !ruby/object:Gem::Version
|
135
|
-
hash:
|
133
|
+
hash: 3
|
136
134
|
segments:
|
137
|
-
-
|
138
|
-
|
139
|
-
- 1
|
140
|
-
version: 1.3.1
|
135
|
+
- 0
|
136
|
+
version: "0"
|
141
137
|
requirements: []
|
142
138
|
|
143
139
|
rubyforge_project: fraggle
|