ruote-beanstalk 2.1.10 → 2.1.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,147 +1,3 @@
1
- #--
2
- # Copyright (c) 2005-2010, John Mettraux, jmettraux@gmail.com
3
- #
4
- # Permission is hereby granted, free of charge, to any person obtaining a copy
5
- # of this software and associated documentation files (the "Software"), to deal
6
- # in the Software without restriction, including without limitation the rights
7
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
- # copies of the Software, and to permit persons to whom the Software is
9
- # furnished to do so, subject to the following conditions:
10
- #
11
- # The above copyright notice and this permission notice shall be included in
12
- # all copies or substantial portions of the Software.
13
- #
14
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
- # THE SOFTWARE.
21
- #
22
- # Made in Japan.
23
- #++
24
1
 
25
- require 'beanstalk-client'
26
-
27
- #require 'ruote/part/local_participant'
28
-
29
-
30
- module Ruote
31
- module Beanstalk
32
-
33
- #
34
- # This participant emits workitems towards a beanstalk queue.
35
- #
36
- # engine.register_participant(
37
- # :heavy_labour,
38
- # :reply_by_default => true, :beanstalk => '127.0.0.1:11300')
39
- #
40
- #
41
- # == workitem format
42
- #
43
- # Workitems are encoded in the format
44
- #
45
- # [ 'workitem', workitem.to_h ]
46
- #
47
- # and then serialized as JSON strings.
48
- #
49
- #
50
- # == cancel items
51
- #
52
- # Like workitems, but the format is
53
- #
54
- # [ 'cancelitem', fei.to_h, flavour.to_s ]
55
- #
56
- # where fei is the FlowExpressionId of the expression getting cancelled
57
- # (and whose workitems are to be retired) and flavour is either 'cancel' or
58
- # 'kill'.
59
- #
60
- #
61
- # == extending this participant
62
- #
63
- # Extend and overwrite encode_workitem and encode_cancelitem or
64
- # simply re-open the class and change those methods.
65
- #
66
- #
67
- # == :beanstalk
68
- #
69
- # Indicates which beanstalk to talk to
70
- #
71
- # engine.register_participant(
72
- # 'alice'
73
- # Ruote::Beanstalk::BsParticipant,
74
- # 'beanstalk' => '127.0.0.1:11300')
75
- #
76
- #
77
- # == :tube
78
- #
79
- # Most of the time, you want the workitems (or the cancelitems) to be
80
- # emitted over/in a specific tube
81
- #
82
- # engine.register_participant(
83
- # 'alice'
84
- # Ruote::Beanstalk::BsParticipant,
85
- # 'beanstalk' => '127.0.0.1:11300',
86
- # 'tube' => 'ruote-workitems')
87
- #
88
- #
89
- # == :reply_by_default
90
- #
91
- # If the participant is configured with 'reply_by_default' => true, the
92
- # participant will dispatch the workitem over to Beanstalk and then
93
- # immediately reply to its ruote engine (letting the flow resume).
94
- #
95
- # engine.register_participant(
96
- # 'alice'
97
- # Ruote::Beanstalk::BsParticipant,
98
- # 'beanstalk' => '127.0.0.1:11300',
99
- # 'reply_by_default' => true)
100
- #
101
- class BsParticipant
102
-
103
- include Ruote::LocalParticipant
104
-
105
- def initialize (opts)
106
-
107
- @opts = opts
108
- end
109
-
110
- def consume (workitem)
111
-
112
- connection.put(encode_workitem(workitem))
113
-
114
- reply(workitem) if @opts['reply_by_default']
115
- end
116
-
117
- def cancel (fei, flavour)
118
-
119
- connection.put(encode_cancelitem(fei, flavour))
120
- end
121
-
122
- def encode_workitem (workitem)
123
-
124
- Rufus::Json.encode([ 'workitem', workitem.to_h ])
125
- end
126
-
127
- def encode_cancelitem (fei, flavour)
128
-
129
- Rufus::Json.encode([ 'cancelitem', fei.to_h, flavour.to_s ])
130
- end
131
-
132
- protected
133
-
134
- def connection
135
-
136
- con = ::Beanstalk::Connection.new(@opts['beanstalk'])
137
-
138
- if tube = @opts['tube']
139
- con.use(tube)
140
- end
141
-
142
- con
143
- end
144
- end
145
- end
146
- end
2
+ require 'ruote/beanstalk/participant_proxy'
147
3
 
@@ -0,0 +1,157 @@
1
+ #--
2
+ # Copyright (c) 2005-2010, John Mettraux, jmettraux@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+ # Made in Japan.
23
+ #++
24
+
25
+ require 'beanstalk-client'
26
+
27
+ #require 'ruote/part/local_participant'
28
+
29
+
30
+ module Ruote
31
+ module Beanstalk
32
+
33
+ #
34
+ # This participant emits workitems towards a beanstalk queue.
35
+ #
36
+ # engine.register_participant(
37
+ # :heavy_labour,
38
+ # :reply_by_default => true, :beanstalk => '127.0.0.1:11300')
39
+ #
40
+ #
41
+ # == workitem format
42
+ #
43
+ # Workitems are encoded in the format
44
+ #
45
+ # [ 'workitem', workitem.to_h ]
46
+ #
47
+ # and then serialized as JSON strings.
48
+ #
49
+ #
50
+ # == cancel items
51
+ #
52
+ # Like workitems, but the format is
53
+ #
54
+ # [ 'cancelitem', fei.to_h, flavour.to_s ]
55
+ #
56
+ # where fei is the FlowExpressionId of the expression getting cancelled
57
+ # (and whose workitems are to be retired) and flavour is either 'cancel' or
58
+ # 'kill'.
59
+ #
60
+ #
61
+ # == extending this participant
62
+ #
63
+ # Extend and overwrite encode_workitem and encode_cancelitem or
64
+ # simply re-open the class and change those methods.
65
+ #
66
+ #
67
+ # == :beanstalk
68
+ #
69
+ # Indicates which beanstalk to talk to
70
+ #
71
+ # engine.register_participant(
72
+ # 'alice'
73
+ # Ruote::Beanstalk::ParticipantProxy,
74
+ # 'beanstalk' => '127.0.0.1:11300')
75
+ #
76
+ #
77
+ # == :tube
78
+ #
79
+ # Most of the time, you want the workitems (or the cancelitems) to be
80
+ # emitted over/in a specific tube
81
+ #
82
+ # engine.register_participant(
83
+ # 'alice'
84
+ # Ruote::Beanstalk::ParticipantProxy,
85
+ # 'beanstalk' => '127.0.0.1:11300',
86
+ # 'tube' => 'ruote-workitems')
87
+ #
88
+ #
89
+ # == :reply_by_default
90
+ #
91
+ # If the participant is configured with 'reply_by_default' => true, the
92
+ # participant will dispatch the workitem over to Beanstalk and then
93
+ # immediately reply to its ruote engine (letting the flow resume).
94
+ #
95
+ # engine.register_participant(
96
+ # 'alice'
97
+ # Ruote::Beanstalk::ParticipantProxy,
98
+ # 'beanstalk' => '127.0.0.1:11300',
99
+ # 'reply_by_default' => true)
100
+ #
101
+ class ParticipantProxy
102
+
103
+ include Ruote::LocalParticipant
104
+
105
+ def initialize(opts)
106
+
107
+ @opts = opts
108
+ end
109
+
110
+ def consume(workitem)
111
+
112
+ con = new_connection
113
+
114
+ con.put(encode_workitem(workitem))
115
+
116
+ reply(workitem) if @opts['reply_by_default']
117
+
118
+ ensure
119
+ con.close rescue nil
120
+ end
121
+
122
+ def cancel(fei, flavour)
123
+
124
+ con = new_connection
125
+
126
+ con.put(encode_cancelitem(fei, flavour))
127
+
128
+ ensure
129
+ con.close rescue nil
130
+ end
131
+
132
+ def encode_workitem(workitem)
133
+
134
+ Rufus::Json.encode([ 'workitem', workitem.to_h ])
135
+ end
136
+
137
+ def encode_cancelitem(fei, flavour)
138
+
139
+ Rufus::Json.encode([ 'cancelitem', fei.to_h, flavour.to_s ])
140
+ end
141
+
142
+ protected
143
+
144
+ def new_connection
145
+
146
+ con = ::Beanstalk::Connection.new(@opts['beanstalk'])
147
+
148
+ if tube = @opts['tube']
149
+ con.use(tube)
150
+ end
151
+
152
+ con
153
+ end
154
+ end
155
+ end
156
+ end
157
+
@@ -33,29 +33,29 @@ module Beanstalk
33
33
  #
34
34
  # An error class for error emitted by the "remote side" and received here.
35
35
  #
36
- class BsReceiveError < RuntimeError
36
+ class ReceiveError < RuntimeError
37
37
 
38
38
  attr_reader :fei
39
39
 
40
- def initialize (fei)
40
+ def initialize(fei)
41
41
  @fei = fei
42
42
  super("for #{Ruote::FlowExpressionId.to_storage_id(fei)}")
43
43
  end
44
44
  end
45
45
 
46
46
  #
47
- # Whereas BsParticipant emits workitems (and cancelitems) to a Beanstalk
47
+ # Whereas ParticipantProxy emits workitems(and cancelitems) to a Beanstalk
48
48
  # queue, the receiver watches a Beanstalk queue/tube.
49
49
  #
50
50
  # An example initialization :
51
51
  #
52
- # Ruote::Beanstalk::BsReceiver.new(
52
+ # Ruote::Beanstalk::Receiver.new(
53
53
  # engine, '127.0.0.1:11300', :tube => 'out')
54
54
  #
55
55
  #
56
56
  # == workitem format
57
57
  #
58
- # BsParticipant and BsReceiver share the same format :3
58
+ # ParticipantProxy and Receiver share the same format :3
59
59
  #
60
60
  # [ 'workitem', workitem_as_a_hash ]
61
61
  # # or
@@ -72,14 +72,14 @@ module Beanstalk
72
72
  #
73
73
  # Indicates to the receiver which beanstalk tube it should listen to.
74
74
  #
75
- # Ruote::Beanstalk::BsReceiver.new(
75
+ # Ruote::Beanstalk::Receiver.new(
76
76
  # engine, '127.0.0.1:11300', :tube => 'out')
77
77
  #
78
- class BsReceiver < Ruote::Receiver
78
+ class Receiver < ::Ruote::Receiver
79
79
 
80
80
  # cwes = context, worker, engine or storage
81
81
  #
82
- def initialize (cwes, beanstalk, options={})
82
+ def initialize(cwes, beanstalk, options={})
83
83
 
84
84
  super(cwes, options)
85
85
 
@@ -90,7 +90,7 @@ module Beanstalk
90
90
 
91
91
  protected
92
92
 
93
- def listen (beanstalk, tube)
93
+ def listen(beanstalk, tube)
94
94
 
95
95
  con = ::Beanstalk::Connection.new(beanstalk)
96
96
  con.watch(tube)
@@ -108,31 +108,31 @@ module Beanstalk
108
108
  end
109
109
 
110
110
  # Is meant to return a hash with a first element that is either
111
- # 'workitem', 'error' or 'launchitem' (a type).
111
+ # 'workitem', 'error' or 'launchitem'(a type).
112
112
  # The second element depends on the type.
113
- # It's mappend on Ruote::Beanstalk::BsParticipant anyway.
113
+ # It's mappend on Ruote::Beanstalk::ParticipantProxy anyway.
114
114
  #
115
- def decode (job)
115
+ def decode(job)
116
116
 
117
117
  Rufus::Json.decode(job.body)
118
118
  end
119
119
 
120
- def process (job)
120
+ def process(job)
121
121
 
122
122
  type, data = decode(job)
123
123
 
124
124
  if type == 'workitem'
125
125
 
126
- # data holds a workitem (as a Hash)
126
+ # data holds a workitem(as a Hash)
127
127
 
128
128
  reply(data)
129
129
 
130
130
  elsif type == 'error'
131
131
 
132
- # data holds a fei (FlowExpressionId) (as a Hash)
132
+ # data holds a fei(FlowExpressionId) (as a Hash)
133
133
 
134
134
  @context.error_handler.action_handle(
135
- 'dispatch', data, BsReceiveError.new(data))
135
+ 'dispatch', data, ReceiveError.new(data))
136
136
 
137
137
  elsif type == 'launchitem'
138
138
 
@@ -33,7 +33,7 @@ module Beanstalk
33
33
  #
34
34
  # An error class just for BsStorage.
35
35
  #
36
- class BsStorageError < RuntimeError
36
+ class StorageError < RuntimeError
37
37
  end
38
38
 
39
39
  #
@@ -47,9 +47,9 @@ module Beanstalk
47
47
  #
48
48
  # engine = Ruote::Engine.new(
49
49
  # Ruote::Worker.new(
50
- # Ruote::Beanstalk::BsStorage.new('127.0.0.1:11300', opts)))
50
+ # Ruote::Beanstalk::Storage.new('127.0.0.1:11300', opts)))
51
51
  #
52
- # All the operations (put, get, get_many, ...) of the storage are done
52
+ # All the operations(put, get, get_many, ...) of the storage are done
53
53
  # by a server, connected to the same beanstalk queue.
54
54
  #
55
55
  # == server
@@ -57,7 +57,7 @@ module Beanstalk
57
57
  # The storage point to a beanstalk queue and receives orders from clients
58
58
  # via the queue.
59
59
  #
60
- # Ruote::Beanstalk::BsStorage.new(':11300', 'ruote_work', :fork => true)
60
+ # Ruote::Beanstalk::Storage.new(':11300', 'ruote_work', :fork => true)
61
61
  #
62
62
  # Note the directory passed as a string. When in server mode, this storage
63
63
  # uses an embedded Ruote::FsStorage for the actual storage.
@@ -66,11 +66,11 @@ module Beanstalk
66
66
  # the Beanstalk server. The storage takes care of stopping the beanstalk
67
67
  # server when the Ruby process exits.
68
68
  #
69
- class BsStorage
69
+ class Storage
70
70
 
71
71
  include Ruote::StorageBase
72
72
 
73
- def initialize (uri, directory=nil, options=nil)
73
+ def initialize(uri, directory=nil, options=nil)
74
74
 
75
75
  @uri, address, port = split_uri(uri)
76
76
 
@@ -113,7 +113,21 @@ module Beanstalk
113
113
  serve if @cloche
114
114
  end
115
115
 
116
- def put (doc, opts={})
116
+ # One catch : will return [] in case of [network] error
117
+ #
118
+ def get_msgs
119
+
120
+ super rescue []
121
+ end
122
+
123
+ # One catch : will return true (failure) in case of [network] error
124
+ #
125
+ def reserve(doc)
126
+
127
+ super(doc) rescue true
128
+ end
129
+
130
+ def put(doc, opts={})
117
131
 
118
132
  doc.merge!('put_at' => Ruote.now_to_utc_s)
119
133
 
@@ -123,33 +137,40 @@ module Beanstalk
123
137
 
124
138
  return r unless r.nil?
125
139
 
126
- doc['_rev'] = (doc['_rev'] || -1) + 1 if opts[:update_rev]
140
+ doc['_rev'] =(doc['_rev'] || -1) + 1 if opts[:update_rev]
127
141
 
128
142
  nil
129
143
  end
130
144
 
131
- def get (type, key)
145
+ def get(type, key)
132
146
 
133
147
  return @cloche.get(type, key) if @cloche
134
148
 
135
149
  operate('get', [ type, key ])
136
150
  end
137
151
 
138
- def delete (doc)
152
+ def delete(doc)
139
153
 
140
154
  return @cloche.delete(doc) if @cloche
141
155
 
142
156
  operate('delete', [ doc ])
143
157
  end
144
158
 
145
- def get_many (type, key=nil, opts={})
159
+ def get_many(type, key=nil, opts={})
146
160
 
147
- return @cloche.get_many(type, key, opts) if @cloche
161
+ return operate('get_many', [ type, key, opts ]) unless @cloche
162
+
163
+ if key
164
+ key = Array(key).collect { |k|
165
+ k[0..6] == '(?-mix:' ? Regexp.new(k[7..-2]) : "!#{k}"
166
+ } if key
167
+ end
168
+ # assuming /!#{wfid}$/...
148
169
 
149
- operate('get_many', [ type, key, opts ])
170
+ @cloche.get_many(type, key, opts)
150
171
  end
151
172
 
152
- def ids (type)
173
+ def ids(type)
153
174
 
154
175
  return @cloche.ids(type) if @cloche
155
176
 
@@ -165,7 +186,7 @@ module Beanstalk
165
186
  end
166
187
  end
167
188
 
168
- def dump (type)
189
+ def dump(type)
169
190
 
170
191
  get_many(type)
171
192
  end
@@ -174,23 +195,28 @@ module Beanstalk
174
195
 
175
196
  Thread.list.each do |t|
176
197
  t.keys.each do |k|
177
- next unless k.match(/^BeanstalkConnection\_/)
198
+ next unless k.to_s.match(CONN_KEY)
178
199
  t[k].close
179
200
  t[k] = nil
180
201
  end
181
202
  end
182
203
  end
183
204
 
205
+ def close
206
+
207
+ shutdown
208
+ end
209
+
184
210
  # Mainly used by ruote's test/unit/ut_17_storage.rb
185
211
  #
186
- def add_type (type)
212
+ def add_type(type)
187
213
 
188
214
  # nothing to do
189
215
  end
190
216
 
191
- # Nukes a db type and reputs it (losing all the documents that were in it).
217
+ # Nukes a db type and reputs it(losing all the documents that were in it).
192
218
  #
193
- def purge_type! (type)
219
+ def purge_type!(type)
194
220
 
195
221
  if @cloche
196
222
  @cloche.purge_type!(type)
@@ -201,10 +227,10 @@ module Beanstalk
201
227
 
202
228
  protected
203
229
 
204
- CONN_KEY = '__ruote_beanstalk_connection'
230
+ CONN_KEY = 'ruote-beanstalk-connection'
205
231
  TUBE_NAME = 'ruote-storage-commands'
206
232
 
207
- def split_uri (uri)
233
+ def split_uri(uri)
208
234
 
209
235
  uri = ':' if uri == ''
210
236
 
@@ -218,6 +244,15 @@ module Beanstalk
218
244
  def connection
219
245
 
220
246
  c = Thread.current[CONN_KEY]
247
+
248
+ #begin
249
+ # c.stats
250
+ # return c
251
+ #rescue Exception => e
252
+ # c = nil
253
+ #end if c
254
+ # keeping around the idea around
255
+
221
256
  return c if c
222
257
 
223
258
  c = ::Beanstalk::Connection.new(@uri, TUBE_NAME)
@@ -237,7 +272,7 @@ module Beanstalk
237
272
  put({ '_id' => 'engine', 'type' => 'configurations' }.merge(@options))
238
273
  end
239
274
 
240
- def operate (command, params)
275
+ def operate(command, params)
241
276
 
242
277
  client_id = "BsStorage-#{Thread.current.object_id}-#{$$}"
243
278
  timestamp = Time.now.to_f.to_s
@@ -251,11 +286,15 @@ module Beanstalk
251
286
 
252
287
  result = nil
253
288
 
254
- # NOTE : what about a timeout ?
255
-
256
289
  loop do
257
290
 
258
- job = con.reserve
291
+ job = nil
292
+ begin
293
+ job = con.reserve
294
+ rescue Exception => e
295
+ # probably our timeout
296
+ break
297
+ end
259
298
  job.delete
260
299
 
261
300
  result, ts = Rufus::Json.decode(job.body)
@@ -265,7 +304,7 @@ module Beanstalk
265
304
 
266
305
  if result.is_a?(Array) && result.first == 'error'
267
306
  raise ArgumentError.new(result.last) if result[1] == 'ArgumentError'
268
- raise BsStorageError.new(result.last)
307
+ raise StorageError.new(result.last)
269
308
  end
270
309
 
271
310
  result
@@ -1,7 +1,7 @@
1
1
 
2
2
  module Ruote
3
3
  module Beanstalk
4
- VERSION = '2.1.10'
4
+ VERSION = '2.1.11'
5
5
  end
6
6
  end
7
7
 
data/readme.rdoc ADDED
@@ -0,0 +1,5 @@
1
+
2
+ This is the rdoc for ruote-beanstalk.
3
+
4
+ For an overview, see http://github.com/jmettraux/ruote-beanstalk
5
+