temporalio 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +2 -0
- data/Cargo.lock +659 -370
- data/Cargo.toml +2 -2
- data/Gemfile +3 -3
- data/README.md +589 -47
- data/Rakefile +10 -296
- data/ext/Cargo.toml +1 -0
- data/lib/temporalio/activity/complete_async_error.rb +1 -1
- data/lib/temporalio/activity/context.rb +5 -2
- data/lib/temporalio/activity/definition.rb +163 -65
- data/lib/temporalio/activity/info.rb +22 -21
- data/lib/temporalio/activity.rb +2 -59
- data/lib/temporalio/api/activity/v1/message.rb +25 -0
- data/lib/temporalio/api/cloud/account/v1/message.rb +28 -0
- data/lib/temporalio/api/cloud/cloudservice/v1/request_response.rb +34 -1
- data/lib/temporalio/api/cloud/cloudservice/v1/service.rb +1 -1
- data/lib/temporalio/api/cloud/identity/v1/message.rb +6 -1
- data/lib/temporalio/api/cloud/namespace/v1/message.rb +8 -1
- data/lib/temporalio/api/cloud/nexus/v1/message.rb +31 -0
- data/lib/temporalio/api/cloud/operation/v1/message.rb +2 -1
- data/lib/temporalio/api/cloud/region/v1/message.rb +2 -1
- data/lib/temporalio/api/cloud/resource/v1/message.rb +23 -0
- data/lib/temporalio/api/cloud/sink/v1/message.rb +24 -0
- data/lib/temporalio/api/cloud/usage/v1/message.rb +31 -0
- data/lib/temporalio/api/common/v1/message.rb +7 -1
- data/lib/temporalio/api/enums/v1/event_type.rb +1 -1
- data/lib/temporalio/api/enums/v1/failed_cause.rb +1 -1
- data/lib/temporalio/api/enums/v1/reset.rb +1 -1
- data/lib/temporalio/api/history/v1/message.rb +1 -1
- data/lib/temporalio/api/nexus/v1/message.rb +2 -2
- data/lib/temporalio/api/operatorservice/v1/service.rb +1 -1
- data/lib/temporalio/api/payload_visitor.rb +1513 -0
- data/lib/temporalio/api/schedule/v1/message.rb +2 -1
- data/lib/temporalio/api/testservice/v1/request_response.rb +31 -0
- data/lib/temporalio/api/testservice/v1/service.rb +23 -0
- data/lib/temporalio/api/workflow/v1/message.rb +1 -1
- data/lib/temporalio/api/workflowservice/v1/request_response.rb +17 -2
- data/lib/temporalio/api/workflowservice/v1/service.rb +1 -1
- data/lib/temporalio/api.rb +1 -0
- data/lib/temporalio/cancellation.rb +34 -14
- data/lib/temporalio/client/async_activity_handle.rb +12 -37
- data/lib/temporalio/client/connection/cloud_service.rb +309 -231
- data/lib/temporalio/client/connection/operator_service.rb +36 -84
- data/lib/temporalio/client/connection/service.rb +6 -5
- data/lib/temporalio/client/connection/test_service.rb +111 -0
- data/lib/temporalio/client/connection/workflow_service.rb +264 -441
- data/lib/temporalio/client/connection.rb +90 -44
- data/lib/temporalio/client/interceptor.rb +160 -60
- data/lib/temporalio/client/schedule.rb +967 -0
- data/lib/temporalio/client/schedule_handle.rb +126 -0
- data/lib/temporalio/client/workflow_execution.rb +7 -10
- data/lib/temporalio/client/workflow_handle.rb +38 -95
- data/lib/temporalio/client/workflow_update_handle.rb +3 -5
- data/lib/temporalio/client.rb +122 -42
- data/lib/temporalio/common_enums.rb +17 -0
- data/lib/temporalio/converters/data_converter.rb +4 -7
- data/lib/temporalio/converters/failure_converter.rb +5 -3
- data/lib/temporalio/converters/payload_converter/composite.rb +4 -0
- data/lib/temporalio/converters/payload_converter.rb +6 -8
- data/lib/temporalio/converters/raw_value.rb +20 -0
- data/lib/temporalio/error/failure.rb +1 -1
- data/lib/temporalio/error.rb +10 -2
- data/lib/temporalio/internal/bridge/api/core_interface.rb +5 -1
- data/lib/temporalio/internal/bridge/api/nexus/nexus.rb +33 -0
- data/lib/temporalio/internal/bridge/api/workflow_activation/workflow_activation.rb +5 -1
- data/lib/temporalio/internal/bridge/api/workflow_commands/workflow_commands.rb +4 -1
- data/lib/temporalio/internal/bridge/client.rb +11 -6
- data/lib/temporalio/internal/bridge/testing.rb +20 -0
- data/lib/temporalio/internal/bridge/worker.rb +2 -0
- data/lib/temporalio/internal/bridge.rb +1 -1
- data/lib/temporalio/internal/client/implementation.rb +245 -70
- data/lib/temporalio/internal/metric.rb +122 -0
- data/lib/temporalio/internal/proto_utils.rb +86 -7
- data/lib/temporalio/internal/worker/activity_worker.rb +52 -24
- data/lib/temporalio/internal/worker/multi_runner.rb +51 -7
- data/lib/temporalio/internal/worker/workflow_instance/child_workflow_handle.rb +54 -0
- data/lib/temporalio/internal/worker/workflow_instance/context.rb +329 -0
- data/lib/temporalio/internal/worker/workflow_instance/details.rb +44 -0
- data/lib/temporalio/internal/worker/workflow_instance/external_workflow_handle.rb +32 -0
- data/lib/temporalio/internal/worker/workflow_instance/externally_immutable_hash.rb +22 -0
- data/lib/temporalio/internal/worker/workflow_instance/handler_execution.rb +25 -0
- data/lib/temporalio/internal/worker/workflow_instance/handler_hash.rb +41 -0
- data/lib/temporalio/internal/worker/workflow_instance/illegal_call_tracer.rb +97 -0
- data/lib/temporalio/internal/worker/workflow_instance/inbound_implementation.rb +62 -0
- data/lib/temporalio/internal/worker/workflow_instance/outbound_implementation.rb +415 -0
- data/lib/temporalio/internal/worker/workflow_instance/replay_safe_logger.rb +37 -0
- data/lib/temporalio/internal/worker/workflow_instance/replay_safe_metric.rb +40 -0
- data/lib/temporalio/internal/worker/workflow_instance/scheduler.rb +163 -0
- data/lib/temporalio/internal/worker/workflow_instance.rb +730 -0
- data/lib/temporalio/internal/worker/workflow_worker.rb +196 -0
- data/lib/temporalio/metric.rb +109 -0
- data/lib/temporalio/retry_policy.rb +37 -14
- data/lib/temporalio/runtime.rb +118 -75
- data/lib/temporalio/search_attributes.rb +80 -37
- data/lib/temporalio/testing/activity_environment.rb +2 -2
- data/lib/temporalio/testing/workflow_environment.rb +251 -5
- data/lib/temporalio/version.rb +1 -1
- data/lib/temporalio/worker/activity_executor/thread_pool.rb +9 -217
- data/lib/temporalio/worker/activity_executor.rb +3 -3
- data/lib/temporalio/worker/interceptor.rb +340 -66
- data/lib/temporalio/worker/thread_pool.rb +237 -0
- data/lib/temporalio/worker/workflow_executor/thread_pool.rb +230 -0
- data/lib/temporalio/worker/workflow_executor.rb +26 -0
- data/lib/temporalio/worker.rb +201 -30
- data/lib/temporalio/workflow/activity_cancellation_type.rb +20 -0
- data/lib/temporalio/workflow/child_workflow_cancellation_type.rb +21 -0
- data/lib/temporalio/workflow/child_workflow_handle.rb +43 -0
- data/lib/temporalio/workflow/definition.rb +566 -0
- data/lib/temporalio/workflow/external_workflow_handle.rb +41 -0
- data/lib/temporalio/workflow/future.rb +151 -0
- data/lib/temporalio/workflow/handler_unfinished_policy.rb +13 -0
- data/lib/temporalio/workflow/info.rb +82 -0
- data/lib/temporalio/workflow/parent_close_policy.rb +19 -0
- data/lib/temporalio/workflow/update_info.rb +20 -0
- data/lib/temporalio/workflow.rb +523 -0
- data/lib/temporalio.rb +4 -0
- data/temporalio.gemspec +2 -2
- metadata +50 -8
@@ -0,0 +1,523 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'random/formatter'
|
4
|
+
require 'temporalio/error'
|
5
|
+
require 'temporalio/workflow/activity_cancellation_type'
|
6
|
+
require 'temporalio/workflow/child_workflow_cancellation_type'
|
7
|
+
require 'temporalio/workflow/child_workflow_handle'
|
8
|
+
require 'temporalio/workflow/definition'
|
9
|
+
require 'temporalio/workflow/external_workflow_handle'
|
10
|
+
require 'temporalio/workflow/future'
|
11
|
+
require 'temporalio/workflow/handler_unfinished_policy'
|
12
|
+
require 'temporalio/workflow/info'
|
13
|
+
require 'temporalio/workflow/parent_close_policy'
|
14
|
+
require 'temporalio/workflow/update_info'
|
15
|
+
require 'timeout'
|
16
|
+
|
17
|
+
module Temporalio
|
18
|
+
# Module with all class-methods that can be made from a workflow. Methods on this module cannot be used outside of a
|
19
|
+
# workflow with the obvious exception of {in_workflow?}. This module is not meant to be included or mixed in.
|
20
|
+
module Workflow
|
21
|
+
# @return [Boolean] Whether all update and signal handlers have finished executing. Consider waiting on this
|
22
|
+
# condition before workflow return or continue-as-new, to prevent interruption of in-progress handlers by workflow
|
23
|
+
# return: `Temporalio::Workflow.wait_condition { Temporalio::Workflow.all_handlers_finished? }``
|
24
|
+
def self.all_handlers_finished?
|
25
|
+
_current.all_handlers_finished?
|
26
|
+
end
|
27
|
+
|
28
|
+
# @return [Cancellation] Cancellation for the workflow. This is canceled when a workflow cancellation request is
|
29
|
+
# received. This is the default cancellation for most workflow calls.
|
30
|
+
def self.cancellation
|
31
|
+
_current.cancellation
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [Boolean] Whether continue as new is suggested. This value is the current continue-as-new suggestion up
|
35
|
+
# until the current task. Note, this value may not be up to date when accessed in a query. When continue as new is
|
36
|
+
# suggested is based on server-side configuration.
|
37
|
+
def self.continue_as_new_suggested
|
38
|
+
_current.continue_as_new_suggested
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [Integer] Current number of events in history. This value is the current history event count up until the
|
42
|
+
# current task. Note, this value may not be up to date when accessed in a query.
|
43
|
+
def self.current_history_length
|
44
|
+
_current.current_history_length
|
45
|
+
end
|
46
|
+
|
47
|
+
# @return [Integer] Current history size in bytes. This value is the current history size up until the current task.
|
48
|
+
# Note, this value may not be up to date when accessed in a query.
|
49
|
+
def self.current_history_size
|
50
|
+
_current.current_history_size
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [UpdateInfo] Current update info if this code is running inside an update. This is set via a Fiber-local
|
54
|
+
# storage so it is only visible to the current handler fiber.
|
55
|
+
def self.current_update_info
|
56
|
+
_current.current_update_info
|
57
|
+
end
|
58
|
+
|
59
|
+
# Mark a patch as deprecated.
|
60
|
+
#
|
61
|
+
# This marks a workflow that had {patched} in a previous version of the code as no longer applicable because all
|
62
|
+
# workflows that use the old code path are done and will never be queried again. Therefore the old code path is
|
63
|
+
# removed as well.
|
64
|
+
#
|
65
|
+
# @param patch_id [Symbol, String] Patch ID.
|
66
|
+
def self.deprecate_patch(patch_id)
|
67
|
+
_current.deprecate_patch(patch_id)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Execute an activity and return its result. Either `start_to_close_timeout` or `schedule_to_close_timeout` _must_
|
71
|
+
# be set. The `heartbeat_timeout` should be set for any non-immediately-completing activity so it can receive
|
72
|
+
# cancellation. To run an activity in the background, use a {Future}.
|
73
|
+
#
|
74
|
+
# @note Using an already-canceled cancellation may give a different exception than canceling after started. Use
|
75
|
+
# {Error.canceled?} to check if the exception is a cancellation either way.
|
76
|
+
#
|
77
|
+
# @param activity [Class<Activity::Definition>, Symbol, String] Activity definition class or activity name.
|
78
|
+
# @param args [Array<Object>] Arguments to the activity.
|
79
|
+
# @param task_queue [String] Task queue to run the activity on. Defaults to the current workflow's task queue.
|
80
|
+
# @param schedule_to_close_timeout [Float, nil] Max amount of time the activity can take from first being scheduled
|
81
|
+
# to being completed before it times out. This is inclusive of all retries.
|
82
|
+
# @param schedule_to_start_timeout [Float, nil] Max amount of time the activity can take to be started from first
|
83
|
+
# being scheduled.
|
84
|
+
# @param start_to_close_timeout [Float, nil] Max amount of time a single activity run can take from when it starts
|
85
|
+
# to when it completes. This is per retry.
|
86
|
+
# @param heartbeat_timeout [Float, nil] How frequently an activity must invoke heartbeat while running before it is
|
87
|
+
# considered timed out. This also affects how heartbeats are throttled, see general heartbeating documentation.
|
88
|
+
# @param retry_policy [RetryPolicy] How an activity is retried on failure. If unset, a server-defined default is
|
89
|
+
# used. Set maximum attempts to 1 to disable retries.
|
90
|
+
# @param cancellation [Cancellation] Cancellation to apply to the activity. How cancellation is treated is based on
|
91
|
+
# `cancellation_type`. This defaults to the workflow's cancellation, but may need to be overridden with a
|
92
|
+
# new/detached one if an activity is being run in an `ensure` after workflow cancellation.
|
93
|
+
# @param cancellation_type [ActivityCancellationType] How the activity is treated when it is canceled from the
|
94
|
+
# workflow.
|
95
|
+
# @param activity_id [String, nil] Optional unique identifier for the activity. This is an advanced setting that
|
96
|
+
# should not be set unless users are sure they need to. Contact Temporal before setting this value.
|
97
|
+
# @param disable_eager_execution [Boolean] Whether eager execution is disabled. Eager activity execution is an
|
98
|
+
# optimization on some servers that sends activities back to the same worker as the calling workflow if they can
|
99
|
+
# run there. If `false` (the default), eager execution may still be disabled at the worker level or may not be
|
100
|
+
# requested due to lack of available slots.
|
101
|
+
#
|
102
|
+
# @return [Object] Result of the activity.
|
103
|
+
# @raise [Error::ActivityError] Activity failed (and retry was disabled or exhausted).
|
104
|
+
# @raise [Error::CanceledError] Activity was canceled before started. When canceled after started (and not
|
105
|
+
# waited-then-swallowed), instead this canceled error is the cause of a {Error::ActivityError}.
|
106
|
+
def self.execute_activity(
|
107
|
+
activity,
|
108
|
+
*args,
|
109
|
+
task_queue: info.task_queue,
|
110
|
+
schedule_to_close_timeout: nil,
|
111
|
+
schedule_to_start_timeout: nil,
|
112
|
+
start_to_close_timeout: nil,
|
113
|
+
heartbeat_timeout: nil,
|
114
|
+
retry_policy: nil,
|
115
|
+
cancellation: Workflow.cancellation,
|
116
|
+
cancellation_type: ActivityCancellationType::TRY_CANCEL,
|
117
|
+
activity_id: nil,
|
118
|
+
disable_eager_execution: false
|
119
|
+
)
|
120
|
+
_current.execute_activity(
|
121
|
+
activity, *args,
|
122
|
+
task_queue:, schedule_to_close_timeout:, schedule_to_start_timeout:, start_to_close_timeout:,
|
123
|
+
heartbeat_timeout:, retry_policy:, cancellation:, cancellation_type:, activity_id:, disable_eager_execution:
|
124
|
+
)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Shortcut for {start_child_workflow} + {ChildWorkflowHandle.result}. See those two calls for more details.
|
128
|
+
def self.execute_child_workflow(
|
129
|
+
workflow,
|
130
|
+
*args,
|
131
|
+
id: random.uuid,
|
132
|
+
task_queue: info.task_queue,
|
133
|
+
cancellation: Workflow.cancellation,
|
134
|
+
cancellation_type: ChildWorkflowCancellationType::WAIT_CANCELLATION_COMPLETED,
|
135
|
+
parent_close_policy: ParentClosePolicy::TERMINATE,
|
136
|
+
execution_timeout: nil,
|
137
|
+
run_timeout: nil,
|
138
|
+
task_timeout: nil,
|
139
|
+
id_reuse_policy: WorkflowIDReusePolicy::ALLOW_DUPLICATE,
|
140
|
+
retry_policy: nil,
|
141
|
+
cron_schedule: nil,
|
142
|
+
memo: nil,
|
143
|
+
search_attributes: nil
|
144
|
+
)
|
145
|
+
start_child_workflow(
|
146
|
+
workflow, *args,
|
147
|
+
id:, task_queue:, cancellation:, cancellation_type:, parent_close_policy:, execution_timeout:, run_timeout:,
|
148
|
+
task_timeout:, id_reuse_policy:, retry_policy:, cron_schedule:, memo:, search_attributes:
|
149
|
+
).result
|
150
|
+
end
|
151
|
+
|
152
|
+
# Execute an activity locally in this same workflow task and return its result. This should usually only be used for
|
153
|
+
# short/simple activities where the result performance matters. Either `start_to_close_timeout` or
|
154
|
+
# `schedule_to_close_timeout` _must_ be set. To run an activity in the background, use a {Future}.
|
155
|
+
#
|
156
|
+
# @note Using an already-canceled cancellation may give a different exception than canceling after started. Use
|
157
|
+
# {Error.canceled?} to check if the exception is a cancellation either way.
|
158
|
+
#
|
159
|
+
# @param activity [Class<Activity::Definition>, Symbol, String] Activity definition class or name.
|
160
|
+
# @param args [Array<Object>] Arguments to the activity.
|
161
|
+
# @param schedule_to_close_timeout [Float, nil] Max amount of time the activity can take from first being scheduled
|
162
|
+
# to being completed before it times out. This is inclusive of all retries.
|
163
|
+
# @param schedule_to_start_timeout [Float, nil] Max amount of time the activity can take to be started from first
|
164
|
+
# being scheduled.
|
165
|
+
# @param start_to_close_timeout [Float, nil] Max amount of time a single activity run can take from when it starts
|
166
|
+
# to when it completes. This is per retry.
|
167
|
+
# @param retry_policy [RetryPolicy] How an activity is retried on failure. If unset, a server-defined default is
|
168
|
+
# used. Set maximum attempts to 1 to disable retries.
|
169
|
+
# @param local_retry_threshold [Float, nil] If the activity is retrying and backoff would exceed this value, a timer
|
170
|
+
# is scheduled and the activity is retried after. Otherwise, backoff will happen internally within the task.
|
171
|
+
# Defaults to 1 minute.
|
172
|
+
# @param cancellation [Cancellation] Cancellation to apply to the activity. How cancellation is treated is based on
|
173
|
+
# `cancellation_type`. This defaults to the workflow's cancellation, but may need to be overridden with a
|
174
|
+
# new/detached one if an activity is being run in an `ensure` after workflow cancellation.
|
175
|
+
# @param cancellation_type [ActivityCancellationType] How the activity is treated when it is canceled from the
|
176
|
+
# workflow.
|
177
|
+
# @param activity_id [String, nil] Optional unique identifier for the activity. This is an advanced setting that
|
178
|
+
# should not be set unless users are sure they need to. Contact Temporal before setting this value.
|
179
|
+
#
|
180
|
+
# @return [Object] Result of the activity.
|
181
|
+
# @raise [Error::ActivityError] Activity failed (and retry was disabled or exhausted).
|
182
|
+
# @raise [Error::CanceledError] Activity was canceled before started. When canceled after started (and not
|
183
|
+
# waited-then-swallowed), instead this canceled error is the cause of a {Error::ActivityError}.
|
184
|
+
def self.execute_local_activity(
|
185
|
+
activity,
|
186
|
+
*args,
|
187
|
+
schedule_to_close_timeout: nil,
|
188
|
+
schedule_to_start_timeout: nil,
|
189
|
+
start_to_close_timeout: nil,
|
190
|
+
retry_policy: nil,
|
191
|
+
local_retry_threshold: nil,
|
192
|
+
cancellation: Workflow.cancellation,
|
193
|
+
cancellation_type: ActivityCancellationType::TRY_CANCEL,
|
194
|
+
activity_id: nil
|
195
|
+
)
|
196
|
+
_current.execute_local_activity(
|
197
|
+
activity, *args,
|
198
|
+
schedule_to_close_timeout:, schedule_to_start_timeout:, start_to_close_timeout:,
|
199
|
+
retry_policy:, local_retry_threshold:, cancellation:, cancellation_type:, activity_id:
|
200
|
+
)
|
201
|
+
end
|
202
|
+
|
203
|
+
# Get a handle to an external workflow for canceling and issuing signals.
|
204
|
+
#
|
205
|
+
# @param workflow_id [String] Workflow ID.
|
206
|
+
# @param run_id [String, nil] Optional, specific run ID.
|
207
|
+
#
|
208
|
+
# @return [ExternalWorkflowHandle] External workflow handle.
|
209
|
+
def self.external_workflow_handle(workflow_id, run_id: nil)
|
210
|
+
_current.external_workflow_handle(workflow_id, run_id:)
|
211
|
+
end
|
212
|
+
|
213
|
+
# @return [Boolean] Whether the current code is executing in a workflow.
|
214
|
+
def self.in_workflow?
|
215
|
+
_current_or_nil != nil
|
216
|
+
end
|
217
|
+
|
218
|
+
# @return [Info] Information about the current workflow.
|
219
|
+
def self.info
|
220
|
+
_current.info
|
221
|
+
end
|
222
|
+
|
223
|
+
# @return [Logger] Logger for the workflow. This is a scoped logger that automatically appends workflow details to
|
224
|
+
# every log and takes care not to log during replay.
|
225
|
+
def self.logger
|
226
|
+
_current.logger
|
227
|
+
end
|
228
|
+
|
229
|
+
# @return [Hash{String, Symbol => Object}] Memo for the workflow. This is a read-only view of the memo. To update
|
230
|
+
# the memo, use {upsert_memo}. This always returns the same instance and updates are reflected on the returned
|
231
|
+
# instance, so it is not technically frozen.
|
232
|
+
def self.memo
|
233
|
+
_current.memo
|
234
|
+
end
|
235
|
+
|
236
|
+
# @return [Metric::Meter] Metric meter to create metrics on. This metric meter already contains some
|
237
|
+
# workflow-specific attributes and takes care not to apply metrics during replay.
|
238
|
+
def self.metric_meter
|
239
|
+
_current.metric_meter
|
240
|
+
end
|
241
|
+
|
242
|
+
# @return [Time] Current UTC time for this workflow. This creates and returns a new {::Time} instance every time it
|
243
|
+
# is invoked, it is not the same instance continually mutated.
|
244
|
+
def self.now
|
245
|
+
_current.now
|
246
|
+
end
|
247
|
+
|
248
|
+
# Patch a workflow.
|
249
|
+
#
|
250
|
+
# When called, this will only return true if code should take the newer path which means this is either not
|
251
|
+
# replaying or is replaying and has seen this patch before. Results for successive calls to this function for the
|
252
|
+
# same ID and workflow are memoized. Use {deprecate_patch} when all workflows are done and will never be queried
|
253
|
+
# again. The old code path can be removed at that time too.
|
254
|
+
#
|
255
|
+
# @param patch_id [Symbol, String] Patch ID.
|
256
|
+
# @return [Boolean] True if this should take the newer patch, false if it should take the old path.
|
257
|
+
def self.patched(patch_id)
|
258
|
+
_current.patched(patch_id)
|
259
|
+
end
|
260
|
+
|
261
|
+
# @return [Converters::PayloadConverter] Payload converter for the workflow.
|
262
|
+
def self.payload_converter
|
263
|
+
_current.payload_converter
|
264
|
+
end
|
265
|
+
|
266
|
+
# @return [Hash<String, Definition::Query>] Query handlers for this workflow. This hash is mostly immutable except
|
267
|
+
# for `[]=` (and `store`) which can be used to set a new handler, or can be set with `nil` to remove a handler.
|
268
|
+
# For most use cases, defining a handler as a `workflow_query` method is best.
|
269
|
+
def self.query_handlers
|
270
|
+
_current.query_handlers
|
271
|
+
end
|
272
|
+
|
273
|
+
# @return [Random] Deterministic instance of {::Random} for use in a workflow. This instance should be accessed each
|
274
|
+
# time needed, not stored. This instance may be recreated with a different seed in special cases (e.g. workflow
|
275
|
+
# reset). Do not use any other randomization inside workflow code.
|
276
|
+
def self.random
|
277
|
+
_current.random
|
278
|
+
end
|
279
|
+
|
280
|
+
# @return [SearchAttributes] Search attributes for the workflow. This is a read-only view of the attributes. To
|
281
|
+
# update the attributes, use {upsert_search_attributes}. This always returns the same instance and updates are
|
282
|
+
# reflected on the returned instance, so it is not technically frozen.
|
283
|
+
def self.search_attributes
|
284
|
+
_current.search_attributes
|
285
|
+
end
|
286
|
+
|
287
|
+
# @return [Hash<String, Definition::Signal>] Signal handlers for this workflow. This hash is mostly immutable except
|
288
|
+
# for `[]=` (and `store`) which can be used to set a new handler, or can be set with `nil` to remove a handler.
|
289
|
+
# For most use cases, defining a handler as a `workflow_signal` method is best.
|
290
|
+
def self.signal_handlers
|
291
|
+
_current.signal_handlers
|
292
|
+
end
|
293
|
+
|
294
|
+
# Sleep in a workflow for the given time.
|
295
|
+
#
|
296
|
+
# @param duration [Float, nil] Time to sleep in seconds. `nil` represents infinite, which does not start a timer and
|
297
|
+
# just waits for cancellation. `0` is assumed to be 1 millisecond and still results in a server-side timer. This
|
298
|
+
# value cannot be negative. Since Temporal timers are server-side, timer resolution may not end up as precise as
|
299
|
+
# system timers.
|
300
|
+
# @param summary [String, nil] A simple string identifying this timer that may be visible in UI/CLI. While it can be
|
301
|
+
# normal text, it is best to treat as a timer ID.
|
302
|
+
# @param cancellation [Cancellation] Cancellation for this timer.
|
303
|
+
# @raise [Error::CanceledError] Sleep canceled.
|
304
|
+
def self.sleep(duration, summary: nil, cancellation: Workflow.cancellation)
|
305
|
+
_current.sleep(duration, summary:, cancellation:)
|
306
|
+
end
|
307
|
+
|
308
|
+
# Start a child workflow and return the handle.
|
309
|
+
#
|
310
|
+
# @param workflow [Class<Workflow::Definition>, Symbol, String] Workflow definition class or workflow name.
|
311
|
+
# @param args [Array<Object>] Arguments to the workflow.
|
312
|
+
# @param id [String] Unique identifier for the workflow execution. Defaults to a new UUID from {random}.
|
313
|
+
# @param task_queue [String] Task queue to run the workflow on. Defaults to the current workflow's task queue.
|
314
|
+
# @param cancellation [Cancellation] Cancellation to apply to the child workflow. How cancellation is treated is
|
315
|
+
# based on `cancellation_type`. This defaults to the workflow's cancellation.
|
316
|
+
# @param cancellation_type [ChildWorkflowCancellationType] How the child workflow will react to cancellation.
|
317
|
+
# @param parent_close_policy [ParentClosePolicy] How to handle the child workflow when the parent workflow closes.
|
318
|
+
# @param execution_timeout [Float, nil] Total workflow execution timeout in seconds including retries and continue
|
319
|
+
# as new.
|
320
|
+
# @param run_timeout [Float, nil] Timeout of a single workflow run inseconds.
|
321
|
+
# @param task_timeout [Float, nil] Timeout of a single workflow task in seconds.
|
322
|
+
# @param id_reuse_policy [WorkflowIDReusePolicy] How already-existing IDs are treated.
|
323
|
+
# @param retry_policy [RetryPolicy, nil] Retry policy for the workflow.
|
324
|
+
# @param cron_schedule [String, nil] Cron schedule. Users should use schedules instead of this.
|
325
|
+
# @param memo [Hash{String, Symbol => Object}, nil] Memo for the workflow.
|
326
|
+
# @param search_attributes [SearchAttributes, nil] Search attributes for the workflow.
|
327
|
+
#
|
328
|
+
# @return [ChildWorkflowHandle] Workflow handle to the started workflow.
|
329
|
+
# @raise [Error::WorkflowAlreadyStartedError] Workflow already exists for the ID.
|
330
|
+
# @raise [Error::CanceledError] Starting of the child was canceled.
|
331
|
+
def self.start_child_workflow(
|
332
|
+
workflow,
|
333
|
+
*args,
|
334
|
+
id: random.uuid,
|
335
|
+
task_queue: info.task_queue,
|
336
|
+
cancellation: Workflow.cancellation,
|
337
|
+
cancellation_type: ChildWorkflowCancellationType::WAIT_CANCELLATION_COMPLETED,
|
338
|
+
parent_close_policy: ParentClosePolicy::TERMINATE,
|
339
|
+
execution_timeout: nil,
|
340
|
+
run_timeout: nil,
|
341
|
+
task_timeout: nil,
|
342
|
+
id_reuse_policy: WorkflowIDReusePolicy::ALLOW_DUPLICATE,
|
343
|
+
retry_policy: nil,
|
344
|
+
cron_schedule: nil,
|
345
|
+
memo: nil,
|
346
|
+
search_attributes: nil
|
347
|
+
)
|
348
|
+
_current.start_child_workflow(
|
349
|
+
workflow, *args,
|
350
|
+
id:, task_queue:, cancellation:, cancellation_type:, parent_close_policy:, execution_timeout:, run_timeout:,
|
351
|
+
task_timeout:, id_reuse_policy:, retry_policy:, cron_schedule:, memo:, search_attributes:
|
352
|
+
)
|
353
|
+
end
|
354
|
+
|
355
|
+
# Run the block until the timeout is reached. This is backed by {sleep}. This does not accept cancellation because
|
356
|
+
# it is expected the block within will properly handle/bubble cancellation.
|
357
|
+
#
|
358
|
+
# @param duration [Float, nil] Duration for the timeout. This is backed by {sleep} so see that method for details.
|
359
|
+
# @param exception_class [Class<Exception>] Exception to raise on timeout. Defaults to {::Timeout::Error} like
|
360
|
+
# {::Timeout.timeout}. Note that {::Timeout::Error} is considered a workflow failure exception, not a task failure
|
361
|
+
# exception.
|
362
|
+
# @param message [String] Message to use for timeout exception. Defaults to "execution expired" like
|
363
|
+
# {::Timeout.timeout}.
|
364
|
+
# @param summary [String] Timer summer for the timer created by this timeout. This is backed by {sleep} so see that
|
365
|
+
# method for details.
|
366
|
+
#
|
367
|
+
# @yield Block to run with a timeout.
|
368
|
+
# @return [Object] The result of the block.
|
369
|
+
# @raise [Exception] Upon timeout, raises whichever class is set in `exception_class` with the message of `message`.
|
370
|
+
def self.timeout(
|
371
|
+
duration,
|
372
|
+
exception_class = Timeout::Error,
|
373
|
+
message = 'execution expired',
|
374
|
+
summary: 'Timeout timer',
|
375
|
+
&
|
376
|
+
)
|
377
|
+
_current.timeout(duration, exception_class, message, summary:, &)
|
378
|
+
end
|
379
|
+
|
380
|
+
# @return [Hash<String, Definition::Update>] Update handlers for this workflow. This hash is mostly immutable except
|
381
|
+
# for `[]=` (and `store`) which can be used to set a new handler, or can be set with `nil` to remove a handler.
|
382
|
+
# For most use cases, defining a handler as a `workflow_update` method is best.
|
383
|
+
def self.update_handlers
|
384
|
+
_current.update_handlers
|
385
|
+
end
|
386
|
+
|
387
|
+
# Issue updates to the workflow memo.
|
388
|
+
#
|
389
|
+
# @param hash [Hash{String, Symbol => Object, nil}] Updates to apply. Value can be `nil` to effectively remove the
|
390
|
+
# memo value.
|
391
|
+
def self.upsert_memo(hash)
|
392
|
+
_current.upsert_memo(hash)
|
393
|
+
end
|
394
|
+
|
395
|
+
# Issue updates to the workflow search attributes.
|
396
|
+
#
|
397
|
+
# @param updates [Array<SearchAttributes::Update>] Updates to apply. Note these are {SearchAttributes::Update}
|
398
|
+
# objects which are created via {SearchAttributes::Key.value_set} and {SearchAttributes::Key.value_unset} methods.
|
399
|
+
def self.upsert_search_attributes(*updates)
|
400
|
+
_current.upsert_search_attributes(*updates)
|
401
|
+
end
|
402
|
+
|
403
|
+
# Wait for the given block to return a "truthy" value (i.e. any value other than `false` or `nil`). The block must
|
404
|
+
# be side-effect free since it may be invoked frequently during event loop iteration. To timeout a wait, {timeout}
|
405
|
+
# can be used. This cannot be used in side-effect-free contexts such as `initialize`, queries, or update validators.
|
406
|
+
#
|
407
|
+
# This is very commonly used to wait on a value to be set by a handler, e.g.
|
408
|
+
# `Temporalio::Workflow.wait_condition { @some_value }`. Special care was taken to only wake up a single wait
|
409
|
+
# condition when it evaluates to true. Therefore if multiple wait conditions are waiting on the same thing, only one
|
410
|
+
# is awoken at a time, which means the code immediately following that wait condition can change the variable before
|
411
|
+
# other wait conditions are evaluated. This is a useful property for building mutexes/semaphores.
|
412
|
+
#
|
413
|
+
# @param cancellation [Cancellation, nil] Cancellation to cancel the wait. This defaults to the workflow's
|
414
|
+
# cancellation.
|
415
|
+
# @yield Block that is run many times to test for truthiness.
|
416
|
+
# @yieldreturn [Object] Value to check whether truthy or falsy.
|
417
|
+
#
|
418
|
+
# @return [Object] Truthy value returned from the block.
|
419
|
+
# @raise [Error::CanceledError] Wait was canceled.
|
420
|
+
def self.wait_condition(cancellation: Workflow.cancellation, &)
|
421
|
+
raise 'Block required' unless block_given?
|
422
|
+
|
423
|
+
_current.wait_condition(cancellation:, &)
|
424
|
+
end
|
425
|
+
|
426
|
+
# @!visibility private
|
427
|
+
def self._current
|
428
|
+
current = _current_or_nil
|
429
|
+
raise Error, 'Not in workflow environment' if current.nil?
|
430
|
+
|
431
|
+
current
|
432
|
+
end
|
433
|
+
|
434
|
+
# @!visibility private
|
435
|
+
def self._current_or_nil
|
436
|
+
# We choose to use Fiber.scheduler instead of Fiber.current_scheduler here because the constructor of the class is
|
437
|
+
# not scheduled on this scheduler and so current_scheduler is nil during class construction.
|
438
|
+
sched = Fiber.scheduler
|
439
|
+
return sched.context if sched.is_a?(Internal::Worker::WorkflowInstance::Scheduler)
|
440
|
+
|
441
|
+
nil
|
442
|
+
end
|
443
|
+
|
444
|
+
# Unsafe module contains only-in-workflow methods that are considered unsafe. These should not be used unless the
|
445
|
+
# consequences are understood.
|
446
|
+
module Unsafe
|
447
|
+
# @return [Boolean] True if the workflow is replaying, false otherwise. Most code should not check this value.
|
448
|
+
def self.replaying?
|
449
|
+
Workflow._current.replaying?
|
450
|
+
end
|
451
|
+
|
452
|
+
# Run a block of code with illegal call tracing disabled. Users should be cautious about using this as it can
|
453
|
+
# often signify unsafe code.
|
454
|
+
#
|
455
|
+
# @yield Block to run with call tracing disabled
|
456
|
+
#
|
457
|
+
# @return [Object] Result of the block.
|
458
|
+
def self.illegal_call_tracing_disabled(&)
|
459
|
+
Workflow._current.illegal_call_tracing_disabled(&)
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
# Error that is raised by a workflow out of the primary workflow method to issue a continue-as-new.
|
464
|
+
class ContinueAsNewError < Error
|
465
|
+
attr_accessor :args, :workflow, :task_queue, :run_timeout, :task_timeout,
|
466
|
+
:retry_policy, :memo, :search_attributes, :headers
|
467
|
+
|
468
|
+
# Create a continue as new error.
|
469
|
+
#
|
470
|
+
# @param args [Array<Object>] Arguments for the new workflow.
|
471
|
+
# @param workflow [Class<Workflow::Definition>, String, Symbol, nil] Workflow definition class or workflow name.
|
472
|
+
# If unset/nil, the current workflow is used.
|
473
|
+
# @param task_queue [String, nil] Task queue for the workflow. If unset/nil, the current workflow task queue is
|
474
|
+
# used.
|
475
|
+
# @param run_timeout [Float, nil] Timeout of a single workflow run in seconds. The default is _not_ carried over
|
476
|
+
# from the current workflow.
|
477
|
+
# @param task_timeout [Float, nil] Timeout of a single workflow task in seconds. The default is _not_ carried over
|
478
|
+
# from the current workflow.
|
479
|
+
# @param retry_policy [RetryPolicy, nil] Retry policy for the workflow. If unset/nil, the current workflow retry
|
480
|
+
# policy is used.
|
481
|
+
# @param memo [Hash{String, Symbol => Object}, nil] Memo for the workflow. If unset/nil, the current workflow memo
|
482
|
+
# is used.
|
483
|
+
# @param search_attributes [SearchAttributes, nil] Search attributes for the workflow. If unset/nil, the current
|
484
|
+
# workflow search attributes are used.
|
485
|
+
# @param headers [Hash<String, Object>] Headers for the workflow. The default is _not_ carried over from the
|
486
|
+
# current workflow.
|
487
|
+
def initialize(
|
488
|
+
*args,
|
489
|
+
workflow: nil,
|
490
|
+
task_queue: nil,
|
491
|
+
run_timeout: nil,
|
492
|
+
task_timeout: nil,
|
493
|
+
retry_policy: nil,
|
494
|
+
memo: nil,
|
495
|
+
search_attributes: nil,
|
496
|
+
headers: {}
|
497
|
+
)
|
498
|
+
super('Continue as new')
|
499
|
+
@args = args
|
500
|
+
@workflow = workflow
|
501
|
+
@task_queue = task_queue
|
502
|
+
@run_timeout = run_timeout
|
503
|
+
@task_timeout = task_timeout
|
504
|
+
@retry_policy = retry_policy
|
505
|
+
@memo = memo
|
506
|
+
@search_attributes = search_attributes
|
507
|
+
@headers = headers
|
508
|
+
Workflow._current.initialize_continue_as_new_error(self)
|
509
|
+
end
|
510
|
+
end
|
511
|
+
|
512
|
+
# Error raised when a workflow does something with a side effect in an improper context. In `initialize`, query
|
513
|
+
# handlers, and update validators, a workflow cannot do anything that would generate a command (e.g. starting an
|
514
|
+
# activity) or anything that could wait (e.g. scheduling a fiber, running a future, or using a wait condition).
|
515
|
+
class InvalidWorkflowStateError < Error; end
|
516
|
+
|
517
|
+
# Error raised when a workflow does something potentially non-deterministic such as making an illegal call. Note,
|
518
|
+
# non-deterministic errors during replay do not raise an error that can be caught, those happen internally. But this
|
519
|
+
# error can still be used with configuring workflow failure exception types to change non-deterministic errors from
|
520
|
+
# task failures to workflow failures.
|
521
|
+
class NondeterminismError < Error; end
|
522
|
+
end
|
523
|
+
end
|
data/lib/temporalio.rb
CHANGED
data/temporalio.gemspec
CHANGED
@@ -11,12 +11,12 @@ Gem::Specification.new do |spec|
|
|
11
11
|
spec.summary = 'Temporal.io Ruby SDK'
|
12
12
|
spec.homepage = 'https://github.com/temporalio/sdk-ruby'
|
13
13
|
spec.license = 'MIT'
|
14
|
-
spec.required_ruby_version = '>= 3.1.0'
|
15
14
|
|
16
15
|
spec.metadata['homepage_uri'] = spec.homepage
|
17
16
|
spec.metadata['source_code_uri'] = 'https://github.com/temporalio/sdk-ruby'
|
18
17
|
|
19
|
-
spec.files = Dir['lib/**/*.rb', 'LICENSE', 'README.md', 'Cargo.*',
|
18
|
+
spec.files = Dir['lib/**/*.rb', 'LICENSE', 'README.md', 'Cargo.*',
|
19
|
+
'temporalio.gemspec', 'Gemfile', 'Rakefile', '.yardopts']
|
20
20
|
|
21
21
|
spec.bindir = 'exe'
|
22
22
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|