officer 0.8.4 → 0.8.5
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/.autotest +10 -0
- data/README.markdown +3 -9
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/officer.gemspec +4 -3
- data/spec/integration/officer_spec.rb +207 -15
- metadata +6 -5
data/.autotest
ADDED
data/README.markdown
CHANGED
@@ -1,11 +1,10 @@
|
|
1
|
-
# Officer -
|
1
|
+
# Officer - Ruby lock server and client built on EventMachine
|
2
2
|
|
3
|
-
|
3
|
+
Officer is designed to help you coordinate distributed processes and avoid race conditions. Inspiration comes from [elock](http://github.com/dustin/elock).
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
7
|
-
|
8
|
-
sudo gem install officer
|
7
|
+
gem install officer
|
9
8
|
|
10
9
|
## Usage
|
11
10
|
|
@@ -101,11 +100,6 @@ Options:
|
|
101
100
|
client.my_locks
|
102
101
|
|
103
102
|
|
104
|
-
## Planned Features
|
105
|
-
|
106
|
-
- Server: configure the daemons gem to allow multiple server processes to run on one box.
|
107
|
-
- Tests
|
108
|
-
|
109
103
|
## Copyright
|
110
104
|
|
111
105
|
Copyright (c) 2010 Chad Remesch. See LICENSE for details.
|
data/Rakefile
CHANGED
@@ -7,8 +7,8 @@ Jeweler::Tasks.new do |gem|
|
|
7
7
|
gem.name = "officer"
|
8
8
|
gem.homepage = "http://github.com/chadrem/officer"
|
9
9
|
gem.license = "MIT"
|
10
|
-
gem.summary = %Q{
|
11
|
-
gem.description = %Q{
|
10
|
+
gem.summary = %Q{Ruby lock server and client built on EventMachine.}
|
11
|
+
gem.description = %Q{Officer is designed to help you coordinate distributed processes and avoid race conditions.}
|
12
12
|
gem.email = "chad@remesch.com"
|
13
13
|
gem.authors = ["Chad Remesch"]
|
14
14
|
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.8.
|
1
|
+
0.8.5
|
data/officer.gemspec
CHANGED
@@ -5,13 +5,13 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{officer}
|
8
|
-
s.version = "0.8.
|
8
|
+
s.version = "0.8.5"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Chad Remesch"]
|
12
12
|
s.date = %q{2011-01-22}
|
13
13
|
s.default_executable = %q{officer}
|
14
|
-
s.description = %q{
|
14
|
+
s.description = %q{Officer is designed to help you coordinate distributed processes and avoid race conditions.}
|
15
15
|
s.email = %q{chad@remesch.com}
|
16
16
|
s.executables = ["officer"]
|
17
17
|
s.extra_rdoc_files = [
|
@@ -19,6 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
"README.markdown"
|
20
20
|
]
|
21
21
|
s.files = [
|
22
|
+
".autotest",
|
22
23
|
".document",
|
23
24
|
".rspec",
|
24
25
|
"LICENSE",
|
@@ -41,7 +42,7 @@ Gem::Specification.new do |s|
|
|
41
42
|
s.licenses = ["MIT"]
|
42
43
|
s.require_paths = ["lib"]
|
43
44
|
s.rubygems_version = %q{1.3.7}
|
44
|
-
s.summary = %q{
|
45
|
+
s.summary = %q{Ruby lock server and client built on EventMachine.}
|
45
46
|
s.test_files = [
|
46
47
|
"spec/integration/officer_spec.rb",
|
47
48
|
"spec/spec_helper.rb"
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
require "benchmark"
|
2
3
|
|
3
4
|
describe Officer do
|
4
5
|
before do
|
@@ -11,7 +12,7 @@ describe Officer do
|
|
11
12
|
@server_thread.terminate
|
12
13
|
end
|
13
14
|
|
14
|
-
|
15
|
+
describe "COMMAND: with_lock" do
|
15
16
|
before do
|
16
17
|
@client = Officer::Client.new
|
17
18
|
end
|
@@ -21,22 +22,22 @@ describe Officer do
|
|
21
22
|
@client = nil
|
22
23
|
end
|
23
24
|
|
24
|
-
it "should allow a client to request its locks" do
|
25
|
-
@client.my_locks.should eq({"value"=>[], "result"=>"locks"})
|
26
|
-
end
|
27
|
-
|
28
|
-
it "should allow a client to request and release a lock using non-block syntax" do
|
29
|
-
@client.lock("testlock")
|
30
|
-
@client.my_locks.should eq({"value"=>["testlock"], "result"=>"locks"})
|
31
|
-
@client.unlock("testlock")
|
32
|
-
@client.my_locks.should eq({"value"=>[], "result"=>"locks"})
|
33
|
-
end
|
34
|
-
|
35
25
|
it "should allow a client to request and release a lock using block syntax" do
|
36
26
|
@client.with_lock("testlock") do
|
37
27
|
@client.my_locks.should eq({"value"=>["testlock"], "result"=>"locks"})
|
38
28
|
end
|
39
29
|
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "COMMAND: reset" do
|
33
|
+
before do
|
34
|
+
@client = Officer::Client.new
|
35
|
+
end
|
36
|
+
|
37
|
+
after do
|
38
|
+
@client.send("disconnect")
|
39
|
+
@client = nil
|
40
|
+
end
|
40
41
|
|
41
42
|
it "should allow a client to reset all of its locks (release them all)" do
|
42
43
|
@client.lock("testlock1")
|
@@ -47,10 +48,36 @@ describe Officer do
|
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
50
|
-
|
51
|
+
describe "COMMAND: reconnect" do
|
52
|
+
before do
|
53
|
+
@client = Officer::Client.new
|
54
|
+
end
|
55
|
+
|
56
|
+
after do
|
57
|
+
@client.send("disconnect")
|
58
|
+
@client = nil
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should allow a client to force a reconnect in order to get a new socket" do
|
62
|
+
original_socket = @client.instance_variable_get("@socket")
|
63
|
+
@client.reconnect
|
64
|
+
@client.instance_variable_get("@socket").should_not eq(original_socket)
|
65
|
+
@client.my_locks.should eq({"value"=>[], "result"=>"locks"})
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "COMMAND: connections" do
|
51
70
|
before do
|
52
71
|
@client1 = Officer::Client.new
|
53
72
|
@client2 = Officer::Client.new
|
73
|
+
|
74
|
+
@client1_src_port = @client1.instance_variable_get('@socket').addr[1]
|
75
|
+
@client2_src_port = @client2.instance_variable_get('@socket').addr[1]
|
76
|
+
|
77
|
+
@client1.lock("client1_testlock1")
|
78
|
+
@client1.lock("client1_testlock2")
|
79
|
+
@client2.lock("client2_testlock1")
|
80
|
+
@client2.lock("client2_testlock2")
|
54
81
|
end
|
55
82
|
|
56
83
|
after do
|
@@ -60,12 +87,177 @@ describe Officer do
|
|
60
87
|
@client2 = nil
|
61
88
|
end
|
62
89
|
|
63
|
-
it "should allow a client to see all the
|
90
|
+
it "should allow a client to see all the connections to a server" do
|
91
|
+
connections = @client2.connections
|
92
|
+
|
93
|
+
connections["value"]["127.0.0.1:#{@client1_src_port}"].should eq(["client1_testlock1", "client1_testlock2"])
|
94
|
+
connections["value"]["127.0.0.1:#{@client2_src_port}"].should eq(["client2_testlock1", "client2_testlock2"])
|
95
|
+
connections["value"].keys.length.should eq(2)
|
96
|
+
connections["result"].should eq("connections")
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "COMMAND: locks" do
|
101
|
+
before do
|
102
|
+
@client1 = Officer::Client.new
|
103
|
+
@client2 = Officer::Client.new
|
104
|
+
|
105
|
+
@client1_src_port = @client1.instance_variable_get('@socket').addr[1]
|
106
|
+
@client2_src_port = @client2.instance_variable_get('@socket').addr[1]
|
107
|
+
|
64
108
|
@client1.lock("client1_testlock1")
|
65
109
|
@client1.lock("client1_testlock2")
|
66
110
|
@client2.lock("client2_testlock1")
|
67
111
|
@client2.lock("client2_testlock2")
|
68
|
-
|
112
|
+
end
|
113
|
+
|
114
|
+
after do
|
115
|
+
@client1.send("disconnect")
|
116
|
+
@client1 = nil
|
117
|
+
@client2.send("disconnect")
|
118
|
+
@client2 = nil
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should allow a client to see all the locks on a server (including those owned by other clients)" do
|
122
|
+
locks = @client2.locks
|
123
|
+
|
124
|
+
locks["value"]["client1_testlock1"].should eq(["127.0.0.1:#{@client1_src_port}"])
|
125
|
+
locks["value"]["client1_testlock2"].should eq(["127.0.0.1:#{@client1_src_port}"])
|
126
|
+
locks["value"]["client2_testlock1"].should eq(["127.0.0.1:#{@client2_src_port}"])
|
127
|
+
locks["value"]["client2_testlock2"].should eq(["127.0.0.1:#{@client2_src_port}"])
|
128
|
+
locks["value"].length.should eq(4)
|
129
|
+
locks["result"].should eq("locks")
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe "COMMAND: my_locks" do
|
134
|
+
before do
|
135
|
+
@client = Officer::Client.new
|
136
|
+
end
|
137
|
+
|
138
|
+
after do
|
139
|
+
@client.send("disconnect")
|
140
|
+
@client = nil
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should allow a client to request its locks" do
|
144
|
+
@client.my_locks.should eq({"value"=>[], "result"=>"locks"})
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe "COMMAND: lock & unlock" do
|
149
|
+
describe "basic functionality" do
|
150
|
+
before do
|
151
|
+
@client = Officer::Client.new
|
152
|
+
end
|
153
|
+
|
154
|
+
after do
|
155
|
+
@client.send("disconnect")
|
156
|
+
@client = nil
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should allow a client to request and release a lock" do
|
160
|
+
@client.lock("testlock").should eq({"result" => "acquired", "name" => "testlock"})
|
161
|
+
@client.my_locks.should eq({"value"=>["testlock"], "result"=>"locks"})
|
162
|
+
@client.unlock("testlock")
|
163
|
+
@client.my_locks.should eq({"value"=>[], "result"=>"locks"})
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
describe "locking options" do
|
168
|
+
describe "OPTION: timeout" do
|
169
|
+
before do
|
170
|
+
@client1 = Officer::Client.new
|
171
|
+
@client2 = Officer::Client.new
|
172
|
+
|
173
|
+
@client1_src_port = @client1.instance_variable_get('@socket').addr[1]
|
174
|
+
@client2_src_port = @client2.instance_variable_get('@socket').addr[1]
|
175
|
+
|
176
|
+
@client1.lock("testlock")
|
177
|
+
end
|
178
|
+
|
179
|
+
after do
|
180
|
+
@client1.send("disconnect")
|
181
|
+
@client1 = nil
|
182
|
+
@client2.send("disconnect")
|
183
|
+
@client2 = nil
|
184
|
+
end
|
185
|
+
|
186
|
+
it "should allow a client to set an instant timeout when obtaining a lock" do
|
187
|
+
@client2.lock("testlock", :timeout => 0).should eq(
|
188
|
+
{"result"=>"timed_out", "name"=>"testlock", "queue"=>["127.0.0.1:#{@client1_src_port}"]}
|
189
|
+
)
|
190
|
+
end
|
191
|
+
|
192
|
+
it "should allow a client to set a positive integer timeout when obtaining a lock" do
|
193
|
+
time = Benchmark.realtime do
|
194
|
+
@client2.lock("testlock", :timeout => 1).should eq(
|
195
|
+
{"result"=>"timed_out", "name"=>"testlock", "queue"=>["127.0.0.1:#{@client1_src_port}"]}
|
196
|
+
)
|
197
|
+
end
|
198
|
+
time.should > 1
|
199
|
+
time.should < 1.5
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
describe "OPTION: queue_max" do
|
204
|
+
before do
|
205
|
+
end
|
206
|
+
|
207
|
+
after do
|
208
|
+
@thread1.terminate
|
209
|
+
@thread2.terminate
|
210
|
+
end
|
211
|
+
|
212
|
+
it "should allow a client to abort when obtaining a lock if too many other clients are waiting for the same lock" do
|
213
|
+
@client1 = Officer::Client.new
|
214
|
+
@client1.lock("testlock")
|
215
|
+
|
216
|
+
@thread1 = Thread.new {
|
217
|
+
@client2 = Officer::Client.new
|
218
|
+
@client2.lock("testlock")
|
219
|
+
raise "This should never execute since the lock request should block"
|
220
|
+
}
|
221
|
+
|
222
|
+
@thread2 = Thread.new {
|
223
|
+
@client3 = Officer::Client.new
|
224
|
+
@client3.lock("testlock")
|
225
|
+
raise "This should never execute since the lock request should block"
|
226
|
+
}
|
227
|
+
|
228
|
+
sleep(0.25) # Allow thread 1 & 2 time to run.
|
229
|
+
|
230
|
+
@thread1.status.should eq("sleep")
|
231
|
+
@thread2.status.should eq("sleep")
|
232
|
+
|
233
|
+
client1_src_port = @client1.instance_variable_get('@socket').addr[1]
|
234
|
+
client2_src_port = @client2.instance_variable_get('@socket').addr[1]
|
235
|
+
client3_src_port = @client3.instance_variable_get('@socket').addr[1]
|
236
|
+
|
237
|
+
@client4 = Officer::Client.new
|
238
|
+
@client4.lock("testlock", :queue_max => 3).should eq(
|
239
|
+
{"result" => "queue_maxed", "name" => "testlock", "queue" =>
|
240
|
+
["127.0.0.1:#{client1_src_port}", "127.0.0.1:#{client2_src_port}", "127.0.0.1:#{client3_src_port}"]}
|
241
|
+
)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
describe "OPTION: namespace" do
|
246
|
+
before do
|
247
|
+
@client = Officer::Client.new(:namespace => "myapp")
|
248
|
+
end
|
249
|
+
|
250
|
+
after do
|
251
|
+
@client.send("disconnect")
|
252
|
+
@client = nil
|
253
|
+
end
|
254
|
+
|
255
|
+
it "should allow a client to set a namespace when obtaining a lock" do
|
256
|
+
@client.with_lock("testlock") do
|
257
|
+
@client.locks["value"]["myapp:testlock"].should_not eq(nil)
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
69
261
|
end
|
70
262
|
end
|
71
263
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: officer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 53
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 8
|
9
|
-
-
|
10
|
-
version: 0.8.
|
9
|
+
- 5
|
10
|
+
version: 0.8.5
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Chad Remesch
|
@@ -90,7 +90,7 @@ dependencies:
|
|
90
90
|
version: "0"
|
91
91
|
type: :runtime
|
92
92
|
version_requirements: *id005
|
93
|
-
description:
|
93
|
+
description: Officer is designed to help you coordinate distributed processes and avoid race conditions.
|
94
94
|
email: chad@remesch.com
|
95
95
|
executables:
|
96
96
|
- officer
|
@@ -100,6 +100,7 @@ extra_rdoc_files:
|
|
100
100
|
- LICENSE
|
101
101
|
- README.markdown
|
102
102
|
files:
|
103
|
+
- .autotest
|
103
104
|
- .document
|
104
105
|
- .rspec
|
105
106
|
- LICENSE
|
@@ -150,7 +151,7 @@ rubyforge_project:
|
|
150
151
|
rubygems_version: 1.3.7
|
151
152
|
signing_key:
|
152
153
|
specification_version: 3
|
153
|
-
summary:
|
154
|
+
summary: Ruby lock server and client built on EventMachine.
|
154
155
|
test_files:
|
155
156
|
- spec/integration/officer_spec.rb
|
156
157
|
- spec/spec_helper.rb
|