Class: Concurrently::Proc::Evaluation

Inherits:
Evaluation
  • Object
show all
Defined in:
lib/all/concurrently/proc/evaluation.rb,
lib/all/concurrently/proc/evaluation/error.rb

Overview

Note:

Evaluations are not thread safe. They are operating on a fiber. Fibers cannot be resumed inside a thread they were not created in.

Concurrently::Proc::Evaluation represents the evaluation of a concurrent proc.

An instance will be returned by Evaluation.current if called by code inside a concurrent proc. It will also be returned by every call of #call_detached and also by #call_nonblock if the evaluation cannot be concluded in one go and needs to wait.

Since:

  • 1.0.0

Defined Under Namespace

Modules: RescueableError Classes: Cancelled

Instance Attribute Summary collapse

Attributes inherited from Evaluation

#waiting?

Instance Method Summary collapse

Methods inherited from Evaluation

#__resume__!, current

Instance Attribute Details

#concludedBoolean (readonly) Also known as: concluded?

Checks if the evaluation is concluded

Since:

  • 1.0.0


237
238
239
# File 'lib/all/concurrently/proc/evaluation.rb', line 237

def concluded
  @concluded
end

Instance Method Details

#[](key) ⇒ Object

Retrieves the attached value under the given key

Examples:

evaluation = concurrently{ :result }
evaluation[:key] = :value
evaluation[:key]  # => :value

Since:

  • 1.0.0


48
49
50
# File 'lib/all/concurrently/proc/evaluation.rb', line 48

def [](key)
  @data[key]
end

#[]=(key, value) ⇒ value

Attaches a value to the evaluation under the given key

Examples:

evaluation = concurrently{ :result }
evaluation[:key] = :value
evaluation[:key]  # => :value

Since:

  • 1.0.0


35
36
37
# File 'lib/all/concurrently/proc/evaluation.rb', line 35

def []=(key, value)
  @data[key] = value
end

#await_result(opts = {}) ⇒ Object #await_result(opts = {}) {|result| ... } ⇒ Object

Waits for the evaluation to be concluded with a result.

The result can be awaited from multiple places at once. All of them are resumed once the result is available.

Examples:

Waiting inside another concurrent evaluation

# Control flow is indicated by (N)

# (1)
evaluation = concurrently do
  # (4)
  :result
end

# (2)
concurrent_proc do
  # (3)
  evaluation.await_result
  # (5)
end.call # => :result
# (6)

Waiting outside a concurrent evaluation

# Control flow is indicated by (N)

# (1)
evaluation = concurrently do
  # (3)
  :result
end

# (2)
evaluation.await_result # => :result
# (4)

Waiting with a timeout

evaluation = concurrently do
  wait 1
  :result
end

evaluation.await_result within: 0.1
# => raises a TimeoutError after 0.1 seconds

Waiting with a timeout and a timeout result

evaluation = concurrently do
  wait 1
  :result
end

evaluation.await_result within: 0.1, timeout_result: false
# => returns false after 0.1 seconds

When the evaluation raises or returns an error

evaluation = concurrently do
  RuntimeError.new("self destruct!") # equivalent: raise "self destruct!"
end

evaluation.await_result # => raises "self destruct!"

Overloads:

  • #await_result(opts = {}) {|result| ... } ⇒ Object

    Use the block to do something with the result before returning it. This can be used to validate or transform the result.

    Examples:

    Transforming a result

    evaluation = concurrently do
      :result
    end
    
    evaluation.await_result{ |result| "transformed_#{result}" }
    # => "transformed_result"

    Validating a result

    evaluation = concurrently do
      :invalid_result
    end
    
    evaluation.await_result{ |result| raise "invalid result" if result != :result }
    # => raises "invalid result"

    Yield Parameters:

    • result (Object)

      its result

    Yield Returns:

    • (Object)

      a (potentially) transformed result

Options Hash (opts):

  • :within (Numeric)

    maximum time to wait (defaults to: Float::INFINITY)

  • :timeout_result (Object)

    result to return in case of an exceeded waiting time (defaults to raising Evaluation::TimeoutError)

Raises:

Since:

  • 1.0.0


216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/all/concurrently/proc/evaluation.rb', line 216

def await_result(opts = {}) # &with_result
  result = if @concluded
             @result
           else
             begin
               Concurrently::Evaluation.current.__await_result_of__ self, opts
             rescue Exception => error
               error
             end
           end

  result = yield result if block_given?

  (Exception === result) ? (raise result) : result
end

#conclude_to(result) ⇒ :concluded

Cancels the concurrent evaluation prematurely by injecting a result.

Examples:

# Control flow is indicated by (N)

# (1)
evaluation = concurrently do
  # (4)
  wait 1
  # never reached
  :result
end

# (2)
concurrently do
  # (5)
  evaluation.conclude_to :premature_result
end

# (3)
evaluation.await_result # => :premature_result
# (6)

Raises:

  • (Error)

    if it is already concluded

Since:

  • 1.0.0


268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/all/concurrently/proc/evaluation.rb', line 268

def conclude_to(result)
  if @concluded
    raise self.class::Error, "already concluded\n#{Debug.notice_for @fiber}"
  end

  @result = result
  @concluded = true

  if Fiber.current != @fiber
    # Cancel its fiber
    run_queue = Concurrently::EventLoop.current.run_queue
    previous_evaluation = run_queue.current_evaluation
    run_queue.current_evaluation = self
    @fiber.resume Cancelled
    run_queue.current_evaluation = previous_evaluation
  end

  @waiting_evaluations.each{ |evaluation, override| evaluation.resume! (override or result) }
  :concluded
end

#key?(key) ⇒ Boolean

Checks if there is an attached value for the given key

Examples:

evaluation = concurrently{ :result }
evaluation[:key] = :value
evaluation.key? :key          # => true
evaluation.key? :another_key  # => false

Since:

  • 1.0.0


62
63
64
# File 'lib/all/concurrently/proc/evaluation.rb', line 62

def key?(key)
  @data.key? key
end

#keysArray

Returns all keys with values

Examples:

evaluation = concurrently{ :result }
evaluation[:key1] = :value1
evaluation[:key2] = :value2
evaluation.keys  # => [:key1, :key2]

Since:

  • 1.0.0


75
76
77
# File 'lib/all/concurrently/proc/evaluation.rb', line 75

def keys
  @data.keys
end