concurrent-ruby 0.6.0.pre.2 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -8
  3. data/lib/concurrent.rb +2 -0
  4. data/lib/concurrent/actor/actor.rb +3 -3
  5. data/lib/concurrent/actor/postable.rb +1 -1
  6. data/lib/concurrent/actors.rb +0 -3
  7. data/lib/concurrent/actress.rb +75 -0
  8. data/lib/concurrent/actress/ad_hoc.rb +14 -0
  9. data/lib/concurrent/actress/context.rb +96 -0
  10. data/lib/concurrent/actress/core.rb +204 -0
  11. data/lib/concurrent/actress/core_delegations.rb +37 -0
  12. data/lib/concurrent/actress/doc.md +53 -0
  13. data/lib/concurrent/actress/envelope.rb +25 -0
  14. data/lib/concurrent/actress/errors.rb +14 -0
  15. data/lib/concurrent/actress/reference.rb +64 -0
  16. data/lib/concurrent/actress/type_check.rb +48 -0
  17. data/lib/concurrent/agent.rb +20 -11
  18. data/lib/concurrent/async.rb +54 -25
  19. data/lib/concurrent/atomic/atomic.rb +48 -0
  20. data/lib/concurrent/atomic/atomic_boolean.rb +13 -13
  21. data/lib/concurrent/atomic/atomic_fixnum.rb +9 -17
  22. data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +7 -4
  23. data/lib/concurrent/atomic/copy_on_write_observer_set.rb +16 -14
  24. data/lib/concurrent/atomic/event.rb +11 -16
  25. data/lib/concurrent/atomics.rb +1 -0
  26. data/lib/concurrent/channel/channel.rb +4 -2
  27. data/lib/concurrent/collection/blocking_ring_buffer.rb +1 -1
  28. data/lib/concurrent/configuration.rb +59 -47
  29. data/lib/concurrent/delay.rb +28 -12
  30. data/lib/concurrent/dereferenceable.rb +6 -6
  31. data/lib/concurrent/errors.rb +30 -0
  32. data/lib/concurrent/executor/executor.rb +11 -4
  33. data/lib/concurrent/executor/immediate_executor.rb +1 -0
  34. data/lib/concurrent/executor/java_thread_pool_executor.rb +4 -0
  35. data/lib/concurrent/executor/one_by_one.rb +24 -12
  36. data/lib/concurrent/executor/per_thread_executor.rb +1 -0
  37. data/lib/concurrent/executor/ruby_single_thread_executor.rb +2 -1
  38. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +7 -2
  39. data/lib/concurrent/executor/ruby_thread_pool_worker.rb +3 -0
  40. data/lib/concurrent/executor/timer_set.rb +1 -1
  41. data/lib/concurrent/future.rb +0 -2
  42. data/lib/concurrent/ivar.rb +31 -6
  43. data/lib/concurrent/logging.rb +17 -0
  44. data/lib/concurrent/mvar.rb +45 -0
  45. data/lib/concurrent/obligation.rb +61 -20
  46. data/lib/concurrent/observable.rb +7 -0
  47. data/lib/concurrent/promise.rb +1 -0
  48. data/lib/concurrent/runnable.rb +2 -2
  49. data/lib/concurrent/supervisor.rb +1 -2
  50. data/lib/concurrent/timer_task.rb +17 -13
  51. data/lib/concurrent/tvar.rb +113 -73
  52. data/lib/concurrent/utility/processor_count.rb +141 -116
  53. data/lib/concurrent/utility/timeout.rb +4 -5
  54. data/lib/concurrent/version.rb +1 -1
  55. data/spec/concurrent/actor/postable_shared.rb +1 -1
  56. data/spec/concurrent/actress_spec.rb +191 -0
  57. data/spec/concurrent/async_spec.rb +35 -3
  58. data/spec/concurrent/atomic/atomic_boolean_spec.rb +1 -1
  59. data/spec/concurrent/atomic/atomic_fixnum_spec.rb +1 -1
  60. data/spec/concurrent/atomic/atomic_spec.rb +133 -0
  61. data/spec/concurrent/atomic/count_down_latch_spec.rb +1 -1
  62. data/spec/concurrent/collection/priority_queue_spec.rb +1 -1
  63. data/spec/concurrent/configuration_spec.rb +5 -2
  64. data/spec/concurrent/delay_spec.rb +14 -0
  65. data/spec/concurrent/exchanger_spec.rb +4 -9
  66. data/spec/concurrent/executor/java_cached_thread_pool_spec.rb +1 -1
  67. data/spec/concurrent/executor/java_fixed_thread_pool_spec.rb +1 -1
  68. data/spec/concurrent/executor/java_single_thread_executor_spec.rb +1 -1
  69. data/spec/concurrent/executor/java_thread_pool_executor_spec.rb +1 -1
  70. data/spec/concurrent/executor/ruby_thread_pool_executor_spec.rb +4 -4
  71. data/spec/concurrent/ivar_spec.rb +2 -2
  72. data/spec/concurrent/obligation_spec.rb +113 -24
  73. data/spec/concurrent/observable_shared.rb +4 -0
  74. data/spec/concurrent/observable_spec.rb +8 -3
  75. data/spec/concurrent/runnable_spec.rb +2 -2
  76. data/spec/concurrent/scheduled_task_spec.rb +1 -0
  77. data/spec/concurrent/supervisor_spec.rb +26 -11
  78. data/spec/concurrent/timer_task_spec.rb +36 -35
  79. data/spec/concurrent/tvar_spec.rb +1 -1
  80. data/spec/concurrent/utility/timer_spec.rb +8 -8
  81. data/spec/spec_helper.rb +8 -18
  82. data/spec/support/example_group_extensions.rb +48 -0
  83. metadata +23 -16
  84. data/lib/concurrent/actor/actor_context.rb +0 -77
  85. data/lib/concurrent/actor/actor_ref.rb +0 -67
  86. data/lib/concurrent/actor/simple_actor_ref.rb +0 -94
  87. data/lib/concurrent_ruby_ext.bundle +0 -0
  88. data/spec/concurrent/actor/actor_context_spec.rb +0 -29
  89. data/spec/concurrent/actor/actor_ref_shared.rb +0 -263
  90. data/spec/concurrent/actor/simple_actor_ref_spec.rb +0 -135
  91. data/spec/support/functions.rb +0 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 873e9e671b06398c80e8c918e5e2ba7c0d75564e
4
- data.tar.gz: 69963957bf5e06a7a5b7ca21a678039496874c35
3
+ metadata.gz: 58bf31b4139ff60bd206c0771a4616653c77d710
4
+ data.tar.gz: 1fbbe6556817458272475deac127e92fc0c723a2
5
5
  SHA512:
6
- metadata.gz: 92bb87ece26412064c4d9697b1d92ce1cc4963d74b6f9c32b32db091d216ff8655bbd1961322db8618666a571f4f9559cf7823aa9db1fa33687b2c45db1bb57a
7
- data.tar.gz: 0d2645e119b50b88748b6131bcc984e127399bb9f5988fdfaa095fe915149ad03e60ab530523736006d3eb71a1b86821b6a889c032e9bd3c5d6a04a821d8ca2d
6
+ metadata.gz: 4d701a724fe2bb49c0bfa6c8cd3ccb242af88983ac04d90ac622a40a00e3e8e39b21a635a090c6dd808124f82733c66b99fabf05504691dcbe5a4a1f97ab8f33
7
+ data.tar.gz: 6bc189a09d26d754131c4ca8f09ec45912f2c0a4bb22ef3a578daa5781103df38597c8ab86573a78f211aa88f1f635188673b3d0d51334f56588b5c3d7c3f841
data/README.md CHANGED
@@ -18,6 +18,8 @@ and classic concurrency patterns.
18
18
  <p>
19
19
  The design goals of this gem are:
20
20
  <ul>
21
+ <li>Be an 'unopinionted' toolbox that provides useful utilities without debating which is better or why</li>
22
+ <li>Remain free of external gem dependencies</li>
21
23
  <li>Stay true to the spirit of the languages providing inspiration</li>
22
24
  <li>But implement in a way that makes sense for Ruby</li>
23
25
  <li>Keep the semantics as idiomatic Ruby as possible</li>
@@ -126,14 +128,6 @@ task = Concurrent::ScheduledTask.execute(2){ Ticker.new.get_year_end_closing('IN
126
128
  task.state #=> :pending
127
129
  sleep(3) # do other stuff
128
130
  task.value #=> 25.96
129
-
130
- # Async
131
- ticker = Ticker.new
132
- ticker.extend(Concurrent::Async)
133
- hpq = ticker.async.get_year_end_closing('HPQ', 2013)
134
- ibm = ticker.await.get_year_end_closing('IBM', 2013)
135
- hpq.value #=> 27.98
136
- ibm.value #=> 187.57
137
131
  ```
138
132
 
139
133
  ## Contributors
@@ -144,6 +138,7 @@ ibm.value #=> 187.57
144
138
  * [Lucas Allan](https://github.com/lucasallan)
145
139
  * [Petr Chalupa](https://github.com/pitr-ch)
146
140
  * [Ravil Bayramgalin](https://github.com/brainopia)
141
+ * [Larry Lv](https://github.com/larrylv)
147
142
  * [Giuseppe Capizzi](https://github.com/gcapizzi)
148
143
  * [Brian Shirai](https://github.com/brixen)
149
144
  * [Chip Miller](https://github.com/chip-miller)
data/lib/concurrent.rb CHANGED
@@ -13,6 +13,7 @@ require 'concurrent/async'
13
13
  require 'concurrent/dataflow'
14
14
  require 'concurrent/delay'
15
15
  require 'concurrent/dereferenceable'
16
+ require 'concurrent/errors'
16
17
  require 'concurrent/exchanger'
17
18
  require 'concurrent/future'
18
19
  require 'concurrent/ivar'
@@ -27,6 +28,7 @@ require 'concurrent/stoppable'
27
28
  require 'concurrent/supervisor'
28
29
  require 'concurrent/timer_task'
29
30
  require 'concurrent/tvar'
31
+ require 'concurrent/actress'
30
32
 
31
33
  # Modern concurrency tools for Ruby. Inspired by Erlang, Clojure, Scala, Haskell,
32
34
  # F#, C#, Java, and classic concurrency patterns.
@@ -179,7 +179,7 @@ module Concurrent
179
179
  #
180
180
  # @deprecated +Actor+ is being replaced with a completely new framework prior to v1.0.0
181
181
  def self.pool(count, *args, &block)
182
- warn '[DEPRECATED] `Actor` is deprecated and will be replaced with `ActorContext`.'
182
+ warn '[DEPRECATED] `Actor` is deprecated and will be replaced with `Actress`.'
183
183
  raise ArgumentError.new('count must be greater than zero') unless count > 0
184
184
  mailbox = Queue.new
185
185
  actors = count.times.collect do
@@ -212,7 +212,7 @@ module Concurrent
212
212
  #
213
213
  # @!visibility public
214
214
  def act(*message)
215
- warn '[DEPRECATED] `Actor` is deprecated and will be replaced with `ActorContext`.'
215
+ warn '[DEPRECATED] `Actor` is deprecated and will be replaced with `Actress`.'
216
216
  raise NotImplementedError.new("#{self.class} does not implement #act")
217
217
  end
218
218
 
@@ -220,7 +220,7 @@ module Concurrent
220
220
  #
221
221
  # @deprecated +Actor+ is being replaced with a completely new framework prior to v1.0.0
222
222
  def on_run # :nodoc:
223
- warn '[DEPRECATED] `Actor` is deprecated and will be replaced with `ActorContext`.'
223
+ warn '[DEPRECATED] `Actor` is deprecated and will be replaced with `Actress`.'
224
224
  queue.clear
225
225
  end
226
226
 
@@ -57,7 +57,7 @@ module Concurrent
57
57
 
58
58
  def post!(seconds, *message)
59
59
  raise ArgumentError.new('empty message') if message.empty?
60
- raise Concurrent::Runnable::LifecycleError unless ready?
60
+ raise Concurrent::LifecycleError unless ready?
61
61
  raise Concurrent::TimeoutError if seconds.to_f <= 0.0
62
62
  event = Event.new
63
63
  cback = Queue.new
@@ -1,5 +1,2 @@
1
1
  require 'concurrent/actor/actor'
2
- require 'concurrent/actor/actor_context'
3
- require 'concurrent/actor/actor_ref'
4
2
  require 'concurrent/actor/postable'
5
- require 'concurrent/actor/simple_actor_ref'
@@ -0,0 +1,75 @@
1
+ require 'concurrent/configuration'
2
+ require 'concurrent/executor/one_by_one'
3
+ require 'concurrent/ivar'
4
+ require 'concurrent/logging'
5
+
6
+ module Concurrent
7
+
8
+ # {include:file:lib/concurrent/actress/doc.md}
9
+ module Actress
10
+
11
+ require 'concurrent/actress/type_check'
12
+ require 'concurrent/actress/errors'
13
+ require 'concurrent/actress/core_delegations'
14
+ require 'concurrent/actress/envelope'
15
+ require 'concurrent/actress/reference'
16
+ require 'concurrent/actress/core'
17
+ require 'concurrent/actress/context'
18
+
19
+ require 'concurrent/actress/ad_hoc'
20
+
21
+ # @return [Reference, nil] current executing actor if any
22
+ def self.current
23
+ Thread.current[:__current_actress__]
24
+ end
25
+
26
+ # implements ROOT
27
+ class Root
28
+ include Context
29
+ # to allow spawning of new actors, spawn needs to be called inside the parent Actor
30
+ def on_message(message)
31
+ if message.is_a?(Array) && message.first == :spawn
32
+ spawn message[1], &message[2]
33
+ else
34
+ # ignore
35
+ end
36
+ end
37
+ end
38
+
39
+ # A root actor, a default parent of all actors spawned outside an actor
40
+ ROOT = Core.new(parent: nil, name: '/', class: Root).reference
41
+
42
+ # @param block for actress_class instantiation
43
+ # @param args see {.spawn_optionify}
44
+ def self.spawn(*args, &block)
45
+ warn '[EXPERIMENTAL] A full release of `Actress`, renamed `Actor`, is expected in the 0.7.0 release.'
46
+ if Actress.current
47
+ Core.new(spawn_optionify(*args).merge(parent: Actress.current), &block).reference
48
+ else
49
+ ROOT.ask([:spawn, spawn_optionify(*args), block]).value
50
+ end
51
+ end
52
+
53
+ # as {.spawn} but it'll raise when Actor not initialized properly
54
+ def self.spawn!(*args, &block)
55
+ warn '[EXPERIMENTAL] A full release of `Actress`, renamed `Actor`, is expected in the 0.7.0 release.'
56
+ spawn(spawn_optionify(*args).merge(initialized: ivar = IVar.new), &block).tap { ivar.no_error! }
57
+ end
58
+
59
+ # @overload spawn_optionify(actress_class, name, *args)
60
+ # @param [Context] actress_class to be spawned
61
+ # @param [String, Symbol] name of the instance, it's used to generate the path of the actor
62
+ # @param args for actress_class instantiation
63
+ # @overload spawn_optionify(opts)
64
+ # see {Core#initialize} opts
65
+ def self.spawn_optionify(*args)
66
+ if args.size == 1 && args.first.is_a?(Hash)
67
+ args.first
68
+ else
69
+ { class: args[0],
70
+ name: args[1],
71
+ args: args[2..-1] }
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,14 @@
1
+ module Concurrent
2
+ module Actress
3
+ class AdHoc
4
+ include Context
5
+ def initialize(*args, &initializer)
6
+ @on_message = Type! initializer.call(*args), Proc
7
+ end
8
+
9
+ def on_message(message)
10
+ instance_exec message, &@on_message
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,96 @@
1
+ module Concurrent
2
+ module Actress
3
+
4
+ # module used to define actor behaviours
5
+ # @example ping
6
+ # class Ping
7
+ # include Context
8
+ # def on_message(message)
9
+ # message
10
+ # end
11
+ # end
12
+ #
13
+ # Ping.spawn(:ping1).ask(:m).value #=> :m
14
+ module Context
15
+ include TypeCheck
16
+ include CoreDelegations
17
+
18
+ attr_reader :core
19
+
20
+ # @abstract override to define Actor's behaviour
21
+ # @param [Object] message
22
+ # @return [Object] a result which will be used to set the IVar supplied to Reference#ask
23
+ # @note self should not be returned (or sent to other actors), {#reference} should be used
24
+ # instead
25
+ def on_message(message)
26
+ raise NotImplementedError
27
+ end
28
+
29
+ def logger
30
+ core.logger
31
+ end
32
+
33
+ # @api private
34
+ def on_envelope(envelope)
35
+ @envelope = envelope
36
+ on_message envelope.message
37
+ ensure
38
+ @envelope = nil
39
+ end
40
+
41
+ # @see Actress.spawn
42
+ def spawn(*args, &block)
43
+ Actress.spawn(*args, &block)
44
+ end
45
+
46
+ # @see Core#children
47
+ def children
48
+ core.children
49
+ end
50
+
51
+ # @see Core#terminate!
52
+ def terminate!
53
+ core.terminate!
54
+ end
55
+
56
+ private
57
+
58
+ # @api private
59
+ def initialize_core(core)
60
+ @core = Type! core, Core
61
+ end
62
+
63
+ # @return [Envelope] current envelope, accessible inside #on_message processing
64
+ def envelope
65
+ @envelope or raise 'envelope not set'
66
+ end
67
+
68
+ def self.included(base)
69
+ base.extend ClassMethods
70
+ super base
71
+ end
72
+
73
+ module ClassMethods
74
+ # behaves as {Actress.spawn} but class_name is omitted
75
+ def spawn(name_or_opts, *args, &block)
76
+ Actress.spawn spawn_optionify(name_or_opts, *args), &block
77
+ end
78
+
79
+ # behaves as {Actress.spawn!} but class_name is omitted
80
+ def spawn!(name_or_opts, *args, &block)
81
+ Actress.spawn! spawn_optionify(name_or_opts, *args), &block
82
+ end
83
+
84
+ private
85
+
86
+ def spawn_optionify(name_or_opts, *args)
87
+ if name_or_opts.is_a? Hash
88
+ name_or_opts.merge class: self
89
+ else
90
+ { class: self, name: name_or_opts, args: args }
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,204 @@
1
+ module Concurrent
2
+ module Actress
3
+
4
+ require 'set'
5
+
6
+ # Core of the actor
7
+ # @api private
8
+ # @note devel: core should not block on anything, e.g. it cannot wait on children to terminate
9
+ # that would eat up all threads in task pool and deadlock
10
+ class Core
11
+ include TypeCheck
12
+ include Concurrent::Logging
13
+
14
+ attr_reader :reference, :name, :path, :executor, :terminated
15
+
16
+ # @option opts [String] name
17
+ # @option opts [Reference, nil] parent of an actor spawning this one
18
+ # @option opts [Context] actress_class a class to be instantiated defining Actor's behaviour
19
+ # @option opts [Array<Object>] args arguments for actress_class instantiation
20
+ # @option opts [Executor] executor, default is `Concurrent.configuration.global_task_pool`
21
+ # @option opts [IVar, nil] initialized, if present it'll be set or failed after {Context} initialization
22
+ # @option opts [Proc, nil] logger a proc accepting (level, progname, message = nil, &block) params,
23
+ # can be used to hook actor instance to any logging system
24
+ # @param [Proc] block for class instantiation
25
+ def initialize(opts = {}, &block)
26
+ @mailbox = Array.new
27
+ @one_by_one = OneByOne.new
28
+ # noinspection RubyArgCount
29
+ @terminated = Event.new
30
+ @executor = Type! opts.fetch(:executor, Concurrent.configuration.global_task_pool), Executor
31
+ @children = Set.new
32
+ @reference = Reference.new self
33
+ @name = (Type! opts.fetch(:name), String, Symbol).to_s
34
+
35
+ parent = opts[:parent]
36
+ @parent_core = (Type! parent, Reference, NilClass) && parent.send(:core)
37
+ if @parent_core.nil? && @name != '/'
38
+ raise 'only root has no parent'
39
+ end
40
+
41
+ @path = @parent_core ? File.join(@parent_core.path, @name) : @name
42
+ @logger = opts[:logger]
43
+
44
+ @parent_core.add_child reference if @parent_core
45
+
46
+ @actress_class = actress_class = Child! opts.fetch(:class), Context
47
+ args = opts.fetch(:args, [])
48
+ initialized = Type! opts[:initialized], IVar, NilClass
49
+
50
+ schedule_execution do
51
+ begin
52
+ @actress = actress_class.new *args, &block
53
+ @actress.send :initialize_core, self
54
+ initialized.set true if initialized
55
+ rescue => ex
56
+ log ERROR, ex
57
+ terminate!
58
+ initialized.fail ex if initialized
59
+ end
60
+ end
61
+ end
62
+
63
+ # @return [Reference, nil] of parent actor
64
+ def parent
65
+ @parent_core && @parent_core.reference
66
+ end
67
+
68
+ # @return [Array<Reference>] of children actors
69
+ def children
70
+ guard!
71
+ @children.to_a
72
+ end
73
+
74
+ # @api private
75
+ def add_child(child)
76
+ guard!
77
+ Type! child, Reference
78
+ @children.add child
79
+ nil
80
+ end
81
+
82
+ # @api private
83
+ def remove_child(child)
84
+ schedule_execution do
85
+ Type! child, Reference
86
+ @children.delete child
87
+ end
88
+ nil
89
+ end
90
+
91
+ # is executed by Reference scheduling processing of new messages
92
+ # can be called from other alternative Reference implementations
93
+ # @param [Envelope] envelope
94
+ def on_envelope(envelope)
95
+ schedule_execution do
96
+ if terminated?
97
+ reject_envelope envelope
98
+ else
99
+ @mailbox.push envelope
100
+ end
101
+ process_envelopes?
102
+ end
103
+ nil
104
+ end
105
+
106
+ # @note Actor rejects envelopes when terminated.
107
+ # @return [true, false] if actor is terminated
108
+ def terminated?
109
+ @terminated.set?
110
+ end
111
+
112
+ # Terminates the actor. Any Envelope received after termination is rejected.
113
+ # Terminates all its children, does not wait until they are terminated.
114
+ def terminate!
115
+ guard!
116
+ @children.each do |ch|
117
+ ch.send(:core).tap { |core| core.send(:schedule_execution) { core.terminate! } }
118
+ end
119
+
120
+ @terminated.set
121
+
122
+ @parent_core.remove_child reference if @parent_core
123
+ @mailbox.each do |envelope|
124
+ reject_envelope envelope
125
+ log DEBUG, "rejected #{envelope.message} from #{envelope.sender_path}"
126
+ end
127
+ @mailbox.clear
128
+
129
+ nil
130
+ end
131
+
132
+ # @api private
133
+ # ensures that we are inside of the executor
134
+ def guard!
135
+ unless Actress.current == reference
136
+ raise "can be called only inside actor #{reference} but was #{Actress.current}"
137
+ end
138
+ end
139
+
140
+ private
141
+
142
+ # Ensures that only one envelope processing is scheduled with #schedule_execution,
143
+ # this allows other scheduled blocks to be executed before next envelope processing.
144
+ # Simply put this ensures that Core is still responsive to internal calls (like add_child)
145
+ # even though the Actor is flooded with messages.
146
+ def process_envelopes?
147
+ unless @mailbox.empty? || @receive_envelope_scheduled
148
+ @receive_envelope_scheduled = true
149
+ schedule_execution { receive_envelope }
150
+ end
151
+ end
152
+
153
+ # Processes single envelope, calls #process_envelopes? at the end to ensure next envelope
154
+ # scheduling.
155
+ def receive_envelope
156
+ envelope = @mailbox.shift
157
+
158
+ if terminated?
159
+ reject_envelope envelope
160
+ log FATAL, "this should not be happening #{caller[0]}"
161
+ end
162
+
163
+ log DEBUG, "received #{envelope.message} from #{envelope.sender_path}"
164
+
165
+ result = @actress.on_envelope envelope
166
+ envelope.ivar.set result unless envelope.ivar.nil?
167
+
168
+ nil
169
+ rescue => error
170
+ log ERROR, error
171
+ terminate!
172
+ envelope.ivar.fail error unless envelope.ivar.nil?
173
+ ensure
174
+ @receive_envelope_scheduled = false
175
+ process_envelopes?
176
+ end
177
+
178
+ # Schedules blocks to be executed on executor sequentially,
179
+ # sets Actress.current
180
+ def schedule_execution
181
+ @one_by_one.post(@executor) do
182
+ begin
183
+ Thread.current[:__current_actress__] = reference
184
+ yield
185
+ rescue => e
186
+ log FATAL, e
187
+ ensure
188
+ Thread.current[:__current_actress__] = nil
189
+ end
190
+ end
191
+
192
+ nil
193
+ end
194
+
195
+ def reject_envelope(envelope)
196
+ envelope.reject! ActressTerminated.new(reference)
197
+ end
198
+
199
+ def log(level, message = nil, &block)
200
+ super level, @path, message, &block
201
+ end
202
+ end
203
+ end
204
+ end