concurrent-ruby 0.6.0.pre.2 → 0.6.0

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 (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