Class: Temporalio::Workflow::Future

Inherits:
Object
  • Object
show all
Defined in:
lib/temporalio/workflow/future.rb

Defined Under Namespace

Classes: Rejected

Constant Summary collapse

THREAD_KEY =
:temporalio_workflow_future

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(&block) ⇒ Future

Revist the reason for combining futures and cancellation scopes, maybe they are separate?



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/temporalio/workflow/future.rb', line 17

def initialize(&block)
  @resolved = false
  @value = nil
  @rejected = false
  @error = Rejected.new('Future rejected')
  @cancel_requested = false
  @blocked_fibers = []
  @callbacks = []
  @cancel_callbacks = []

  # Chain cancellation into parent future if one exists
  Future.current&.on_cancel { cancel }

  # NOTE: resolve and reject methods are accessible via procs to avoid exposing
  #       them via the public interface.
  block.call(
    self,
    ->(value) { resolve(value) },
    ->(error) { reject(error) },
  )
end

Class Method Details

.currentObject



8
9
10
# File 'lib/temporalio/workflow/future.rb', line 8

def self.current
  Thread.current[THREAD_KEY]
end

.current=(future) ⇒ Object



12
13
14
# File 'lib/temporalio/workflow/future.rb', line 12

def self.current=(future)
  Thread.current[THREAD_KEY] = future
end

Instance Method Details

#awaitObject



81
82
83
84
85
86
87
88
89
90
91
# File 'lib/temporalio/workflow/future.rb', line 81

def await
  if pending?
    blocked_fibers << Fiber.current
    # yield into the parent fiber
    Fiber.yield while pending?
  end

  raise error if rejected?

  value
end

#cancelObject



93
94
95
96
97
98
99
# File 'lib/temporalio/workflow/future.rb', line 93

def cancel
  return unless pending?
  return if cancel_requested?

  @cancel_requested = true
  cancel_callbacks.each(&:call)
end

#on_cancel(&block) ⇒ Object



61
62
63
64
65
66
67
# File 'lib/temporalio/workflow/future.rb', line 61

def on_cancel(&block)
  if pending? && !cancel_requested?
    cancel_callbacks << block
  else
    block.call
  end
end

#pending?Boolean

Returns:

  • (Boolean)


69
70
71
# File 'lib/temporalio/workflow/future.rb', line 69

def pending?
  !resolved? && !rejected?
end

#rejected?Boolean

Returns:

  • (Boolean)


77
78
79
# File 'lib/temporalio/workflow/future.rb', line 77

def rejected?
  @rejected
end

#resolved?Boolean

Returns:

  • (Boolean)


73
74
75
# File 'lib/temporalio/workflow/future.rb', line 73

def resolved?
  @resolved
end

#then(&block) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/temporalio/workflow/future.rb', line 39

def then(&block)
  Future.new do |future, resolve, reject|
    # @type var wrapped_block: ^() -> void
    wrapped_block = -> do # rubocop:disable Style/Lambda
      Fiber.new do
        Future.current = future
        # The block is provided the Future on which #then was called
        result = block.call(self)
        resolve.call(result)
      rescue StandardError => e
        reject.call(e)
      end.resume
    end

    if pending?
      callbacks << wrapped_block
    else
      wrapped_block.call
    end
  end
end