temporalio 0.2.0 → 0.4.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 (141) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -0
  3. data/Cargo.lock +980 -583
  4. data/Cargo.toml +2 -2
  5. data/Gemfile +7 -3
  6. data/README.md +769 -54
  7. data/Rakefile +10 -296
  8. data/ext/Cargo.toml +2 -0
  9. data/lib/temporalio/activity/complete_async_error.rb +1 -1
  10. data/lib/temporalio/activity/context.rb +18 -2
  11. data/lib/temporalio/activity/definition.rb +180 -65
  12. data/lib/temporalio/activity/info.rb +25 -21
  13. data/lib/temporalio/activity.rb +2 -59
  14. data/lib/temporalio/api/activity/v1/message.rb +25 -0
  15. data/lib/temporalio/api/batch/v1/message.rb +6 -1
  16. data/lib/temporalio/api/cloud/account/v1/message.rb +28 -0
  17. data/lib/temporalio/api/cloud/cloudservice/v1/request_response.rb +34 -1
  18. data/lib/temporalio/api/cloud/cloudservice/v1/service.rb +1 -1
  19. data/lib/temporalio/api/cloud/identity/v1/message.rb +6 -1
  20. data/lib/temporalio/api/cloud/namespace/v1/message.rb +8 -1
  21. data/lib/temporalio/api/cloud/nexus/v1/message.rb +31 -0
  22. data/lib/temporalio/api/cloud/operation/v1/message.rb +2 -1
  23. data/lib/temporalio/api/cloud/region/v1/message.rb +2 -1
  24. data/lib/temporalio/api/cloud/resource/v1/message.rb +23 -0
  25. data/lib/temporalio/api/cloud/sink/v1/message.rb +24 -0
  26. data/lib/temporalio/api/cloud/usage/v1/message.rb +31 -0
  27. data/lib/temporalio/api/command/v1/message.rb +1 -1
  28. data/lib/temporalio/api/common/v1/message.rb +8 -1
  29. data/lib/temporalio/api/deployment/v1/message.rb +38 -0
  30. data/lib/temporalio/api/enums/v1/batch_operation.rb +1 -1
  31. data/lib/temporalio/api/enums/v1/common.rb +1 -1
  32. data/lib/temporalio/api/enums/v1/deployment.rb +23 -0
  33. data/lib/temporalio/api/enums/v1/event_type.rb +1 -1
  34. data/lib/temporalio/api/enums/v1/failed_cause.rb +1 -1
  35. data/lib/temporalio/api/enums/v1/nexus.rb +21 -0
  36. data/lib/temporalio/api/enums/v1/reset.rb +1 -1
  37. data/lib/temporalio/api/enums/v1/workflow.rb +2 -1
  38. data/lib/temporalio/api/errordetails/v1/message.rb +3 -1
  39. data/lib/temporalio/api/failure/v1/message.rb +3 -1
  40. data/lib/temporalio/api/history/v1/message.rb +3 -1
  41. data/lib/temporalio/api/nexus/v1/message.rb +3 -2
  42. data/lib/temporalio/api/operatorservice/v1/service.rb +1 -1
  43. data/lib/temporalio/api/payload_visitor.rb +1581 -0
  44. data/lib/temporalio/api/query/v1/message.rb +2 -1
  45. data/lib/temporalio/api/schedule/v1/message.rb +2 -1
  46. data/lib/temporalio/api/taskqueue/v1/message.rb +4 -1
  47. data/lib/temporalio/api/testservice/v1/request_response.rb +31 -0
  48. data/lib/temporalio/api/testservice/v1/service.rb +23 -0
  49. data/lib/temporalio/api/workflow/v1/message.rb +9 -1
  50. data/lib/temporalio/api/workflowservice/v1/request_response.rb +46 -2
  51. data/lib/temporalio/api/workflowservice/v1/service.rb +1 -1
  52. data/lib/temporalio/api.rb +2 -0
  53. data/lib/temporalio/cancellation.rb +34 -14
  54. data/lib/temporalio/client/async_activity_handle.rb +12 -37
  55. data/lib/temporalio/client/connection/cloud_service.rb +309 -231
  56. data/lib/temporalio/client/connection/operator_service.rb +36 -84
  57. data/lib/temporalio/client/connection/service.rb +6 -5
  58. data/lib/temporalio/client/connection/test_service.rb +111 -0
  59. data/lib/temporalio/client/connection/workflow_service.rb +474 -441
  60. data/lib/temporalio/client/connection.rb +90 -44
  61. data/lib/temporalio/client/interceptor.rb +199 -60
  62. data/lib/temporalio/client/schedule.rb +991 -0
  63. data/lib/temporalio/client/schedule_handle.rb +126 -0
  64. data/lib/temporalio/client/with_start_workflow_operation.rb +115 -0
  65. data/lib/temporalio/client/workflow_execution.rb +26 -10
  66. data/lib/temporalio/client/workflow_handle.rb +41 -98
  67. data/lib/temporalio/client/workflow_update_handle.rb +3 -5
  68. data/lib/temporalio/client.rb +247 -44
  69. data/lib/temporalio/common_enums.rb +17 -0
  70. data/lib/temporalio/contrib/open_telemetry.rb +470 -0
  71. data/lib/temporalio/converters/data_converter.rb +4 -7
  72. data/lib/temporalio/converters/failure_converter.rb +5 -3
  73. data/lib/temporalio/converters/payload_converter/composite.rb +4 -0
  74. data/lib/temporalio/converters/payload_converter.rb +6 -8
  75. data/lib/temporalio/converters/raw_value.rb +20 -0
  76. data/lib/temporalio/error/failure.rb +1 -1
  77. data/lib/temporalio/error.rb +11 -2
  78. data/lib/temporalio/internal/bridge/api/activity_task/activity_task.rb +1 -1
  79. data/lib/temporalio/internal/bridge/api/common/common.rb +2 -1
  80. data/lib/temporalio/internal/bridge/api/core_interface.rb +5 -1
  81. data/lib/temporalio/internal/bridge/api/nexus/nexus.rb +33 -0
  82. data/lib/temporalio/internal/bridge/api/workflow_activation/workflow_activation.rb +5 -1
  83. data/lib/temporalio/internal/bridge/api/workflow_commands/workflow_commands.rb +4 -1
  84. data/lib/temporalio/internal/bridge/api/workflow_completion/workflow_completion.rb +2 -1
  85. data/lib/temporalio/internal/bridge/client.rb +11 -6
  86. data/lib/temporalio/internal/bridge/runtime.rb +3 -0
  87. data/lib/temporalio/internal/bridge/testing.rb +23 -0
  88. data/lib/temporalio/internal/bridge/worker.rb +2 -0
  89. data/lib/temporalio/internal/bridge.rb +1 -1
  90. data/lib/temporalio/internal/client/implementation.rb +468 -71
  91. data/lib/temporalio/internal/metric.rb +122 -0
  92. data/lib/temporalio/internal/proto_utils.rb +118 -7
  93. data/lib/temporalio/internal/worker/activity_worker.rb +69 -29
  94. data/lib/temporalio/internal/worker/multi_runner.rb +53 -9
  95. data/lib/temporalio/internal/worker/workflow_instance/child_workflow_handle.rb +54 -0
  96. data/lib/temporalio/internal/worker/workflow_instance/context.rb +383 -0
  97. data/lib/temporalio/internal/worker/workflow_instance/details.rb +46 -0
  98. data/lib/temporalio/internal/worker/workflow_instance/external_workflow_handle.rb +32 -0
  99. data/lib/temporalio/internal/worker/workflow_instance/externally_immutable_hash.rb +22 -0
  100. data/lib/temporalio/internal/worker/workflow_instance/handler_execution.rb +25 -0
  101. data/lib/temporalio/internal/worker/workflow_instance/handler_hash.rb +41 -0
  102. data/lib/temporalio/internal/worker/workflow_instance/illegal_call_tracer.rb +97 -0
  103. data/lib/temporalio/internal/worker/workflow_instance/inbound_implementation.rb +62 -0
  104. data/lib/temporalio/internal/worker/workflow_instance/outbound_implementation.rb +400 -0
  105. data/lib/temporalio/internal/worker/workflow_instance/replay_safe_logger.rb +37 -0
  106. data/lib/temporalio/internal/worker/workflow_instance/replay_safe_metric.rb +40 -0
  107. data/lib/temporalio/internal/worker/workflow_instance/scheduler.rb +183 -0
  108. data/lib/temporalio/internal/worker/workflow_instance.rb +774 -0
  109. data/lib/temporalio/internal/worker/workflow_worker.rb +239 -0
  110. data/lib/temporalio/metric.rb +109 -0
  111. data/lib/temporalio/retry_policy.rb +37 -14
  112. data/lib/temporalio/runtime/metric_buffer.rb +94 -0
  113. data/lib/temporalio/runtime.rb +160 -79
  114. data/lib/temporalio/search_attributes.rb +93 -37
  115. data/lib/temporalio/testing/activity_environment.rb +44 -16
  116. data/lib/temporalio/testing/workflow_environment.rb +276 -7
  117. data/lib/temporalio/version.rb +1 -1
  118. data/lib/temporalio/worker/activity_executor/thread_pool.rb +9 -217
  119. data/lib/temporalio/worker/activity_executor.rb +3 -3
  120. data/lib/temporalio/worker/interceptor.rb +343 -66
  121. data/lib/temporalio/worker/thread_pool.rb +237 -0
  122. data/lib/temporalio/worker/tuner.rb +38 -0
  123. data/lib/temporalio/worker/workflow_executor/thread_pool.rb +235 -0
  124. data/lib/temporalio/worker/workflow_executor.rb +26 -0
  125. data/lib/temporalio/worker/workflow_replayer.rb +350 -0
  126. data/lib/temporalio/worker.rb +235 -58
  127. data/lib/temporalio/workflow/activity_cancellation_type.rb +20 -0
  128. data/lib/temporalio/workflow/child_workflow_cancellation_type.rb +21 -0
  129. data/lib/temporalio/workflow/child_workflow_handle.rb +43 -0
  130. data/lib/temporalio/workflow/definition.rb +598 -0
  131. data/lib/temporalio/workflow/external_workflow_handle.rb +41 -0
  132. data/lib/temporalio/workflow/future.rb +151 -0
  133. data/lib/temporalio/workflow/handler_unfinished_policy.rb +13 -0
  134. data/lib/temporalio/workflow/info.rb +104 -0
  135. data/lib/temporalio/workflow/parent_close_policy.rb +19 -0
  136. data/lib/temporalio/workflow/update_info.rb +20 -0
  137. data/lib/temporalio/workflow.rb +575 -0
  138. data/lib/temporalio/workflow_history.rb +26 -1
  139. data/lib/temporalio.rb +4 -0
  140. data/temporalio.gemspec +4 -3
  141. metadata +73 -10
@@ -0,0 +1,183 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'temporalio'
4
+ require 'temporalio/cancellation'
5
+ require 'temporalio/error'
6
+ require 'temporalio/internal/worker/workflow_instance'
7
+ require 'temporalio/workflow'
8
+ require 'timeout'
9
+
10
+ module Temporalio
11
+ module Internal
12
+ module Worker
13
+ class WorkflowInstance
14
+ # Deterministic {::Fiber::Scheduler} implementation.
15
+ class Scheduler
16
+ def initialize(instance)
17
+ @instance = instance
18
+ @fibers = []
19
+ @ready = []
20
+ @wait_conditions = {}
21
+ @wait_condition_counter = 0
22
+ end
23
+
24
+ def context
25
+ @instance.context
26
+ end
27
+
28
+ def run_until_all_yielded
29
+ loop do
30
+ # Run all fibers until all yielded
31
+ while (fiber = @ready.shift)
32
+ fiber.resume
33
+ end
34
+
35
+ # Find the _first_ resolvable wait condition and if there, resolve it, and loop again, otherwise return.
36
+ # It is important that we both let fibers get all settled _before_ this and only allow a _single_ wait
37
+ # condition to be satisfied before looping. This allows wait condition users to trust that the line of
38
+ # code after the wait condition still has the condition satisfied.
39
+ # @type var cond_fiber: Fiber?
40
+ cond_fiber = nil
41
+ cond_result = nil
42
+ @wait_conditions.each do |seq, cond|
43
+ next unless (cond_result = cond.first.call)
44
+
45
+ cond_fiber = cond[1]
46
+ @wait_conditions.delete(seq)
47
+ break
48
+ end
49
+ return unless cond_fiber
50
+
51
+ cond_fiber.resume(cond_result)
52
+ end
53
+ end
54
+
55
+ def wait_condition(cancellation:, &block)
56
+ raise Workflow::InvalidWorkflowStateError, 'Cannot wait in this context' if @instance.context_frozen
57
+
58
+ if cancellation&.canceled?
59
+ raise Error::CanceledError,
60
+ cancellation.canceled_reason || 'Wait condition canceled before started'
61
+ end
62
+
63
+ seq = (@wait_condition_counter += 1)
64
+ @wait_conditions[seq] = [block, Fiber.current]
65
+
66
+ # Add a cancellation callback
67
+ cancel_callback_key = cancellation&.add_cancel_callback do
68
+ # Only if the condition is still present
69
+ cond = @wait_conditions.delete(seq)
70
+ if cond&.last&.alive?
71
+ cond&.last&.raise(Error::CanceledError.new(cancellation&.canceled_reason || 'Wait condition canceled'))
72
+ end
73
+ end
74
+
75
+ # This blocks until a resume is called on this fiber
76
+ result = Fiber.yield
77
+
78
+ # Remove cancellation callback (only needed on success)
79
+ cancellation&.remove_cancel_callback(cancel_callback_key) if cancel_callback_key
80
+
81
+ result
82
+ end
83
+
84
+ def stack_trace
85
+ # Collect backtraces of known fibers, separating with a blank line. We make sure to remove any lines that
86
+ # reference Temporal paths, and we remove any empty backtraces.
87
+ dir_path = @instance.illegal_call_tracing_disabled { File.dirname(Temporalio._root_file_path) }
88
+ @fibers.map do |fiber|
89
+ fiber.backtrace.reject { |s| s.start_with?(dir_path) }.join("\n")
90
+ end.reject(&:empty?).join("\n\n")
91
+ end
92
+
93
+ ###
94
+ # Fiber::Scheduler methods
95
+ #
96
+ # Note, we do not implement many methods here such as io_read and
97
+ # such. While it might seem to make sense to implement them and
98
+ # raise, we actually want to default to the blocking behavior of them
99
+ # not being present. This is so advanced things like logging still
100
+ # work inside of workflows. So we only implement the bare minimum.
101
+ ###
102
+
103
+ def block(_blocker, timeout = nil)
104
+ # TODO(cretz): Make the blocker visible in the stack trace?
105
+
106
+ # We just yield because unblock will resume this. We will just wrap in timeout if needed.
107
+ if timeout
108
+ begin
109
+ Timeout.timeout(timeout) { Fiber.yield }
110
+ true
111
+ rescue Timeout::Error
112
+ false
113
+ end
114
+ else
115
+ Fiber.yield
116
+ true
117
+ end
118
+ end
119
+
120
+ def close
121
+ # Nothing to do here, lifetime of scheduler is controlled by the instance
122
+ end
123
+
124
+ def fiber(&block)
125
+ if @instance.context_frozen
126
+ raise Workflow::InvalidWorkflowStateError, 'Cannot schedule fibers in this context'
127
+ end
128
+
129
+ fiber = Fiber.new do
130
+ block.call # steep:ignore
131
+ ensure
132
+ @fibers.delete(Fiber.current)
133
+ end
134
+ @fibers << fiber
135
+ @ready << fiber
136
+ fiber
137
+ end
138
+
139
+ def io_wait(io, events, timeout)
140
+ # Do not allow if IO disabled
141
+ unless @instance.io_enabled
142
+ raise Workflow::NondeterminismError,
143
+ 'Cannot perform IO from inside a workflow. If this is known to be safe, ' \
144
+ 'the code can be run in a Temporalio::Workflow::Unsafe.io_enabled block.'
145
+ end
146
+
147
+ # Use regular Ruby behavior of blocking this thread. There is no Ruby implementation of io_wait we can just
148
+ # delegate to at this time (or default scheduler or anything like that), so we had to implement this
149
+ # ourselves.
150
+ readers = events.nobits?(IO::READABLE) ? nil : [io]
151
+ writers = events.nobits?(IO::WRITABLE) ? nil : [io]
152
+ priority = events.nobits?(IO::PRIORITY) ? nil : [io]
153
+ ready = IO.select(readers, writers, priority, timeout) # steep:ignore
154
+
155
+ result = 0
156
+ unless ready.nil?
157
+ result |= IO::READABLE if ready[0]&.include?(io)
158
+ result |= IO::WRITABLE if ready[1]&.include?(io)
159
+ result |= IO::PRIORITY if ready[2]&.include?(io)
160
+ end
161
+ result
162
+ end
163
+
164
+ def kernel_sleep(duration = nil)
165
+ Workflow.sleep(duration)
166
+ end
167
+
168
+ def process_wait(pid, flags)
169
+ raise NotImplementedError, 'Cannot wait on other processes in workflows'
170
+ end
171
+
172
+ def timeout_after(duration, exception_class, *exception_arguments, &)
173
+ context.timeout(duration, exception_class, *exception_arguments, summary: 'Timeout timer', &)
174
+ end
175
+
176
+ def unblock(_blocker, fiber)
177
+ @ready << fiber
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end