celluloid 0.14.1 → 0.15.0.pre

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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -2
  3. data/lib/celluloid.rb +92 -108
  4. data/lib/celluloid/actor.rb +42 -64
  5. data/lib/celluloid/autostart.rb +1 -1
  6. data/lib/celluloid/call_chain.rb +13 -0
  7. data/lib/celluloid/calls.rb +5 -8
  8. data/lib/celluloid/condition.rb +8 -10
  9. data/lib/celluloid/cpu_counter.rb +1 -1
  10. data/lib/celluloid/evented_mailbox.rb +7 -10
  11. data/lib/celluloid/fsm.rb +1 -1
  12. data/lib/celluloid/future.rb +1 -2
  13. data/lib/celluloid/internal_pool.rb +77 -20
  14. data/lib/celluloid/legacy.rb +0 -38
  15. data/lib/celluloid/mailbox.rb +17 -10
  16. data/lib/celluloid/pool_manager.rb +1 -1
  17. data/lib/celluloid/properties.rb +24 -0
  18. data/lib/celluloid/proxies/abstract_proxy.rb +3 -0
  19. data/lib/celluloid/proxies/actor_proxy.rb +3 -32
  20. data/lib/celluloid/proxies/async_proxy.rb +4 -8
  21. data/lib/celluloid/proxies/future_proxy.rb +8 -6
  22. data/lib/celluloid/proxies/sync_proxy.rb +12 -7
  23. data/lib/celluloid/rspec.rb +3 -1
  24. data/lib/celluloid/signals.rb +7 -35
  25. data/lib/celluloid/stack_dump.rb +50 -37
  26. data/lib/celluloid/supervision_group.rb +5 -5
  27. data/lib/celluloid/task_set.rb +49 -0
  28. data/lib/celluloid/tasks.rb +67 -42
  29. data/lib/celluloid/tasks/task_fiber.rb +3 -1
  30. data/lib/celluloid/tasks/task_thread.rb +2 -3
  31. data/lib/celluloid/thread.rb +2 -0
  32. data/spec/celluloid/actor_spec.rb +5 -0
  33. data/spec/celluloid/block_spec.rb +54 -0
  34. data/spec/celluloid/calls_spec.rb +42 -0
  35. data/spec/celluloid/condition_spec.rb +65 -0
  36. data/spec/celluloid/evented_mailbox_spec.rb +34 -0
  37. data/spec/celluloid/fsm_spec.rb +107 -0
  38. data/spec/celluloid/future_spec.rb +32 -0
  39. data/spec/celluloid/internal_pool_spec.rb +52 -0
  40. data/spec/celluloid/links_spec.rb +45 -0
  41. data/spec/celluloid/logging/ring_buffer_spec.rb +38 -0
  42. data/spec/celluloid/mailbox_spec.rb +5 -0
  43. data/spec/celluloid/notifications_spec.rb +120 -0
  44. data/spec/celluloid/pool_spec.rb +52 -0
  45. data/spec/celluloid/properties_spec.rb +42 -0
  46. data/spec/celluloid/registry_spec.rb +64 -0
  47. data/spec/celluloid/stack_dump_spec.rb +35 -0
  48. data/spec/celluloid/supervision_group_spec.rb +53 -0
  49. data/spec/celluloid/supervisor_spec.rb +92 -0
  50. data/spec/celluloid/tasks/task_fiber_spec.rb +5 -0
  51. data/spec/celluloid/tasks/task_thread_spec.rb +5 -0
  52. data/spec/celluloid/thread_handle_spec.rb +22 -0
  53. data/spec/celluloid/uuid_spec.rb +11 -0
  54. data/spec/spec_helper.rb +31 -0
  55. data/spec/support/actor_examples.rb +161 -10
  56. data/spec/support/example_actor_class.rb +8 -0
  57. data/spec/support/mailbox_examples.rb +15 -3
  58. data/spec/support/task_examples.rb +2 -2
  59. metadata +28 -3
  60. data/lib/celluloid/version.rb +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 83a01356fe7e144f11c0ac9db25951850f53c9b4
4
- data.tar.gz: 243e2915cef408cf97229f8ec0a512bfb2524fb8
3
+ metadata.gz: 802e81b987e2d65c9d7055c2160805612db65b50
4
+ data.tar.gz: 2a2c5eaf4c8afa92a8ee3c782ffb3e6556454061
5
5
  SHA512:
6
- metadata.gz: 60e75d013b08ff7101ea6280b31bd5976ba097e821880e3d6d9b935580c8515d05d8619bc6a3df7be1d2733366d97b482a3668443e59c3c9e397bc6a14e46c75
7
- data.tar.gz: 3e9fe0851276289183c6ca52e72bc545dc174831d325d78a9682f63087c4f54ff3b6f454babf4b091641a163235f953e02bbf656cfbdce4e093ec35df831e167
6
+ metadata.gz: 3bee45fcc9e099fcd5b61d605fa06293d9454402f65601ff789aac7c679e9f0d206a7f696a53d37fa3febeda10163dd5c2e4da1bc8dece2101bf1a3f949ca60e
7
+ data.tar.gz: c897040ce47e50088ee2c53ea8291733d2214cb127d3014558e366f8a1e58239ea232a9d7381671d99c64fcf6dca6e65b6f1d8b335a986a8779b97f875a163da
data/README.md CHANGED
@@ -99,7 +99,9 @@ Installation
99
99
 
100
100
  Add this line to your application's Gemfile:
101
101
 
102
- gem 'celluloid'
102
+ ```ruby
103
+ gem 'celluloid'
104
+ ```
103
105
 
104
106
  And then execute:
105
107
 
@@ -111,7 +113,9 @@ Or install it yourself as:
111
113
 
112
114
  Inside of your Ruby program, require Celluloid with:
113
115
 
114
- require 'celluloid/autostart'
116
+ ```ruby
117
+ require 'celluloid/autostart'
118
+ ```
115
119
 
116
120
  Supported Platforms
117
121
  -------------------
@@ -3,7 +3,14 @@ require 'thread'
3
3
  require 'timeout'
4
4
  require 'set'
5
5
 
6
+ if defined?(JRUBY_VERSION) && JRUBY_VERSION == "1.7.3"
7
+ raise "Celluloid is broken on JRuby 1.7.3. Please upgrade to 1.7.4+"
8
+ end
9
+
6
10
  module Celluloid
11
+ VERSION = '0.15.0.pre'
12
+ Error = Class.new StandardError
13
+
7
14
  extend self # expose all instance methods as singleton methods
8
15
 
9
16
  # Warning message added to Celluloid objects accessed outside their actors
@@ -18,6 +25,24 @@ module Celluloid
18
25
  def included(klass)
19
26
  klass.send :extend, ClassMethods
20
27
  klass.send :include, InstanceMethods
28
+
29
+ klass.send :extend, Properties
30
+
31
+ klass.property :mailbox_class, :default => Celluloid::Mailbox
32
+ klass.property :proxy_class, :default => Celluloid::ActorProxy
33
+ klass.property :task_class, :default => Celluloid.task_class
34
+ klass.property :mailbox_size
35
+
36
+ klass.property :execute_block_on_receiver,
37
+ :default => [:after, :every, :receive],
38
+ :multi => true
39
+
40
+ klass.property :finalizer
41
+ klass.property :exit_handler
42
+
43
+ klass.send(:define_singleton_method, :trap_exit) do |*args|
44
+ exit_handler(*args)
45
+ end
21
46
  end
22
47
 
23
48
  # Are we currently inside of an actor?
@@ -48,6 +73,18 @@ module Celluloid
48
73
  end
49
74
  alias_method :dump, :stack_dump
50
75
 
76
+ # Detect if a particular call is recursing through multiple actors
77
+ def detect_recursion
78
+ actor = Thread.current[:celluloid_actor]
79
+ return unless actor
80
+
81
+ task = Thread.current[:celluloid_task]
82
+ return unless task
83
+
84
+ chain_id = CallChain.current_id
85
+ actor.tasks.to_a.any? { |t| t != task && t.chain_id == chain_id }
86
+ end
87
+
51
88
  # Define an exception handler for actor crashes
52
89
  def exception_handler(&block)
53
90
  Logger.exception_handler(&block)
@@ -63,10 +100,18 @@ module Celluloid
63
100
  end
64
101
  end
65
102
 
103
+ def boot
104
+ init
105
+ start
106
+ end
107
+
108
+ def init
109
+ self.internal_pool = InternalPool.new
110
+ end
111
+
66
112
  # Launch default services
67
113
  # FIXME: We should set up the supervision hierarchy here
68
- def boot
69
- internal_pool.reset
114
+ def start
70
115
  Celluloid::Notifications::Fanout.supervise_as :notifications_fanout
71
116
  Celluloid::IncidentReporter.supervise_as :default_incident_reporter, STDERR
72
117
  end
@@ -90,11 +135,12 @@ module Celluloid
90
135
 
91
136
  # Shut down all running actors
92
137
  def shutdown
138
+ actors = Actor.all
139
+
93
140
  Timeout.timeout(shutdown_timeout) do
94
141
  internal_pool.shutdown
95
142
 
96
- actors = Actor.all
97
- Logger.debug "Terminating #{actors.size} actors..." if actors.size > 0
143
+ Logger.debug "Terminating #{actors.size} #{(actors.size > 1) ? 'actors' : 'actor'}..." if actors.size > 0
98
144
 
99
145
  # Attempt to shut down the supervision tree, if available
100
146
  Supervisor.root.terminate if Supervisor.root
@@ -103,21 +149,31 @@ module Celluloid
103
149
  actors.each do |actor|
104
150
  begin
105
151
  actor.terminate!
106
- rescue DeadActorError, MailboxError
152
+ rescue DeadActorError
107
153
  end
108
154
  end
109
155
 
110
156
  actors.each do |actor|
111
157
  begin
112
158
  Actor.join(actor)
113
- rescue DeadActorError, MailboxError
159
+ rescue DeadActorError
114
160
  end
115
161
  end
116
-
117
- Logger.debug "Shutdown completed cleanly"
118
162
  end
119
163
  rescue Timeout::Error
120
164
  Logger.error("Couldn't cleanly terminate all actors in #{shutdown_timeout} seconds!")
165
+ actors.each do |actor|
166
+ begin
167
+ Actor.kill(actor)
168
+ rescue DeadActorError, MailboxDead
169
+ end
170
+ end
171
+ ensure
172
+ internal_pool.kill
173
+ end
174
+
175
+ def version
176
+ VERSION
121
177
  end
122
178
  end
123
179
 
@@ -173,63 +229,6 @@ module Celluloid
173
229
  Actor.join(new(*args, &block))
174
230
  end
175
231
 
176
- # Trap errors from actors we're linked to when they exit
177
- def exit_handler(callback = nil)
178
- if callback
179
- @exit_handler = callback.to_sym
180
- elsif defined?(@exit_handler)
181
- @exit_handler
182
- elsif superclass.respond_to? :exit_handler
183
- superclass.exit_handler
184
- end
185
- end
186
- alias_method :trap_exit, :exit_handler
187
-
188
- # Define a callback to run when the actor is finalized.
189
- def finalizer(callback = nil)
190
- if callback
191
- @finalizer = callback.to_sym
192
- elsif defined?(@finalizer)
193
- @finalizer
194
- elsif superclass.respond_to? :finalizer
195
- superclass.finalizer
196
- end
197
- end
198
-
199
- # Define the mailbox class for this class
200
- def mailbox_class(klass = nil)
201
- if klass
202
- mailbox.class = klass
203
- else
204
- mailbox.class
205
- end
206
- end
207
-
208
- def proxy_class(klass = nil)
209
- if klass
210
- @proxy_class = klass
211
- elsif defined?(@proxy_class)
212
- @proxy_class
213
- elsif superclass.respond_to? :proxy_class
214
- superclass.proxy_class
215
- else
216
- Celluloid::ActorProxy
217
- end
218
- end
219
-
220
- # Define the default task type for this class
221
- def task_class(klass = nil)
222
- if klass
223
- @task_class = klass
224
- elsif defined?(@task_class)
225
- @task_class
226
- elsif superclass.respond_to? :task_class
227
- superclass.task_class
228
- else
229
- Celluloid.task_class
230
- end
231
- end
232
-
233
232
  # Mark methods as running exclusively
234
233
  def exclusive(*methods)
235
234
  if methods.empty?
@@ -240,55 +239,22 @@ module Celluloid
240
239
  end
241
240
  end
242
241
 
243
- # Mark methods as running blocks on the receiver
244
- def execute_block_on_receiver(*methods)
245
- receiver_block_executions.merge methods.map(&:to_sym)
246
- end
247
-
248
- def receiver_block_executions
249
- @receiver_block_executions ||= Set.new([:after, :every, :receive])
250
- end
251
-
252
242
  # Configuration options for Actor#new
253
243
  def actor_options
254
244
  {
255
- :mailbox => mailbox.build,
245
+ :mailbox_class => mailbox_class,
246
+ :mailbox_size => mailbox_size,
256
247
  :proxy_class => proxy_class,
257
248
  :task_class => task_class,
258
249
  :exit_handler => exit_handler,
259
250
  :exclusive_methods => defined?(@exclusive_methods) ? @exclusive_methods : nil,
260
- :receiver_block_executions => receiver_block_executions
251
+ :receiver_block_executions => execute_block_on_receiver
261
252
  }
262
253
  end
263
254
 
264
255
  def ===(other)
265
256
  other.kind_of? self
266
257
  end
267
-
268
- def mailbox
269
- @mailbox_factory ||= MailboxFactory.new(self)
270
- end
271
-
272
- class MailboxFactory
273
- attr_accessor :class, :max_size
274
-
275
- def initialize(actor)
276
- @actor = actor
277
- @class = nil
278
- @max_size = nil
279
- end
280
-
281
- def build
282
- mailbox = mailbox_class.new
283
- mailbox.max_size = @max_size
284
- mailbox
285
- end
286
-
287
- private
288
- def mailbox_class
289
- @class || (@actor.superclass.respond_to?(:mailbox_class) && @actor.superclass.mailbox_class) || Celluloid::Mailbox
290
- end
291
- end
292
258
  end
293
259
 
294
260
  # These are methods we don't want added to the Celluloid singleton but to be
@@ -326,6 +292,8 @@ module Celluloid
326
292
  end
327
293
 
328
294
  def inspect
295
+ return "..." if Celluloid.detect_recursion
296
+
329
297
  str = "#<"
330
298
 
331
299
  if leaked?
@@ -363,7 +331,7 @@ module Celluloid
363
331
 
364
332
  # Terminate this actor
365
333
  def terminate
366
- Thread.current[:celluloid_actor].terminate
334
+ Thread.current[:celluloid_actor].proxy.terminate!
367
335
  end
368
336
 
369
337
  # Send a signal with the given name to all waiting methods
@@ -383,7 +351,7 @@ module Celluloid
383
351
 
384
352
  # Obtain the UUID of the current call chain
385
353
  def call_chain_id
386
- Thread.current[:celluloid_chain_id]
354
+ CallChain.current_id
387
355
  end
388
356
 
389
357
  # Obtain the running tasks for this actor
@@ -446,16 +414,30 @@ module Celluloid
446
414
  end
447
415
  end
448
416
 
417
+ # Timeout on task suspension (eg Sync calls to other actors)
418
+ def timeout(duration)
419
+ bt = caller
420
+ task = Task.current
421
+ timer = after(duration) do
422
+ exception = Task::TimeoutError.new
423
+ exception.set_backtrace bt
424
+ task.resume exception
425
+ end
426
+ yield
427
+ ensure
428
+ timer.cancel if timer
429
+ end
430
+
449
431
  # Run given block in an exclusive mode: all synchronous calls block the whole
450
432
  # actor, not only current message processing.
451
433
  def exclusive(&block)
452
- Thread.current[:celluloid_actor].exclusive(&block)
434
+ Thread.current[:celluloid_task].exclusive(&block)
453
435
  end
454
436
 
455
437
  # Are we currently exclusive
456
438
  def exclusive?
457
- actor = Thread.current[:celluloid_actor]
458
- actor && actor.exclusive?
439
+ task = Thread.current[:celluloid_task]
440
+ task && task.exclusive?
459
441
  end
460
442
 
461
443
  # Call a block after a given interval, returning a Celluloid::Timer object
@@ -488,9 +470,8 @@ module Celluloid
488
470
  end
489
471
  end
490
472
 
491
- require 'celluloid/version'
492
-
493
473
  require 'celluloid/calls'
474
+ require 'celluloid/call_chain'
494
475
  require 'celluloid/condition'
495
476
  require 'celluloid/thread'
496
477
  require 'celluloid/core_ext'
@@ -503,6 +484,7 @@ require 'celluloid/logger'
503
484
  require 'celluloid/mailbox'
504
485
  require 'celluloid/evented_mailbox'
505
486
  require 'celluloid/method'
487
+ require 'celluloid/properties'
506
488
  require 'celluloid/receivers'
507
489
  require 'celluloid/registry'
508
490
  require 'celluloid/responses'
@@ -510,6 +492,7 @@ require 'celluloid/signals'
510
492
  require 'celluloid/stack_dump'
511
493
  require 'celluloid/system_events'
512
494
  require 'celluloid/tasks'
495
+ require 'celluloid/task_set'
513
496
  require 'celluloid/thread_handle'
514
497
  require 'celluloid/uuid'
515
498
 
@@ -535,3 +518,4 @@ Celluloid.task_class = Celluloid::TaskFiber
535
518
  Celluloid.logger = Logger.new(STDERR)
536
519
  Celluloid.shutdown_timeout = 10
537
520
  Celluloid.register_shutdown
521
+ Celluloid.init
@@ -2,16 +2,16 @@ require 'timers'
2
2
 
3
3
  module Celluloid
4
4
  # Don't do Actor-like things outside Actor scope
5
- class NotActorError < StandardError; end
5
+ class NotActorError < Celluloid::Error; end
6
6
 
7
7
  # Trying to do something to a dead actor
8
- class DeadActorError < StandardError; end
8
+ class DeadActorError < Celluloid::Error; end
9
9
 
10
10
  # A timeout occured before the given request could complete
11
- class TimeoutError < StandardError; end
11
+ class TimeoutError < Celluloid::Error; end
12
12
 
13
13
  # The sender made an error, not the current actor
14
- class AbortError < StandardError
14
+ class AbortError < Celluloid::Error
15
15
  attr_reader :cause
16
16
 
17
17
  def initialize(cause)
@@ -77,8 +77,8 @@ module Celluloid
77
77
  # Obtain all running actors in the system
78
78
  def all
79
79
  actors = []
80
- Thread.list.each do |t|
81
- next unless t.celluloid? && t.role == :actor
80
+ Celluloid.internal_pool.each do |t|
81
+ next unless t.role == :actor
82
82
  actors << t.actor.proxy if t.actor && t.actor.respond_to?(:proxy)
83
83
  end
84
84
  actors
@@ -121,10 +121,7 @@ module Celluloid
121
121
  # Forcibly kill a given actor
122
122
  def kill(actor)
123
123
  actor.thread.kill
124
- begin
125
- actor.mailbox.shutdown
126
- rescue DeadActorError
127
- end
124
+ actor.mailbox.shutdown if actor.mailbox.alive?
128
125
  end
129
126
 
130
127
  # Wait for an actor to terminate
@@ -136,12 +133,15 @@ module Celluloid
136
133
 
137
134
  # Wrap the given subject with an Actor
138
135
  def initialize(subject, options = {})
139
- @subject = subject
140
- @mailbox = options[:mailbox] || Mailbox.new
136
+ @subject = subject
137
+
138
+ @mailbox = options.fetch(:mailbox_class, Mailbox).new
139
+ @mailbox.max_size = options.fetch(:mailbox_size, nil)
140
+
141
+ @task_class = options[:task_class] || Celluloid.task_class
141
142
  @exit_handler = options[:exit_handler]
142
143
  @exclusives = options[:exclusive_methods]
143
144
  @receiver_block_executions = options[:receiver_block_executions]
144
- @task_class = options[:task_class] || Celluloid.task_class
145
145
 
146
146
  @tasks = TaskSet.new
147
147
  @links = Links.new
@@ -193,28 +193,9 @@ module Celluloid
193
193
  @running = false
194
194
  end
195
195
 
196
- # Is this actor running in exclusive mode?
197
- def exclusive?
198
- @exclusive
199
- end
200
-
201
- # Execute a code block in exclusive mode.
202
- def exclusive
203
- if @exclusive
204
- yield
205
- else
206
- begin
207
- @exclusive = true
208
- yield
209
- ensure
210
- @exclusive = false
211
- end
212
- end
213
- end
214
-
215
196
  # Perform a linking request with another actor
216
197
  def linking_request(receiver, type)
217
- exclusive do
198
+ Celluloid.exclusive do
218
199
  start_time = Time.now
219
200
  receiver.mailbox << LinkingRequest.new(Actor.current, type)
220
201
  system_events = []
@@ -245,7 +226,7 @@ module Celluloid
245
226
 
246
227
  # Send a signal with the given name to all waiting methods
247
228
  def signal(name, value = nil)
248
- @signals.send name, value
229
+ @signals.broadcast name, value
249
230
  end
250
231
 
251
232
  # Wait for the given signal
@@ -314,15 +295,17 @@ module Celluloid
314
295
  when SystemEvent
315
296
  handle_system_event message
316
297
  when Call
317
- task(:call, message.method) {
318
- if @receiver_block_executions && meth = message.method
319
- if meth == :__send__
320
- meth = message.arguments.first
321
- end
322
- if @receiver_block_executions.include?(meth.to_sym)
323
- message.execute_block_on_receiver
324
- end
298
+ meth = message.method
299
+ if meth == :__send__
300
+ meth = message.arguments.first
301
+ end
302
+ if @receiver_block_executions && meth
303
+ if @receiver_block_executions.include?(meth.to_sym)
304
+ message.execute_block_on_receiver
325
305
  end
306
+ end
307
+
308
+ task(:call, :method_name => meth, :dangerous_suspend => meth == :initialize) {
326
309
  message.dispatch(@subject)
327
310
  }
328
311
  when BlockCall
@@ -330,7 +313,9 @@ module Celluloid
330
313
  when BlockResponse, Response
331
314
  message.dispatch
332
315
  else
333
- @receivers.handle_message(message)
316
+ unless @receivers.handle_message(message)
317
+ Logger.debug "Discarded message (unhandled): #{message}"
318
+ end
334
319
  end
335
320
  message
336
321
  end
@@ -339,13 +324,13 @@ module Celluloid
339
324
  def handle_system_event(event)
340
325
  case event
341
326
  when ExitEvent
342
- task(:exit_handler, @exit_handler) { handle_exit_event event }
327
+ task(:exit_handler, :method_name => @exit_handler) { handle_exit_event event }
343
328
  when LinkingRequest
344
329
  event.process(links)
345
330
  when NamingRequest
346
331
  @name = event.name
347
332
  when TerminationRequest
348
- @running = false
333
+ terminate
349
334
  when SignalConditionRequest
350
335
  event.call
351
336
  end
@@ -382,17 +367,9 @@ module Celluloid
382
367
 
383
368
  # Run the user-defined finalizer, if one is set
384
369
  def run_finalizer
385
- # FIXME: remove before Celluloid 1.0
386
- if @subject.respond_to?(:finalize) && @subject.class.finalizer != :finalize
387
- Logger.warn("DEPRECATION WARNING: #{@subject.class}#finalize is deprecated and will be removed in Celluloid 1.0. " +
388
- "Define finalizers with '#{@subject.class}.finalizer :callback.'")
389
-
390
- task(:finalizer, :finalize) { @subject.finalize }
391
- end
392
-
393
370
  finalizer = @subject.class.finalizer
394
371
  if finalizer && @subject.respond_to?(finalizer, true)
395
- task(:finalizer, :finalize) { @subject.__send__(finalizer) }
372
+ task(:finalizer, :method_name => finalizer, :dangerous_suspend => true) { @subject.__send__(finalizer) }
396
373
  end
397
374
  rescue => ex
398
375
  Logger.crash("#{@subject.class}#finalize crashed!", ex)
@@ -402,25 +379,26 @@ module Celluloid
402
379
  def cleanup(exit_event)
403
380
  @mailbox.shutdown
404
381
  @links.each do |actor|
405
- begin
382
+ if actor.mailbox.alive?
406
383
  actor.mailbox << exit_event
407
- rescue MailboxError
408
- # We're exiting/crashing, they're dead. Give up :(
409
384
  end
410
385
  end
411
386
 
412
- tasks.each { |task| task.terminate }
387
+ tasks.to_a.each { |task| task.terminate }
413
388
  rescue => ex
414
389
  Logger.crash("#{@subject.class}: CLEANUP CRASHED!", ex)
415
390
  end
416
391
 
417
392
  # Run a method inside a task unless it's exclusive
418
- def task(task_type, method_name = nil, &block)
419
- if @exclusives && (@exclusives == :all || (method_name && @exclusives.include?(method_name.to_sym)))
420
- exclusive { block.call }
421
- else
422
- @task_class.new(task_type, &block).resume
423
- end
393
+ def task(task_type, meta = nil)
394
+ method_name = meta && meta.fetch(:method_name, nil)
395
+ @task_class.new(task_type, meta) {
396
+ if @exclusives && (@exclusives == :all || (method_name && @exclusives.include?(method_name.to_sym)))
397
+ Celluloid.exclusive { yield }
398
+ else
399
+ yield
400
+ end
401
+ }.resume
424
402
  end
425
403
  end
426
404
  end