Class: Phronomy::Task::FiberBackend Private

Inherits:
Backend
  • Object
show all
Defined in:
lib/phronomy/task/fiber_backend.rb

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Instance Method Summary collapse

Methods inherited from Backend

#completed_error, #completed_value

Constructor Details

#initialize(task:, &block) ⇒ FiberBackend

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of FiberBackend.



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/phronomy/task/fiber_backend.rb', line 22

def initialize(task:, &block)
  super
  @value = nil
  @error = nil
  @cancel_error = nil
  @cancel_requested = false
  @started = false
  @cooperative_suspend = false

  # Capture `self` (the FiberBackend instance) in the closure so that
  # instance-variable writes from inside the Fiber update this object.
  @fiber = Fiber.new do
    task.transition!(:running)
    begin
      # If cancel! was called before the first step, raise immediately.
      raise @cancel_error if @cancel_error

      @value = block.call
      task.transition!(:completed, value: @value)
    rescue CancellationError => e
      task.transition!(:cancelled, error: e)
      @error = e
    rescue => e
      task.transition!(:failed, error: e)
      @error = e
    ensure
      task.transition!(:cancelled) unless task.done?
    end
  end
end

Instance Method Details

#alive?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns +true+ while the Fiber has not yet finished.

Returns:

  • (Boolean)

    +true+ while the Fiber has not yet finished



129
130
131
# File 'lib/phronomy/task/fiber_backend.rb', line 129

def alive?
  @fiber.alive?
end

#awaitObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Blocks until the task completes.

When called from within a DeterministicScheduler-managed Fiber, suspends the current Fiber cooperatively and schedules it to resume when this task completes. When called from outside a managed Fiber (e.g. the main fiber or a regular thread), drives execution by calling #step in a loop.

Returns:

  • (Object)

Raises:

  • (Exception)


103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/phronomy/task/fiber_backend.rb', line 103

def await
  unless @fiber.alive?
    raise @error if @error
    return @value
  end

  scheduler = Thread.current.thread_variable_get(SCHEDULER_KEY)
  # Fiber.main was added in Ruby 3.2.4+; fall back to true (assume we are
  # inside a managed Fiber whenever a scheduler is active).
  in_managed_fiber = !Fiber.respond_to?(:main) || Fiber.current != Fiber.main
  if scheduler && in_managed_fiber
    # Cooperative context: suspend current Fiber until task is done.
    waiting_fiber = Fiber.current
    @task.on_complete { scheduler.enqueue_fiber(-> { waiting_fiber.resume }) }
    Fiber.yield(:cooperative_suspend)
  else
    # Non-cooperative context: drive the fiber to completion.
    step while @fiber.alive?
  end

  raise @error if @error
  @value
end

#cancel!self

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Requests cancellation using a cooperative checkpoint mechanism. Sets a cancellation flag; the error is raised inside the Fiber at the next +step+ call (i.e. when the scheduler next dispatches this task), not injected at an arbitrary suspension point via +Fiber#raise+. If the Fiber has not yet started, the error is recorded so it is raised on the first #step.

Returns:

  • (self)


141
142
143
144
145
# File 'lib/phronomy/task/fiber_backend.rb', line 141

def cancel!
  @cancel_error = CancellationError.new("Task cancelled")
  @cancel_requested = true
  self
end

#cooperative_suspend?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns +true+ if the Fiber yielded cooperatively (via a signal wait) and should not be automatically re-enqueued by the scheduler.

Returns:

  • (Boolean)


88
89
90
# File 'lib/phronomy/task/fiber_backend.rb', line 88

def cooperative_suspend?
  @cooperative_suspend
end

#join(_limit = nil) ⇒ self

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Joins execution by stepping until the Fiber is no longer alive.

Parameters:

  • limit (Numeric, nil)

    ignored

Returns:

  • (self)


151
152
153
154
# File 'lib/phronomy/task/fiber_backend.rb', line 151

def join(_limit = nil)
  step while @fiber.alive?
  self
end

#stepself

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Advances execution by one scheduler step. Resumes the Fiber until it yields (via +Fiber.yield+) or finishes. Cooperative cancellation is checked at the start of each step: if +cancel!+ has been called, +CancellationError+ is raised inside the Fiber at this controlled checkpoint rather than injected at an arbitrary suspension point via +Fiber#raise+.

Returns:

  • (self)


61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/phronomy/task/fiber_backend.rb', line 61

def step
  return self unless @fiber.alive?

  @started = true
  # Deliver pending cancellation at this scheduler checkpoint rather than
  # injecting it mid-Fiber via Fiber#raise (which would be preemptive).
  if @cancel_requested && @cancel_error
    begin
      @fiber.raise(@cancel_error)
    rescue FiberError
      nil  # Fiber completed between the check and raise — safe to ignore.
    end
    @cancel_requested = false
    return self
  end
  yield_value = @fiber.resume
  # A yield value of :cooperative_suspend signals that the Fiber deliberately
  # suspended itself (e.g. inside CoopSignal#wait) and must NOT be
  # re-enqueued by step_callable — it will be resumed by an explicit signal.
  @cooperative_suspend = (yield_value == :cooperative_suspend)
  self
end