symphony 0.10.0.pre20150904120928 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5ac532bca93f670d19204728d5d1cd1d1a887b02
4
- data.tar.gz: 9d1ef778dd4d19414739b855cb242f650e15252f
3
+ metadata.gz: 865650ada7e172f5e4d85096e2dbe1c7bfa01d10
4
+ data.tar.gz: 9d73f8a431821fa56b641bc57a22b769d1bb6c33
5
5
  SHA512:
6
- metadata.gz: c592497ebea87cdec1fc14dbb3a854d389fa70d293e148278fca8d7ee9e5e3d8790a3d3b760e30042bff48034f4837c8513b659bf5ccf06645341c51982b4844
7
- data.tar.gz: e242316c2b893f106a7f1508ea735cade90f42d2fc208f9d11720eba123ad744cb660bbaa3f5060fd31bc8fde1434f06ed518597331686eaf3d01d17437fc983
6
+ metadata.gz: e809665983bb7d562c339ecbc21d329d5428eb56da39c5867873a8bf96564cd166bed96bb3e2f6d0ddaea4abf7af48587f480acdb3a8d4e5bf86d335b44d7f7b
7
+ data.tar.gz: f043bbfa1cbc1cd148744a8de5b9e962f508ce28942c86c00de1977cf101851bd6d4d08a572084b3b267de9c4293372348563b1cc05e6331c60755ba0b07e9c8
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
data/History.rdoc CHANGED
@@ -1,3 +1,29 @@
1
+ == v0.10.0 [2016-03-02] Michael Granger <ged@FaerieMUD.org>
2
+
3
+ Enhancements:
4
+
5
+ - Add a setting to tasks to force them to always rebind
6
+ - Invert scaling logic to handle initial load
7
+
8
+
9
+ == v0.9.2 [2015-07-07] Mahlon E. Smith <mahlon@martini.nu>
10
+
11
+ Fixes:
12
+
13
+ - Ensure the work callback's block returns the work() rval, instead of
14
+ the current time. This fixes Task acknowledgement.
15
+
16
+
17
+ == v0.9.1 [2015-06-08] Michael Granger <ged@FaerieMUD.org>
18
+
19
+ Fixes:
20
+
21
+ - Make Symphony.tasks contain just the task names.
22
+ The Daemon will now load task classes on startup. This is so code can
23
+ depend on Symphony without loading every configured task anytime its
24
+ config loads.
25
+
26
+
1
27
  == v0.9.0 [2015-06-01] Michael Granger <ged@FaerieMUD.org>
2
28
 
3
29
  Improvements:
data/Rakefile CHANGED
@@ -29,7 +29,7 @@ hoespec = Hoe.spec 'symphony' do |spec|
29
29
  spec.dependency 'configurability', '~> 2.2'
30
30
  spec.dependency 'loggability', '~> 0.10'
31
31
  spec.dependency 'pluggability', '~> 0.4'
32
- spec.dependency 'bunny', '~> 1.5'
32
+ spec.dependency 'bunny', '~> 2.0'
33
33
  spec.dependency 'sysexits', '~> 1.1'
34
34
  spec.dependency 'yajl-ruby', '~> 1.2'
35
35
  spec.dependency 'msgpack', '~> 0.5'
data/USAGE.rdoc CHANGED
@@ -52,12 +52,12 @@ were connecting to a virtual host called '/test', wanted to log all
52
52
  messages to STDERR at a level of 'debug', and had an exchange called
53
53
  'symphony' (the default):
54
54
 
55
- amqp:
56
- broker_uri: amqp://USERNAME:PASSWORD@example.com:5672/%2Ftest
57
- exchange: symphony
55
+ amqp:
56
+ broker_uri: amqp://USERNAME:PASSWORD@example.com:5672/%2Ftest
57
+ exchange: symphony
58
58
 
59
- logging:
60
- symphony: debug STDERR (color)
59
+ logging:
60
+ symphony: debug STDERR (color)
61
61
 
62
62
 
63
63
  Symphony won't create the exchange for you, it is expected to
@@ -78,26 +78,26 @@ calling #run on the class itself.
78
78
 
79
79
  == The Simplest Task
80
80
 
81
- #!/usr/bin/env ruby
82
-
83
- require 'symphony'
84
-
85
- class Test < Symphony::Task
86
-
87
- # Process all events
88
- subscribe_to '#'
89
-
90
- def work( payload, metadata )
91
- puts "I received an event: %p with a payload of %p" % [
92
- metadata[ :delivery_info ][ :routing_key ],
93
- payload
94
- ]
95
- return true
96
- end
97
- end
98
-
99
- Symphony.load_config( 'etc/config.yml' )
100
- Test.run
81
+ #!/usr/bin/env ruby
82
+
83
+ require 'symphony'
84
+
85
+ class Test < Symphony::Task
86
+
87
+ # Process all events
88
+ subscribe_to '#'
89
+
90
+ def work( payload, metadata )
91
+ puts "I received an event: %p with a payload of %p" % [
92
+ metadata[ :delivery_info ][ :routing_key ],
93
+ payload
94
+ ]
95
+ return true
96
+ end
97
+ end
98
+
99
+ Symphony.load_config( 'etc/config.yml' )
100
+ Test.run
101
101
 
102
102
 
103
103
  The only requirement is the 'subscribe_to' clause, which indicates what
@@ -107,10 +107,10 @@ In practice, you'll likely want to be more discerning. You can specify
107
107
  as many comma separated topics as you like for a given task, as well as
108
108
  use AMQP wildcard characters.
109
109
 
110
- # Subscribe to hypothetical creation events for all types,
111
- # and deletion events for users.
112
- #
113
- subscribe_to '#.create, 'users.delete'
110
+ # Subscribe to hypothetical creation events for all types,
111
+ # and deletion events for users.
112
+ #
113
+ subscribe_to '#.create, 'users.delete'
114
114
 
115
115
  In this fashion, you can decide to have many separate (and optionally
116
116
  distributed) tasks that only respond to a small subset of possible
@@ -126,44 +126,43 @@ workers will receive roughly equal numbers of matching events.
126
126
 
127
127
  == An Aside on Queues and Binding Behavior
128
128
 
129
- A task will automatically create an auto-delete queue for itself with a
130
- sane (but configurable) name, along with subscription bindings, ONLY if
131
- the queue didn't previously exist. The auto-delete flag ensures that
132
- when the last worker disconnects, the queue is automatically removed
133
- from the AMQP broker, setting everything back to the state it was before
134
- a Symphony worker ever connected.
129
+ By default, a task will automatically create an auto-delete queue for itself
130
+ with a sane (but configurable) name, along with subscription bindings, ONLY if
131
+ the queue didn't previously exist. The auto-delete flag ensures that when the
132
+ last worker disconnects, the queue is automatically removed from the AMQP
133
+ broker, setting everything back to the state it was before a Symphony worker
134
+ ever connected.
135
135
 
136
- Along the same logic as the initial exchange creation, if a matching
137
- queue exists already for a task name (an automatically generated or
138
- manually specified name with the 'queue_name' option), then a binding is
139
- NOT created. Symphony is 'hands off' for anything server side that
140
- already exists, so you can enforce specific behaviors, and know that
141
- Symphony won't fiddle with them.
136
+ Along the same logic as the initial exchange creation, if a matching queue
137
+ exists already for a task name (an automatically generated or manually
138
+ specified name with the 'queue_name' option), then a binding is NOT created by
139
+ default. Symphony defaults to being "hands off" for anything server side that
140
+ already exists, so you can enforce specific behaviors, and know that Symphony
141
+ won't fiddle with them.
142
142
 
143
- This can be confusing if you've created a queue manually for a task,
144
- and didn't also manually create a binding for the topic key. There are
145
- some advanced routing cases where you'll want to set up queues yourself,
146
- rather than let Symphony automatically create and remove them,
147
- we'll talk more on that later.
143
+ This can be confusing if you've created a queue manually for a task, and didn't
144
+ also manually create a binding for the topic key. There are some advanced
145
+ routing cases where you'll want to set up queues yourself, rather than let
146
+ Symphony automatically create and remove them, or rebind existing queues on
147
+ startup; we'll talk more on that later.
148
148
 
149
149
 
150
150
  == Return Values
151
151
 
152
- By default, a Task is configured to tell AMQP when it has completed its
153
- job. It does this by returning +true+ from the #work method. When AMQP
154
- sees the job was completed, the message is considered "delivered", and
155
- its lifetime is at an end. If instead, the task returns an explicit
156
- +false+, the message is retried, potentially on a different task worker.
152
+ By default, a Task is configured to tell AMQP when it has completed its job. It
153
+ does this by returning +true+ from the #work method. When AMQP sees the job was
154
+ completed, the message is considered "delivered", and its lifetime is at an
155
+ end. If instead, the task returns an explicit +false+, the message is retried,
156
+ potentially on a different task worker.
157
157
 
158
- If something within the task raises an exception, the default behavior
159
- is to permanently abort the task. If you need different behavior,
160
- you'll need to catch the exception. As the task author, you're in the
161
- best position to know if a failure state requires an immediate retry,
162
- or a permanent rejection. If you'll be allowing message retries, you
163
- might also want to consider publishing messages with a maximum TTL, to
164
- avoid any situations that could cause jobs to loop infinitely. (Default
165
- Max-TTL is an example of something that is settable when creating queues
166
- on the RabbitMQ server manually.)
158
+ If something within the task raises an exception, the default behavior is to
159
+ permanently abort the task. If you need different behavior, you'll need to
160
+ catch the exception. As the task author, you're in the best position to know if
161
+ a failure state requires an immediate retry, or a permanent rejection. If
162
+ you'll be allowing message retries, you might also want to consider publishing
163
+ messages with a maximum TTL, to avoid any situations that could cause jobs to
164
+ loop infinitely. (Default Max-TTL is an example of something that is settable
165
+ when creating queues on the RabbitMQ server manually.)
167
166
 
168
167
 
169
168
  = Task Options
@@ -176,7 +175,7 @@ considers a message as "delivered" the moment a consumer receives it.
176
175
  This can be useful for additional speed when processing non-important
177
176
  events.
178
177
 
179
- acknowledge false # (default: true)
178
+ acknowledge false # (default: true)
180
179
 
181
180
 
182
181
  == Work Model
@@ -195,7 +194,7 @@ fresh process can take its place. You can do all of your expensive work
195
194
  within the #work method, leaving the main "waiting for messages" loop as
196
195
  low-resource as possible.
197
196
 
198
- work_model :oneshot # (default: :longlived)
197
+ work_model :oneshot # (default: :longlived)
199
198
 
200
199
 
201
200
  == Message Prefetch
@@ -208,7 +207,7 @@ trade off is that all prefetched message payloads are stored in memory
208
207
  until they are processed. It's a good idea to keep this low if your
209
208
  payloads are large.
210
209
 
211
- prefetch 100 # (default: 10)
210
+ prefetch 100 # (default: 10)
212
211
 
213
212
  Message prefetch is ignored (automatically set to 1) if the task's
214
213
  work_model is set to oneshot.
@@ -228,26 +227,46 @@ There is no default timeout. If one is set, the default action is to
228
227
  act as an exception, which is a permanent rejection. You can choose to
229
228
  retry instead:
230
229
 
231
- # perform work for maximum 20 seconds, then stop and try
232
- # again on another worker
233
- #
234
- timeout 20.0, :action => :retry
230
+ # perform work for maximum 20 seconds, then stop and try
231
+ # again on another worker
232
+ #
233
+ timeout 20.0, :action => :retry
234
+
235
235
 
236
236
  == Queue Name
237
237
 
238
238
  By default, Symphony will try and create a queue based on the Class
239
239
  name of the task. You can override this per-task.
240
240
 
241
- class Test < Symphony::Task
242
-
243
- # Process all events
244
- subscribe_to '#'
245
-
246
- # I don't want to connect to a 'test' queue, lets make it interesting:
247
- queue_name 'shazzzaaaam'
248
-
249
- def work( payload, metadata )
250
- ...
241
+ class Test < Symphony::Task
242
+
243
+ # Process all events
244
+ subscribe_to '#'
245
+
246
+ # I don't want to connect to a 'test' queue, lets make it interesting:
247
+ queue_name 'shazzzaaaam'
248
+
249
+ def work( payload, metadata )
250
+ ...
251
+
252
+
253
+ == Queue Persistence
254
+
255
+ If you'd rather keep the Symphony queues around even when the workers aren't
256
+ running (to, for example, queue up events for processing when they resume), you
257
+ can tell a task to create a persistent queue instead of an auto-delete queue:
258
+
259
+ persistent true
260
+
261
+
262
+ == Queue Re-binding
263
+
264
+ If you want Symphony to re-bind a worker's queue when it starts up, you call tell it to with +always_rebind+:
265
+
266
+ always_rebind true
267
+
268
+ Note that re-binding doesn't *unbind* from the existing pattern/s, so you'll
269
+ need to account for this in the Task's +work+ method.
251
270
 
252
271
 
253
272
  = Plugins
@@ -262,13 +281,13 @@ of a task worker to the log. It shows processed message averages and
262
281
  resource consumption summaries at the "info" log level, and also changes
263
282
  the process name to display a total count and jobs per second rate.
264
283
 
265
- require 'symphony/metrics'
284
+ require 'symphony/metrics'
266
285
 
267
- class Test < Symphony::Task
268
- prepend Symphony::Metrics
269
- # ...
270
- end
271
-
286
+ class Test < Symphony::Task
287
+ prepend Symphony::Metrics
288
+ # ...
289
+ end
290
+
272
291
 
273
292
  == Routing
274
293
 
@@ -277,22 +296,22 @@ in the #work method, and instead links individual units of work to
277
296
  separate #on declarations. This makes tasks that are designed to
278
297
  receive multiple message topics much easier to maintain and test.
279
298
 
280
- require 'symphony/routing'
281
-
282
- class Test < Symphony::Task
283
- include Symphony::Routing
284
-
285
- on 'users.create', 'workstation.create' do |payload, metadata|
286
- puts "A user or workstation wants to be created!"
287
- # ...
288
- return true
289
- end
290
-
291
- on 'users.delete' do |payload, metadata|
292
- puts "A user wants to be deleted!"
293
- return true
294
- end
295
- end
299
+ require 'symphony/routing'
300
+
301
+ class Test < Symphony::Task
302
+ include Symphony::Routing
303
+
304
+ on 'users.create', 'workstation.create' do |payload, metadata|
305
+ puts "A user or workstation wants to be created!"
306
+ # ...
307
+ return true
308
+ end
309
+
310
+ on 'users.delete' do |payload, metadata|
311
+ puts "A user wants to be deleted!"
312
+ return true
313
+ end
314
+ end
296
315
 
297
316
  The #on method accepts the same syntax as the 'subscribe_to' option. In
298
317
  fact, if you're using the routing plugin, it removes the requirement of
@@ -300,6 +319,10 @@ fact, if you're using the routing plugin, it removes the requirement of
300
319
  match multiple times for a message will be executed in top down order.
301
320
  It will only return true (signalling success) if all blocks return true.
302
321
 
322
+ This plugin enables +always_rebind+ on your task when it's included so
323
+ that adding a routing pattern will be reflected in the bindings of persistent
324
+ queues.
325
+
303
326
 
304
327
  = Publishing messages
305
328
 
@@ -311,7 +334,7 @@ If you want to publish or republish from within Symphony, you can
311
334
  get a reference to the exchange object Symphony is binding to via
312
335
  the Symphony::Queue class:
313
336
 
314
- exchange = Symphony::Queue.amqp_exchange
337
+ exchange = Symphony::Queue.amqp_exchange
315
338
 
316
339
  This is a Bunny object that you can interact with directly. See the
317
340
  Bunny documentation[http://rubybunny.info/articles/exchanges.html] for
@@ -347,9 +370,9 @@ dead letter queue called '_failures', so all errors filter there without
347
370
  any further configuration. New queues have the same policy applied
348
371
  automatically.
349
372
 
350
- % rabbitmqctl list_policies
351
- Listing policies ...
352
- / DLX queues ^[^_].* {"dead-letter-exchange":"_failures"} 0
373
+ % rabbitmqctl list_policies
374
+ Listing policies ...
375
+ / DLX queues ^[^_].* {"dead-letter-exchange":"_failures"} 0
353
376
 
354
377
  There is an example task (symphony/lib/tasks/failure_logger.rb)
355
378
  that you're welcome to use as a foundation for your error reporting.
data/lib/symphony.rb CHANGED
@@ -15,7 +15,7 @@ module Symphony
15
15
  VERSION = '0.10.0'
16
16
 
17
17
  # Version-control revision constant
18
- REVISION = %q$Revision: ade5a2647590 $
18
+ REVISION = %q$Revision: 6e4811acb073 $
19
19
 
20
20
 
21
21
  # The name of the environment variable to check for config file overrides
@@ -142,29 +142,20 @@ class Symphony::Queue
142
142
  end
143
143
 
144
144
 
145
- ### Return a queue configured for the specified +task_class+.
146
- def self::for_task( task_class )
147
- args = [
148
- task_class.queue_name,
149
- task_class.acknowledge,
150
- task_class.consumer_tag,
151
- task_class.routing_keys,
152
- task_class.prefetch,
153
- task_class.persistent
154
- ]
155
- return new( *args )
156
- end
157
-
145
+ ##
146
+ # Syntactic sugar alias
147
+ singleton_method_alias :for_task, :new
158
148
 
159
149
 
160
- ### Create a new Queue with the specified configuration.
161
- def initialize( name, acknowledge, consumer_tag, routing_keys, prefetch, persistent )
162
- @name = name
163
- @acknowledge = acknowledge
164
- @consumer_tag = consumer_tag
165
- @routing_keys = routing_keys
166
- @prefetch = prefetch
167
- @persistent = persistent
150
+ ### Create a new Queue for the specified +task_class+.
151
+ def initialize( task_class )
152
+ @name = task_class.queue_name
153
+ @acknowledge = task_class.acknowledge
154
+ @consumer_tag = task_class.consumer_tag
155
+ @routing_keys = task_class.routing_keys
156
+ @prefetch = task_class.prefetch
157
+ @persistent = task_class.persistent
158
+ @always_rebind = task_class.always_rebind
168
159
 
169
160
  @amqp_queue = nil
170
161
  @shutting_down = false
@@ -175,27 +166,39 @@ class Symphony::Queue
175
166
  public
176
167
  ######
177
168
 
169
+ ##
178
170
  # The name of the queue
179
171
  attr_reader :name
180
172
 
173
+ ##
181
174
  # Acknowledge mode
182
175
  attr_reader :acknowledge
183
176
 
177
+ ##
184
178
  # The tag to use when setting up consumer
185
179
  attr_reader :consumer_tag
186
180
 
181
+ ##
187
182
  # The Array of routing keys to use when binding the queue to the exchange
188
183
  attr_reader :routing_keys
189
184
 
185
+ ##
190
186
  # The maximum number of un-acked messages to prefetch
191
187
  attr_reader :prefetch
192
188
 
189
+ ##
193
190
  # Whether or not to create a persistent queue
194
191
  attr_reader :persistent
195
192
 
193
+ ##
194
+ # Whether or not to re-bind the queue to the exchange during setup
195
+ attr_predicate :always_rebind
196
+
197
+ ##
196
198
  # The underlying Bunny::Queue this object manages
197
199
  attr_reader :amqp_queue
198
200
 
201
+ ##
199
202
  # The Bunny::Consumer that is dispatching messages for the queue.
200
203
  attr_accessor :consumer
201
204
 
@@ -251,27 +254,32 @@ class Symphony::Queue
251
254
  def create_amqp_queue( prefetch_count=DEFAULT_PREFETCH )
252
255
  exchange = self.class.amqp_exchange
253
256
  channel = self.class.amqp_channel
257
+ created_queue = false
258
+ queue = nil
254
259
 
255
260
  begin
256
261
  queue = channel.queue( self.name, passive: true )
257
262
  channel.prefetch( prefetch_count )
258
263
  self.log.info "Using pre-existing queue: %s" % [ self.name ]
259
- return queue
260
264
  rescue Bunny::NotFound => err
261
- self.log.info "%s; using an auto-delete queue instead." % [ err.message ]
265
+ self.log.info "%s; creating a new queue instead." % [ err.message ]
266
+ created_queue = true
262
267
  channel = self.class.reset_amqp_channel
263
268
  channel.prefetch( prefetch_count )
264
269
 
265
270
  queue = channel.queue( self.name, auto_delete: !self.persistent )
271
+ end
272
+
273
+ if self.always_rebind? || created_queue
266
274
  self.routing_keys.each do |key|
267
275
  self.log.info " binding queue %s to the %s exchange with topic key: %s" %
268
276
  [ self.name, exchange.name, key ]
269
277
  queue.bind( exchange, routing_key: key )
270
278
  end
279
+ end
271
280
 
272
281
  return queue
273
282
  end
274
- end
275
283
 
276
284
 
277
285
  ### Handle each subscribed message.
@@ -21,6 +21,7 @@ module Symphony::Routing
21
21
  mod.singleton_attr_accessor( :routes, :route_options )
22
22
  mod.routes = Hash.new {|h,k| h[k] = [] }
23
23
  mod.route_options = Hash.new {|h,k| h[k] = {} }
24
+ mod.always_rebind( true )
24
25
  end
25
26
 
26
27
 
data/lib/symphony/task.rb CHANGED
@@ -144,6 +144,20 @@ class Symphony::Task
144
144
  class << self; alias_method :routing_keys, :subscribe_to ; end
145
145
 
146
146
 
147
+ ### Get/set the "always re-bind" flag that causes the queue the task uses to always
148
+ ### re-bind to its exchange when the task starts. The normal behavior is that the queue
149
+ ### is only bound if it didn't already exist, which can mean that you'd need to destroy the
150
+ ### queue to force it to rebind if you change a task's routing keys.
151
+ def self::always_rebind( new_setting=nil )
152
+ unless new_setting.nil?
153
+ self.log.info "%s forced re-binding." % [ new_setting ? "Enabled" : "Disabled" ]
154
+ @always_rebind = new_setting
155
+ end
156
+
157
+ return @always_rebind
158
+ end
159
+
160
+
147
161
  ### Enable or disable acknowledgements.
148
162
  def self::acknowledge( new_setting=nil )
149
163
  unless new_setting.nil?
@@ -231,7 +245,6 @@ class Symphony::Task
231
245
 
232
246
 
233
247
 
234
-
235
248
  #
236
249
  # Instance Methods
237
250
  #
@@ -346,7 +359,8 @@ class Symphony::Task
346
359
  end
347
360
 
348
361
  self.last_worked = Time.now
349
- end
362
+ rval
363
+ end
350
364
 
351
365
  return rval
352
366
  end
@@ -149,6 +149,24 @@ describe Symphony::Queue do
149
149
  end
150
150
 
151
151
 
152
+ it "re-binds to an existing queue if the task specifies that it should always re-bind" do
153
+ testing_task_class.subscribe_to( 'floppy.rabbit.#' )
154
+ testing_task_class.always_rebind( true )
155
+ amqp_queue = double( "AMQP queue" )
156
+
157
+ expect( described_class.amqp_channel ).to receive( :queue ).
158
+ with( queue.name, passive: true ).
159
+ and_return( amqp_queue )
160
+ expect( described_class.amqp_channel ).to receive( :prefetch ).
161
+ with( Symphony::Queue::DEFAULT_PREFETCH )
162
+
163
+ expect( amqp_queue ).to receive( :bind ).
164
+ with( described_class.amqp_exchange, routing_key: 'floppy.rabbit.#' )
165
+
166
+ expect( queue.create_amqp_queue ).to be( amqp_queue )
167
+ end
168
+
169
+
152
170
  it "subscribes to the message queue with a configured consumer to wait for messages" do
153
171
  amqp_queue = double( "AMQP queue", name: 'a queue', channel: described_class.amqp_channel )
154
172
  consumer = double( "Bunny consumer", channel: described_class.amqp_channel )
@@ -65,6 +65,11 @@ describe Symphony::Routing do
65
65
  end
66
66
 
67
67
 
68
+ it "sets an including Task to always rebind so updates are applied to existing queues" do
69
+ expect( task_class.always_rebind ).to be_truthy
70
+ end
71
+
72
+
68
73
  describe "route-matching" do
69
74
 
70
75
  let( :task_class ) do
@@ -164,6 +164,12 @@ describe Symphony::Task do
164
164
  end
165
165
 
166
166
 
167
+ it "can specify that its queue should always rebind" do
168
+ task_class.always_rebind( true )
169
+ expect( task_class.always_rebind ).to be_truthy
170
+ end
171
+
172
+
167
173
  context "an instance" do
168
174
 
169
175
  let( :task_class ) do
@@ -245,7 +251,6 @@ describe Symphony::Task do
245
251
  end
246
252
 
247
253
 
248
-
249
254
  context "an instance with no #work method" do
250
255
 
251
256
  let( :task ) { task_class.new(queue) }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: symphony
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0.pre20150904120928
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Granger
@@ -31,7 +31,7 @@ cert_chain:
31
31
  G8LHR7EjtPPmqCCunfyecJ6MmCNaiJCBxq2NYzyNmluPyHT8+0fuB5kccUVZm6CD
32
32
  xn3DzOkDE6NYbk8gC9rTsA==
33
33
  -----END CERTIFICATE-----
34
- date: 2015-09-04 00:00:00.000000000 Z
34
+ date: 2016-03-02 00:00:00.000000000 Z
35
35
  dependencies:
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: configurability
@@ -81,14 +81,14 @@ dependencies:
81
81
  requirements:
82
82
  - - "~>"
83
83
  - !ruby/object:Gem::Version
84
- version: '1.5'
84
+ version: '2.0'
85
85
  type: :runtime
86
86
  prerelease: false
87
87
  version_requirements: !ruby/object:Gem::Requirement
88
88
  requirements:
89
89
  - - "~>"
90
90
  - !ruby/object:Gem::Version
91
- version: '1.5'
91
+ version: '2.0'
92
92
  - !ruby/object:Gem::Dependency
93
93
  name: sysexits
94
94
  requirement: !ruby/object:Gem::Requirement
@@ -263,14 +263,14 @@ dependencies:
263
263
  requirements:
264
264
  - - "~>"
265
265
  - !ruby/object:Gem::Version
266
- version: '3.13'
266
+ version: '3.14'
267
267
  type: :development
268
268
  prerelease: false
269
269
  version_requirements: !ruby/object:Gem::Requirement
270
270
  requirements:
271
271
  - - "~>"
272
272
  - !ruby/object:Gem::Version
273
- version: '3.13'
273
+ version: '3.14'
274
274
  description: |-
275
275
  Symphony is a subscription-based asynchronous job system. It
276
276
  allows you to define jobs that watch for lightweight events from a
@@ -356,12 +356,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
356
356
  version: 2.0.0
357
357
  required_rubygems_version: !ruby/object:Gem::Requirement
358
358
  requirements:
359
- - - ">"
359
+ - - ">="
360
360
  - !ruby/object:Gem::Version
361
- version: 1.3.1
361
+ version: 2.0.3
362
362
  requirements: []
363
363
  rubyforge_project:
364
- rubygems_version: 2.4.7
364
+ rubygems_version: 2.4.8
365
365
  signing_key:
366
366
  specification_version: 4
367
367
  summary: Symphony is a subscription-based asynchronous job system
metadata.gz.sig CHANGED
@@ -1,3 +1,2 @@
1
- <hLsS�ۄ=�����.����^E#��C2��闔�M�͵2�e�
2
- ���f��NqE��M����p��Ck[MKq��6'rVz�<�v޿��5�Ov~�r`�����0,���nb
3
- �Hκ��jQ=�J��ha�c� $.L�E�����u��`cw>���\�/�!H�y�c�B����XK!�:l������4��.qS�~vO�G�%.�;���#-�U���̝.�s�� R��f�T��lzU^���
1
+ }HX��IA���e��ҞNv ����(<�����xC���9�)���sμ+��mנ\'0�Ͱ�MUL_��}�bPd/i�� �{8&
2
+ no���P����X3o�����Dj �M}}BC eemٿ�W]���?�XѤ��g�h$��(+d21�@�؋���;+w}��#a���l2��� ���/���&��GV^ 9������02�6j�