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

current

Instance Attribute Details

#concluded?Boolean (readonly)

Checks if the evaluation is concluded

Returns:

  • (Boolean)

Since:

  • 1.0.0



198
199
200
# File 'lib/all/concurrently/proc/evaluation.rb', line 198

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

Parameters:

  • key (Object)

    The key to look up

Returns:

  • (Object)

    the stored 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

Parameters:

  • key (Object)

    The key to store the value under

  • value (Object)

    The value to store

Returns:

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

Parameters:

  • opts (Hash) (defaults to: {})

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)

Returns:

  • (Object)

    the result the evaluation is concluded with

Raises:

Since:

  • 1.0.0



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/all/concurrently/proc/evaluation.rb', line 173

def await_result(opts = {}) # &with_result
  if @concluded
    result = @result
  else
    result = begin
      evaluation = Concurrently::Evaluation.current
      @awaiting_result.store evaluation, false
      await_resume! opts
    rescue Exception => error
      error
    ensure
      @awaiting_result.delete evaluation
    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)

Parameters:

  • result (Object)

Returns:

  • (:concluded)

Raises:

  • (Error)

    if it is already concluded

Since:

  • 1.0.0



229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/all/concurrently/proc/evaluation.rb', line 229

def conclude_to(result)
  if @concluded
    raise self.class::Error, "already concluded"
  end

  @result = result
  @concluded = true

  if Fiber.current != @fiber
    # Cancel its fiber by resuming it with itself as argument
    @fiber.resume Cancelled
  end

  @awaiting_result.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

Parameters:

  • key (Object)

    The key to look up

Returns:

  • (Boolean)

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]

Returns:

  • (Array)

Since:

  • 1.0.0



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

def keys
  @data.keys
end

#resume!Object

Schedules the evaluation to be resumed

For details see: Evaluation#resume!

Raises:

Since:

  • 1.0.0



251
252
253
254
# File 'lib/all/concurrently/proc/evaluation.rb', line 251

def resume!(*)
  raise Evaluation::Error, "already concluded to #{@result.inspect}" if @concluded
  super
end