beanstalk-client 0.9.0 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +7 -0
- data/Manifest.txt +0 -1
- data/lib/beanstalk-client/connection.rb +100 -97
- data/lib/beanstalk-client/errors.rb +20 -4
- data/lib/beanstalk-client/version.rb +1 -1
- data/website/index.html +1 -1
- metadata +2 -3
- data/lib/beanstalk-client/bag.rb +0 -36
data/History.txt
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
== 0.10.0 2008-04-11
|
2
|
+
|
3
|
+
* Some optimizations to avoid sending unnecessary use and watch commands.
|
4
|
+
* Use newer protocol features to open only one connection per server address.
|
5
|
+
* More consistent and complete peek methods.
|
6
|
+
* Various bug fixes.
|
7
|
+
|
1
8
|
== 0.9.0 2008-02-27
|
2
9
|
|
3
10
|
* Skipping 0.8.x; beanstalkd 0.8 was a botched release.
|
data/Manifest.txt
CHANGED
@@ -19,18 +19,19 @@ require 'socket'
|
|
19
19
|
require 'fcntl'
|
20
20
|
require 'yaml'
|
21
21
|
require 'set'
|
22
|
-
require 'beanstalk-client/bag'
|
23
22
|
require 'beanstalk-client/errors'
|
24
23
|
require 'beanstalk-client/job'
|
25
24
|
|
26
25
|
module Beanstalk
|
27
|
-
class
|
26
|
+
class Connection
|
28
27
|
attr_reader :addr
|
29
28
|
|
30
29
|
def initialize(addr, jptr=self)
|
31
30
|
@addr = addr
|
32
31
|
@jptr = jptr
|
33
32
|
connect
|
33
|
+
@last_used = 'default'
|
34
|
+
@watch_list = ['default']
|
34
35
|
end
|
35
36
|
|
36
37
|
def connect
|
@@ -47,98 +48,116 @@ module Beanstalk
|
|
47
48
|
end
|
48
49
|
|
49
50
|
def put(body, pri=65536, delay=0, ttr=120)
|
50
|
-
|
51
|
-
|
51
|
+
interact("put #{pri} #{delay} #{ttr} #{body.size}\r\n#{body}\r\n",
|
52
|
+
%w(INSERTED BURIED))[0].to_i
|
52
53
|
end
|
53
54
|
|
54
55
|
def yput(obj, pri=65536, delay=0, ttr=120)
|
55
56
|
put(YAML.dump(obj), pri, delay, ttr)
|
56
57
|
end
|
57
58
|
|
58
|
-
def
|
59
|
-
|
60
|
-
begin
|
61
|
-
Job.new(@jptr, *read_job('FOUND'))
|
62
|
-
rescue UnexpectedResponse
|
63
|
-
nil
|
64
|
-
end
|
59
|
+
def peek_job(id)
|
60
|
+
interact("peek #{id}\r\n", :job)
|
65
61
|
end
|
66
62
|
|
67
|
-
def
|
68
|
-
|
69
|
-
|
63
|
+
def peek_ready()
|
64
|
+
interact("peek-ready\r\n", :job)
|
65
|
+
end
|
66
|
+
|
67
|
+
def peek_delayed()
|
68
|
+
interact("peek-delayed\r\n", :job)
|
69
|
+
end
|
70
|
+
|
71
|
+
def peek_buried()
|
72
|
+
interact("peek-buried\r\n", :job)
|
70
73
|
end
|
71
74
|
|
72
75
|
def reserve()
|
76
|
+
raise WaitingForJobError if @waiting
|
73
77
|
@socket.write("reserve\r\n")
|
78
|
+
|
79
|
+
begin
|
80
|
+
@waiting = true
|
81
|
+
# Give the user a chance to select on multiple fds.
|
82
|
+
Beanstalk.select.call([@socket]) if Beanstalk.select
|
83
|
+
rescue WaitingForJobError
|
84
|
+
# just continue
|
85
|
+
ensure
|
86
|
+
@waiting = false
|
87
|
+
end
|
88
|
+
|
74
89
|
Job.new(@jptr, *read_job('RESERVED'))
|
75
90
|
end
|
76
91
|
|
77
92
|
def delete(id)
|
78
|
-
|
79
|
-
check_resp('DELETED')
|
93
|
+
interact("delete #{id}\r\n", %w(DELETED))
|
80
94
|
:ok
|
81
95
|
end
|
82
96
|
|
83
97
|
def release(id, pri, delay)
|
84
|
-
|
85
|
-
check_resp('RELEASED')
|
98
|
+
interact("release #{id} #{pri} #{delay}\r\n", %w(RELEASED))
|
86
99
|
:ok
|
87
100
|
end
|
88
101
|
|
89
102
|
def bury(id, pri)
|
90
|
-
|
91
|
-
check_resp('BURIED')
|
103
|
+
interact("bury #{id} #{pri}\r\n", %w(BURIED))
|
92
104
|
:ok
|
93
105
|
end
|
94
106
|
|
95
107
|
def use(tube)
|
96
|
-
|
97
|
-
|
108
|
+
return tube if tube == @last_used
|
109
|
+
@last_used = interact("use #{tube}\r\n", %w(USING))[0]
|
98
110
|
end
|
99
111
|
|
100
112
|
def watch(tube)
|
101
|
-
@
|
102
|
-
|
113
|
+
return @watch_list.size if @watch_list.include?(tube)
|
114
|
+
r = interact("watch #{tube}\r\n", %w(WATCHING))[0].to_i
|
115
|
+
@watch_list += [tube]
|
116
|
+
return r
|
103
117
|
end
|
104
118
|
|
105
119
|
def ignore(tube)
|
106
|
-
@
|
107
|
-
|
120
|
+
return @watch_list.size if !@watch_list.include?(tube)
|
121
|
+
r = interact("ignore #{tube}\r\n", %w(WATCHING))[0].to_i
|
122
|
+
@watch_list -= [tube]
|
123
|
+
return r
|
108
124
|
end
|
109
125
|
|
110
126
|
def stats()
|
111
|
-
|
112
|
-
read_yaml('OK')
|
127
|
+
interact("stats\r\n", :yaml)
|
113
128
|
end
|
114
129
|
|
115
130
|
def job_stats(id)
|
116
|
-
|
117
|
-
read_yaml('OK')
|
131
|
+
interact("stats-job #{id}\r\n", :yaml)
|
118
132
|
end
|
119
133
|
|
120
134
|
def stats_tube(tube)
|
121
|
-
|
122
|
-
read_yaml('OK')
|
135
|
+
interact("stats-tube #{tube}\r\n", :yaml)
|
123
136
|
end
|
124
137
|
|
125
138
|
def list_tubes()
|
126
|
-
|
127
|
-
read_yaml('OK')
|
139
|
+
interact("list-tubes\r\n", :yaml)
|
128
140
|
end
|
129
141
|
|
130
142
|
def list_tube_used()
|
131
|
-
|
132
|
-
check_resp('USING')[0]
|
143
|
+
interact("list-tube-used\r\n", %w(USING))[0]
|
133
144
|
end
|
134
145
|
|
135
|
-
def list_tubes_watched()
|
136
|
-
@
|
137
|
-
|
146
|
+
def list_tubes_watched(cached=false)
|
147
|
+
return @watch_list if cached
|
148
|
+
@watch_list = interact("list-tubes-watched\r\n", :yaml)
|
138
149
|
end
|
139
150
|
|
140
151
|
private
|
141
152
|
|
153
|
+
def interact(cmd, rfmt)
|
154
|
+
raise WaitingForJobError if @waiting
|
155
|
+
@socket.write(cmd)
|
156
|
+
return read_yaml('OK') if rfmt == :yaml
|
157
|
+
return found_job if rfmt == :job
|
158
|
+
check_resp(*rfmt)
|
159
|
+
end
|
160
|
+
|
142
161
|
def get_resp()
|
143
162
|
r = @socket.gets("\r\n")
|
144
163
|
raise EOFError if r == nil
|
@@ -149,15 +168,18 @@ module Beanstalk
|
|
149
168
|
r = get_resp()
|
150
169
|
rword, *vals = r.split(/\s+/)
|
151
170
|
if (words.size > 0) and !words.include?(rword)
|
152
|
-
raise UnexpectedResponse.
|
171
|
+
raise UnexpectedResponse.classify(rword, r)
|
153
172
|
end
|
154
173
|
vals
|
155
174
|
end
|
156
175
|
|
157
|
-
def
|
158
|
-
|
159
|
-
|
176
|
+
def found_job()
|
177
|
+
Job.new(@jptr, *read_job('FOUND'))
|
178
|
+
rescue NotFoundError
|
179
|
+
nil
|
180
|
+
end
|
160
181
|
|
182
|
+
def read_job(word)
|
161
183
|
id, bytes = check_resp(word).map{|s| s.to_i}
|
162
184
|
body = read_bytes(bytes)
|
163
185
|
raise 'bad trailer' if read_bytes(2) != "\r\n"
|
@@ -179,47 +201,6 @@ module Beanstalk
|
|
179
201
|
end
|
180
202
|
end
|
181
203
|
|
182
|
-
# Same interface as RawConnection.
|
183
|
-
# With this you can reserve more than one job at a time.
|
184
|
-
class Connection
|
185
|
-
attr_reader :addr
|
186
|
-
|
187
|
-
def initialize(addr, jptr=self)
|
188
|
-
@addr = addr
|
189
|
-
@misc = RawConnection.new(addr, jptr)
|
190
|
-
@free = Bag.new{RawConnection.new(addr, jptr)}
|
191
|
-
@used = {}
|
192
|
-
end
|
193
|
-
|
194
|
-
def reserve()
|
195
|
-
c = @free.take()
|
196
|
-
j = c.reserve()
|
197
|
-
@used[j.id] = c
|
198
|
-
j
|
199
|
-
ensure
|
200
|
-
@free.give(c) if c and not j
|
201
|
-
end
|
202
|
-
|
203
|
-
def delete(id)
|
204
|
-
@used[id].delete(id)
|
205
|
-
@free.give(@used.delete(id))
|
206
|
-
end
|
207
|
-
|
208
|
-
def release(id, pri, delay)
|
209
|
-
@used[id].release(id, pri, delay)
|
210
|
-
@free.give(@used.delete(id))
|
211
|
-
end
|
212
|
-
|
213
|
-
def bury(id, pri)
|
214
|
-
@used[id].bury(id, pri)
|
215
|
-
@free.give(@used.delete(id))
|
216
|
-
end
|
217
|
-
|
218
|
-
def method_missing(selector, *args, &block)
|
219
|
-
@misc.send(selector, *args, &block)
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
204
|
class CleanupWrapper
|
224
205
|
def initialize(addr, multi)
|
225
206
|
@conn = Connection.new(addr, self)
|
@@ -266,14 +247,6 @@ module Beanstalk
|
|
266
247
|
@last_conn.addr
|
267
248
|
end
|
268
249
|
|
269
|
-
def send_to_rand_conn(sel, *args)
|
270
|
-
wrap(pick_connection, sel, *args)
|
271
|
-
end
|
272
|
-
|
273
|
-
def send_to_all_conns(sel, *args)
|
274
|
-
make_hash(@connections.map{|a, c| [a, wrap(c, sel, *args)]})
|
275
|
-
end
|
276
|
-
|
277
250
|
def put(body, pri=65536, delay=0, ttr=120)
|
278
251
|
send_to_rand_conn(:put, body, pri, delay, ttr)
|
279
252
|
end
|
@@ -332,20 +305,46 @@ module Beanstalk
|
|
332
305
|
|
333
306
|
def close
|
334
307
|
while @connections.size > 0
|
335
|
-
addr
|
308
|
+
addr = @connections.keys.last
|
309
|
+
conn = @connections[addr]
|
310
|
+
@connections.delete(addr)
|
336
311
|
conn.close
|
337
312
|
end
|
338
313
|
end
|
339
314
|
|
340
|
-
def
|
315
|
+
def peek_ready()
|
316
|
+
send_to_each_conn_first_res(:peek_ready)
|
317
|
+
end
|
318
|
+
|
319
|
+
def peek_delayed()
|
320
|
+
send_to_each_conn_first_res(:peek_delayed)
|
321
|
+
end
|
322
|
+
|
323
|
+
def peek_buried()
|
324
|
+
send_to_each_conn_first_res(:peek_buried)
|
325
|
+
end
|
326
|
+
|
327
|
+
def peek_job(id)
|
328
|
+
make_hash(send_to_all_conns(:peek_job, id))
|
329
|
+
end
|
330
|
+
|
331
|
+
private
|
332
|
+
|
333
|
+
def send_to_each_conn_first_res(sel, *args)
|
341
334
|
open_connections.each do |c|
|
342
|
-
|
343
|
-
return
|
335
|
+
x = wrap(c, sel, *args)
|
336
|
+
return x if x
|
344
337
|
end
|
345
338
|
nil
|
346
339
|
end
|
347
340
|
|
348
|
-
|
341
|
+
def send_to_rand_conn(sel, *args)
|
342
|
+
wrap(pick_connection, sel, *args)
|
343
|
+
end
|
344
|
+
|
345
|
+
def send_to_all_conns(sel, *args)
|
346
|
+
compact_hash(make_hash(@connections.map{|a, c| [a, wrap(c, sel, *args)]}))
|
347
|
+
end
|
349
348
|
|
350
349
|
def pick_connection()
|
351
350
|
open_connections[rand(open_connections.size)] or raise NotConnected
|
@@ -365,6 +364,10 @@ module Beanstalk
|
|
365
364
|
Hash[*pairs.inject([]){|a,b|a+b}]
|
366
365
|
end
|
367
366
|
|
367
|
+
def compact_hash(hash)
|
368
|
+
hash.reject{|k,v| v == nil}
|
369
|
+
end
|
370
|
+
|
368
371
|
def sum_hashes(hs)
|
369
372
|
hs.inject({}){|a,b| a.merge(b) {|k,o,n| combine_stats(k, o, n)}}
|
370
373
|
end
|
@@ -20,14 +20,30 @@ module Beanstalk
|
|
20
20
|
end
|
21
21
|
|
22
22
|
class UnexpectedResponse < RuntimeError
|
23
|
-
def self.
|
24
|
-
|
25
|
-
|
23
|
+
def self.subclasses
|
24
|
+
@classes ||= []
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.inherited(subclass)
|
28
|
+
subclasses << subclass
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.classify(word, message)
|
32
|
+
for clas in subclasses
|
33
|
+
return clas.new(message) if clas::WORD == word
|
26
34
|
end
|
27
|
-
|
35
|
+
return new(message)
|
28
36
|
end
|
29
37
|
end
|
30
38
|
|
31
39
|
class DrainingError < UnexpectedResponse
|
40
|
+
WORD = 'DRAINING'
|
41
|
+
end
|
42
|
+
|
43
|
+
class NotFoundError < UnexpectedResponse
|
44
|
+
WORD = 'NOT_FOUND'
|
45
|
+
end
|
46
|
+
|
47
|
+
class WaitingForJobError < RuntimeError
|
32
48
|
end
|
33
49
|
end
|
data/website/index.html
CHANGED
@@ -33,7 +33,7 @@
|
|
33
33
|
<h1>Beanstalk Client</h1>
|
34
34
|
<div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/beanstalk"; return false'>
|
35
35
|
<p>Get Version</p>
|
36
|
-
<a href="http://rubyforge.org/projects/beanstalk" class="numbers">0.
|
36
|
+
<a href="http://rubyforge.org/projects/beanstalk" class="numbers">0.10.0</a>
|
37
37
|
</div>
|
38
38
|
<h1>→ ‘beanstalk-client’</h1>
|
39
39
|
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: beanstalk-client
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2008-
|
6
|
+
version: 0.10.0
|
7
|
+
date: 2008-04-11 00:00:00 -07:00
|
8
8
|
summary: Ruby client library for the Beanstalk protocol
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -37,7 +37,6 @@ files:
|
|
37
37
|
- config/hoe.rb
|
38
38
|
- config/requirements.rb
|
39
39
|
- lib/beanstalk-client.rb
|
40
|
-
- lib/beanstalk-client/bag.rb
|
41
40
|
- lib/beanstalk-client/connection.rb
|
42
41
|
- lib/beanstalk-client/errors.rb
|
43
42
|
- lib/beanstalk-client/job.rb
|
data/lib/beanstalk-client/bag.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
# beanstalk-client/bag.rb - client library for beanstalk
|
2
|
-
|
3
|
-
# Copyright (C) 2007 Philotic Inc.
|
4
|
-
|
5
|
-
# This program is free software: you can redistribute it and/or modify
|
6
|
-
# it under the terms of the GNU General Public License as published by
|
7
|
-
# the Free Software Foundation, either version 3 of the License, or
|
8
|
-
# (at your option) any later version.
|
9
|
-
|
10
|
-
# This program is distributed in the hope that it will be useful,
|
11
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
-
# GNU General Public License for more details.
|
14
|
-
|
15
|
-
# You should have received a copy of the GNU General Public License
|
16
|
-
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
-
|
18
|
-
class Beanstalk::Bag
|
19
|
-
def initialize(initial_size=0, &default)
|
20
|
-
@default = default
|
21
|
-
@items = []
|
22
|
-
initial_size.times{give(default.call())}
|
23
|
-
end
|
24
|
-
|
25
|
-
def give(x)
|
26
|
-
(@items << x)[-1]
|
27
|
-
end
|
28
|
-
|
29
|
-
def take()
|
30
|
-
@items.pop or @default.call()
|
31
|
-
end
|
32
|
-
|
33
|
-
def size()
|
34
|
-
@items.size
|
35
|
-
end
|
36
|
-
end
|