temporalio 0.4.0 → 0.5.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.
- checksums.yaml +4 -4
- data/.yardopts +1 -1
- data/Cargo.lock +679 -437
- data/Cargo.toml +5 -5
- data/README.md +98 -34
- data/ext/Cargo.toml +3 -3
- data/lib/temporalio/activity/cancellation_details.rb +58 -0
- data/lib/temporalio/activity/context.rb +10 -1
- data/lib/temporalio/activity/definition.rb +41 -3
- data/lib/temporalio/activity/info.rb +25 -4
- data/lib/temporalio/activity.rb +2 -0
- data/lib/temporalio/api/activity/v1/message.rb +1 -1
- data/lib/temporalio/api/batch/v1/message.rb +4 -2
- data/lib/temporalio/api/cloud/account/v1/message.rb +1 -1
- data/lib/temporalio/api/cloud/cloudservice/v1/request_response.rb +11 -2
- data/lib/temporalio/api/cloud/cloudservice/v1/service.rb +2 -2
- data/lib/temporalio/api/cloud/identity/v1/message.rb +7 -2
- data/lib/temporalio/api/cloud/namespace/v1/message.rb +6 -2
- data/lib/temporalio/api/cloud/nexus/v1/message.rb +3 -2
- data/lib/temporalio/api/cloud/operation/v1/message.rb +1 -1
- data/lib/temporalio/api/cloud/region/v1/message.rb +1 -1
- data/lib/temporalio/api/cloud/resource/v1/message.rb +1 -1
- data/lib/temporalio/api/cloud/sink/v1/message.rb +1 -1
- data/lib/temporalio/api/cloud/usage/v1/message.rb +1 -1
- data/lib/temporalio/api/command/v1/message.rb +2 -2
- data/lib/temporalio/api/common/v1/grpc_status.rb +1 -1
- data/lib/temporalio/api/common/v1/message.rb +3 -2
- data/lib/temporalio/api/deployment/v1/message.rb +3 -2
- data/lib/temporalio/api/enums/v1/batch_operation.rb +1 -1
- data/lib/temporalio/api/enums/v1/command_type.rb +1 -1
- data/lib/temporalio/api/enums/v1/common.rb +5 -2
- data/lib/temporalio/api/enums/v1/deployment.rb +3 -2
- data/lib/temporalio/api/enums/v1/event_type.rb +2 -2
- data/lib/temporalio/api/enums/v1/failed_cause.rb +2 -2
- data/lib/temporalio/api/enums/v1/namespace.rb +1 -1
- data/lib/temporalio/api/enums/v1/nexus.rb +1 -1
- data/lib/temporalio/api/enums/v1/query.rb +1 -1
- data/lib/temporalio/api/enums/v1/reset.rb +1 -1
- data/lib/temporalio/api/enums/v1/schedule.rb +1 -1
- data/lib/temporalio/api/enums/v1/task_queue.rb +1 -1
- data/lib/temporalio/api/enums/v1/update.rb +1 -1
- data/lib/temporalio/api/enums/v1/workflow.rb +2 -2
- data/lib/temporalio/api/errordetails/v1/message.rb +1 -1
- data/lib/temporalio/api/export/v1/message.rb +1 -1
- data/lib/temporalio/api/failure/v1/message.rb +3 -2
- data/lib/temporalio/api/filter/v1/message.rb +1 -1
- data/lib/temporalio/api/history/v1/message.rb +4 -2
- data/lib/temporalio/api/namespace/v1/message.rb +1 -1
- data/lib/temporalio/api/nexus/v1/message.rb +2 -2
- data/lib/temporalio/api/operatorservice/v1/request_response.rb +1 -1
- data/lib/temporalio/api/operatorservice/v1/service.rb +1 -1
- data/lib/temporalio/api/payload_visitor.rb +87 -0
- data/lib/temporalio/api/protocol/v1/message.rb +1 -1
- data/lib/temporalio/api/query/v1/message.rb +1 -1
- data/lib/temporalio/api/replication/v1/message.rb +1 -1
- data/lib/temporalio/api/rules/v1/message.rb +27 -0
- data/lib/temporalio/api/schedule/v1/message.rb +2 -2
- data/lib/temporalio/api/sdk/v1/enhanced_stack_trace.rb +1 -1
- data/lib/temporalio/api/sdk/v1/task_complete_metadata.rb +1 -1
- data/lib/temporalio/api/sdk/v1/user_metadata.rb +1 -1
- data/lib/temporalio/api/sdk/v1/workflow_metadata.rb +1 -1
- data/lib/temporalio/api/taskqueue/v1/message.rb +2 -2
- data/lib/temporalio/api/testservice/v1/request_response.rb +1 -1
- data/lib/temporalio/api/testservice/v1/service.rb +1 -1
- data/lib/temporalio/api/update/v1/message.rb +1 -1
- data/lib/temporalio/api/version/v1/message.rb +1 -1
- data/lib/temporalio/api/worker/v1/message.rb +30 -0
- data/lib/temporalio/api/workflow/v1/message.rb +14 -2
- data/lib/temporalio/api/workflowservice/v1/request_response.rb +19 -2
- data/lib/temporalio/api/workflowservice/v1/service.rb +2 -2
- data/lib/temporalio/client/async_activity_handle.rb +12 -4
- data/lib/temporalio/client/connection/cloud_service.rb +60 -0
- data/lib/temporalio/client/connection/workflow_service.rb +105 -0
- data/lib/temporalio/client/interceptor.rb +25 -7
- data/lib/temporalio/client/schedule.rb +10 -2
- data/lib/temporalio/client/with_start_workflow_operation.rb +9 -1
- data/lib/temporalio/client/workflow_handle.rb +50 -10
- data/lib/temporalio/client/workflow_update_handle.rb +9 -3
- data/lib/temporalio/client.rb +110 -6
- data/lib/temporalio/common_enums.rb +14 -0
- data/lib/temporalio/contrib/open_telemetry.rb +13 -9
- data/lib/temporalio/converters/data_converter.rb +18 -8
- data/lib/temporalio/converters/failure_converter.rb +6 -3
- data/lib/temporalio/converters/payload_converter/binary_null.rb +2 -2
- data/lib/temporalio/converters/payload_converter/binary_plain.rb +2 -2
- data/lib/temporalio/converters/payload_converter/binary_protobuf.rb +2 -2
- data/lib/temporalio/converters/payload_converter/composite.rb +6 -4
- data/lib/temporalio/converters/payload_converter/encoding.rb +4 -2
- data/lib/temporalio/converters/payload_converter/json_plain.rb +2 -2
- data/lib/temporalio/converters/payload_converter/json_protobuf.rb +2 -2
- data/lib/temporalio/converters/payload_converter.rb +16 -6
- data/lib/temporalio/error/failure.rb +19 -1
- data/lib/temporalio/error.rb +1 -1
- data/lib/temporalio/internal/bridge/api/activity_result/activity_result.rb +1 -1
- data/lib/temporalio/internal/bridge/api/activity_task/activity_task.rb +3 -2
- data/lib/temporalio/internal/bridge/api/child_workflow/child_workflow.rb +1 -1
- data/lib/temporalio/internal/bridge/api/common/common.rb +1 -1
- data/lib/temporalio/internal/bridge/api/core_interface.rb +1 -1
- data/lib/temporalio/internal/bridge/api/external_data/external_data.rb +1 -1
- data/lib/temporalio/internal/bridge/api/nexus/nexus.rb +3 -2
- data/lib/temporalio/internal/bridge/api/workflow_activation/workflow_activation.rb +2 -2
- data/lib/temporalio/internal/bridge/api/workflow_commands/workflow_commands.rb +3 -2
- data/lib/temporalio/internal/bridge/api/workflow_completion/workflow_completion.rb +1 -1
- data/lib/temporalio/internal/bridge/worker.rb +28 -4
- data/lib/temporalio/internal/bridge.rb +1 -1
- data/lib/temporalio/internal/client/implementation.rb +60 -52
- data/lib/temporalio/internal/proto_utils.rb +4 -4
- data/lib/temporalio/internal/worker/activity_worker.rb +93 -20
- data/lib/temporalio/internal/worker/workflow_instance/child_workflow_handle.rb +8 -6
- data/lib/temporalio/internal/worker/workflow_instance/context.rb +65 -24
- data/lib/temporalio/internal/worker/workflow_instance/details.rb +5 -2
- data/lib/temporalio/internal/worker/workflow_instance/external_workflow_handle.rb +2 -2
- data/lib/temporalio/internal/worker/workflow_instance/illegal_call_tracer.rb +64 -18
- data/lib/temporalio/internal/worker/workflow_instance/outbound_implementation.rb +28 -14
- data/lib/temporalio/internal/worker/workflow_instance.rb +58 -23
- data/lib/temporalio/internal/worker/workflow_worker.rb +16 -6
- data/lib/temporalio/priority.rb +59 -0
- data/lib/temporalio/testing/activity_environment.rb +17 -2
- data/lib/temporalio/testing/workflow_environment.rb +3 -3
- data/lib/temporalio/version.rb +1 -1
- data/lib/temporalio/versioning_override.rb +56 -0
- data/lib/temporalio/worker/deployment_options.rb +45 -0
- data/lib/temporalio/worker/illegal_workflow_call_validator.rb +64 -0
- data/lib/temporalio/worker/interceptor.rb +13 -1
- data/lib/temporalio/worker/poller_behavior.rb +61 -0
- data/lib/temporalio/worker/thread_pool.rb +1 -1
- data/lib/temporalio/worker/workflow_executor/thread_pool.rb +2 -1
- data/lib/temporalio/worker/workflow_replayer.rb +12 -13
- data/lib/temporalio/worker.rb +63 -27
- data/lib/temporalio/worker_deployment_version.rb +67 -0
- data/lib/temporalio/workflow/child_workflow_handle.rb +10 -2
- data/lib/temporalio/workflow/definition.rb +183 -33
- data/lib/temporalio/workflow/external_workflow_handle.rb +3 -1
- data/lib/temporalio/workflow/info.rb +4 -1
- data/lib/temporalio/workflow.rb +61 -9
- data/lib/temporalio.rb +1 -0
- data/temporalio.gemspec +1 -0
- metadata +12 -3
@@ -56,7 +56,8 @@ module Temporalio
|
|
56
56
|
raise ArgumentError, 'Activity must have schedule_to_close_timeout or start_to_close_timeout'
|
57
57
|
end
|
58
58
|
|
59
|
-
execute_activity_with_local_backoffs(local: false, cancellation: input.cancellation
|
59
|
+
execute_activity_with_local_backoffs(local: false, cancellation: input.cancellation,
|
60
|
+
result_hint: input.result_hint) do
|
60
61
|
seq = (@activity_counter += 1)
|
61
62
|
@instance.add_command(
|
62
63
|
Bridge::Api::WorkflowCommands::WorkflowCommand.new(
|
@@ -66,14 +67,17 @@ module Temporalio
|
|
66
67
|
activity_type: input.activity,
|
67
68
|
task_queue: input.task_queue,
|
68
69
|
headers: ProtoUtils.headers_to_proto_hash(input.headers, @instance.payload_converter),
|
69
|
-
arguments: ProtoUtils.convert_to_payload_array(
|
70
|
+
arguments: ProtoUtils.convert_to_payload_array(
|
71
|
+
@instance.payload_converter, input.args, hints: input.arg_hints
|
72
|
+
),
|
70
73
|
schedule_to_close_timeout: ProtoUtils.seconds_to_duration(input.schedule_to_close_timeout),
|
71
74
|
schedule_to_start_timeout: ProtoUtils.seconds_to_duration(input.schedule_to_start_timeout),
|
72
75
|
start_to_close_timeout: ProtoUtils.seconds_to_duration(input.start_to_close_timeout),
|
73
76
|
heartbeat_timeout: ProtoUtils.seconds_to_duration(input.heartbeat_timeout),
|
74
77
|
retry_policy: input.retry_policy&._to_proto,
|
75
78
|
cancellation_type: input.cancellation_type,
|
76
|
-
do_not_eagerly_execute: input.disable_eager_execution
|
79
|
+
do_not_eagerly_execute: input.disable_eager_execution,
|
80
|
+
priority: input.priority._to_proto
|
77
81
|
),
|
78
82
|
user_metadata: ProtoUtils.to_user_metadata(input.summary, nil, @instance.payload_converter)
|
79
83
|
)
|
@@ -87,7 +91,10 @@ module Temporalio
|
|
87
91
|
raise ArgumentError, 'Activity must have schedule_to_close_timeout or start_to_close_timeout'
|
88
92
|
end
|
89
93
|
|
90
|
-
|
94
|
+
@instance.assert_valid_local_activity.call(input.activity)
|
95
|
+
|
96
|
+
execute_activity_with_local_backoffs(local: true, cancellation: input.cancellation,
|
97
|
+
result_hint: input.result_hint) do |do_backoff|
|
91
98
|
seq = (@activity_counter += 1)
|
92
99
|
@instance.add_command(
|
93
100
|
Bridge::Api::WorkflowCommands::WorkflowCommand.new(
|
@@ -96,7 +103,9 @@ module Temporalio
|
|
96
103
|
activity_id: input.activity_id || seq.to_s,
|
97
104
|
activity_type: input.activity,
|
98
105
|
headers: ProtoUtils.headers_to_proto_hash(input.headers, @instance.payload_converter),
|
99
|
-
arguments: ProtoUtils.convert_to_payload_array(
|
106
|
+
arguments: ProtoUtils.convert_to_payload_array(
|
107
|
+
@instance.payload_converter, input.args, hints: input.arg_hints
|
108
|
+
),
|
100
109
|
schedule_to_close_timeout: ProtoUtils.seconds_to_duration(input.schedule_to_close_timeout),
|
101
110
|
schedule_to_start_timeout: ProtoUtils.seconds_to_duration(input.schedule_to_start_timeout),
|
102
111
|
start_to_close_timeout: ProtoUtils.seconds_to_duration(input.start_to_close_timeout),
|
@@ -112,7 +121,7 @@ module Temporalio
|
|
112
121
|
end
|
113
122
|
end
|
114
123
|
|
115
|
-
def execute_activity_with_local_backoffs(local:, cancellation:, &)
|
124
|
+
def execute_activity_with_local_backoffs(local:, cancellation:, result_hint:, &)
|
116
125
|
# We do not even want to schedule if the cancellation is already cancelled. We choose to use canceled
|
117
126
|
# failure instead of wrapping in activity failure which is similar to what other SDKs do, with the accepted
|
118
127
|
# tradeoff that it makes rescue more difficult (hence the presence of Error.canceled? helper).
|
@@ -121,7 +130,7 @@ module Temporalio
|
|
121
130
|
# This has to be done in a loop for local activity backoff
|
122
131
|
last_local_backoff = nil
|
123
132
|
loop do
|
124
|
-
result = execute_activity_once(local:, cancellation:, last_local_backoff:, &)
|
133
|
+
result = execute_activity_once(local:, cancellation:, last_local_backoff:, result_hint:, &)
|
125
134
|
return result unless result.is_a?(Bridge::Api::ActivityResult::DoBackoff)
|
126
135
|
|
127
136
|
# @type var result: untyped
|
@@ -133,7 +142,7 @@ module Temporalio
|
|
133
142
|
end
|
134
143
|
|
135
144
|
# If this doesn't raise, it returns success | DoBackoff
|
136
|
-
def execute_activity_once(local:, cancellation:, last_local_backoff:, &)
|
145
|
+
def execute_activity_once(local:, cancellation:, last_local_backoff:, result_hint:, &)
|
137
146
|
# Add to pending activities (removed by the resolver)
|
138
147
|
seq = yield last_local_backoff
|
139
148
|
@instance.pending_activities[seq] = Fiber.current
|
@@ -166,7 +175,7 @@ module Temporalio
|
|
166
175
|
|
167
176
|
case resolution.status
|
168
177
|
when :completed
|
169
|
-
@instance.payload_converter.from_payload(resolution.completed.result)
|
178
|
+
@instance.payload_converter.from_payload(resolution.completed.result, hint: result_hint)
|
170
179
|
when :failed
|
171
180
|
raise @instance.failure_converter.from_failure(resolution.failed.failure, @instance.payload_converter)
|
172
181
|
when :cancelled
|
@@ -190,6 +199,7 @@ module Temporalio
|
|
190
199
|
signal: input.signal,
|
191
200
|
args: input.args,
|
192
201
|
cancellation: input.cancellation,
|
202
|
+
arg_hints: input.arg_hints,
|
193
203
|
headers: input.headers
|
194
204
|
)
|
195
205
|
end
|
@@ -202,11 +212,12 @@ module Temporalio
|
|
202
212
|
signal: input.signal,
|
203
213
|
args: input.args,
|
204
214
|
cancellation: input.cancellation,
|
215
|
+
arg_hints: input.arg_hints,
|
205
216
|
headers: input.headers
|
206
217
|
)
|
207
218
|
end
|
208
219
|
|
209
|
-
def _signal_external_workflow(id:, run_id:, child:, signal:, args:, cancellation:, headers:)
|
220
|
+
def _signal_external_workflow(id:, run_id:, child:, signal:, args:, cancellation:, arg_hints:, headers:)
|
210
221
|
raise Error::CanceledError, 'Signal canceled before scheduled' if cancellation.canceled?
|
211
222
|
|
212
223
|
# Add command
|
@@ -214,7 +225,7 @@ module Temporalio
|
|
214
225
|
cmd = Bridge::Api::WorkflowCommands::SignalExternalWorkflowExecution.new(
|
215
226
|
seq:,
|
216
227
|
signal_name: signal,
|
217
|
-
args: ProtoUtils.convert_to_payload_array(@instance.payload_converter, args),
|
228
|
+
args: ProtoUtils.convert_to_payload_array(@instance.payload_converter, args, hints: arg_hints),
|
218
229
|
headers: ProtoUtils.headers_to_proto_hash(headers, @instance.payload_converter)
|
219
230
|
)
|
220
231
|
if child
|
@@ -324,7 +335,8 @@ module Temporalio
|
|
324
335
|
workflow_id: input.id,
|
325
336
|
workflow_type: input.workflow,
|
326
337
|
task_queue: input.task_queue,
|
327
|
-
input: ProtoUtils.convert_to_payload_array(@instance.payload_converter, input.args
|
338
|
+
input: ProtoUtils.convert_to_payload_array(@instance.payload_converter, input.args,
|
339
|
+
hints: input.arg_hints),
|
328
340
|
workflow_execution_timeout: ProtoUtils.seconds_to_duration(input.execution_timeout),
|
329
341
|
workflow_run_timeout: ProtoUtils.seconds_to_duration(input.run_timeout),
|
330
342
|
workflow_task_timeout: ProtoUtils.seconds_to_duration(input.task_timeout),
|
@@ -335,7 +347,8 @@ module Temporalio
|
|
335
347
|
headers: ProtoUtils.headers_to_proto_hash(input.headers, @instance.payload_converter),
|
336
348
|
memo: ProtoUtils.memo_to_proto_hash(input.memo, @instance.payload_converter),
|
337
349
|
search_attributes: input.search_attributes&._to_proto_hash,
|
338
|
-
cancellation_type: input.cancellation_type
|
350
|
+
cancellation_type: input.cancellation_type,
|
351
|
+
priority: input.priority._to_proto
|
339
352
|
),
|
340
353
|
user_metadata: ProtoUtils.to_user_metadata(
|
341
354
|
input.static_summary, input.static_details, @instance.payload_converter
|
@@ -370,7 +383,8 @@ module Temporalio
|
|
370
383
|
first_execution_run_id: resolution.succeeded.run_id,
|
371
384
|
instance: @instance,
|
372
385
|
cancellation: input.cancellation,
|
373
|
-
cancel_callback_key
|
386
|
+
cancel_callback_key:,
|
387
|
+
result_hint: input.result_hint
|
374
388
|
)
|
375
389
|
@instance.pending_child_workflows[seq] = handle
|
376
390
|
handle
|
@@ -24,6 +24,7 @@ require 'temporalio/internal/worker/workflow_instance/scheduler'
|
|
24
24
|
require 'temporalio/retry_policy'
|
25
25
|
require 'temporalio/scoped_logger'
|
26
26
|
require 'temporalio/worker/interceptor'
|
27
|
+
require 'temporalio/worker_deployment_version'
|
27
28
|
require 'temporalio/workflow/info'
|
28
29
|
require 'temporalio/workflow/update_info'
|
29
30
|
require 'timeout'
|
@@ -54,9 +55,9 @@ module Temporalio
|
|
54
55
|
attr_reader :context, :logger, :info, :scheduler, :disable_eager_activity_execution, :pending_activities,
|
55
56
|
:pending_timers, :pending_child_workflow_starts, :pending_child_workflows,
|
56
57
|
:pending_external_signals, :pending_external_cancels, :in_progress_handlers, :payload_converter,
|
57
|
-
:failure_converter, :cancellation, :continue_as_new_suggested, :
|
58
|
-
:current_history_size, :replaying, :random,
|
59
|
-
:context_frozen
|
58
|
+
:failure_converter, :cancellation, :continue_as_new_suggested, :current_deployment_version,
|
59
|
+
:current_history_length, :current_history_size, :replaying, :random,
|
60
|
+
:signal_handlers, :query_handlers, :update_handlers, :context_frozen, :assert_valid_local_activity
|
60
61
|
attr_accessor :io_enabled, :current_details
|
61
62
|
|
62
63
|
def initialize(details)
|
@@ -90,7 +91,7 @@ module Temporalio
|
|
90
91
|
@current_history_length = 0
|
91
92
|
@current_history_size = 0
|
92
93
|
@replaying = false
|
93
|
-
@
|
94
|
+
@workflow_failure_exception_types = details.workflow_failure_exception_types
|
94
95
|
@signal_handlers = HandlerHash.new(
|
95
96
|
details.definition.signals,
|
96
97
|
Workflow::Definition::Signal
|
@@ -107,6 +108,12 @@ module Temporalio
|
|
107
108
|
end
|
108
109
|
@query_handlers = HandlerHash.new(details.definition.queries, Workflow::Definition::Query)
|
109
110
|
@update_handlers = HandlerHash.new(details.definition.updates, Workflow::Definition::Update)
|
111
|
+
@definition_options = Workflow::DefinitionOptions.new(
|
112
|
+
failure_exception_types: details.definition.failure_exception_types,
|
113
|
+
versioning_behavior: details.definition.versioning_behavior
|
114
|
+
)
|
115
|
+
|
116
|
+
@assert_valid_local_activity = details.assert_valid_local_activity
|
110
117
|
|
111
118
|
# Create all things needed from initial job
|
112
119
|
@init_job = details.initial_activation.jobs.find { |j| !j.initialize_workflow.nil? }&.initialize_workflow
|
@@ -133,6 +140,7 @@ module Temporalio
|
|
133
140
|
workflow_id: @init_job.parent_workflow_info.workflow_id
|
134
141
|
)
|
135
142
|
end,
|
143
|
+
priority: Priority._from_proto(@init_job.priority),
|
136
144
|
retry_policy: (RetryPolicy._from_proto(@init_job.retry_policy) if @init_job.retry_policy),
|
137
145
|
root: if @init_job.root_workflow
|
138
146
|
Workflow::Info::RootInfo.new(
|
@@ -142,7 +150,7 @@ module Temporalio
|
|
142
150
|
end,
|
143
151
|
run_id: details.initial_activation.run_id,
|
144
152
|
run_timeout: ProtoUtils.duration_to_seconds(@init_job.workflow_run_timeout),
|
145
|
-
start_time: ProtoUtils.timestamp_to_time(
|
153
|
+
start_time: ProtoUtils.timestamp_to_time(@init_job.start_time) || raise,
|
146
154
|
task_queue: details.task_queue,
|
147
155
|
task_timeout: ProtoUtils.duration_to_seconds(@init_job.workflow_task_timeout) || raise,
|
148
156
|
workflow_id: @init_job.workflow_id,
|
@@ -238,6 +246,9 @@ module Temporalio
|
|
238
246
|
@commands = []
|
239
247
|
@current_activation_error = nil
|
240
248
|
@continue_as_new_suggested = activation.continue_as_new_suggested
|
249
|
+
@current_deployment_version = WorkerDeploymentVersion._from_bridge(
|
250
|
+
activation.deployment_version_for_current_task
|
251
|
+
)
|
241
252
|
@current_history_length = activation.history_length
|
242
253
|
@current_history_size = activation.history_size_bytes
|
243
254
|
@replaying = activation.is_replaying
|
@@ -287,7 +298,9 @@ module Temporalio
|
|
287
298
|
else
|
288
299
|
Bridge::Api::WorkflowCompletion::WorkflowActivationCompletion.new(
|
289
300
|
run_id: activation.run_id,
|
290
|
-
successful: Bridge::Api::WorkflowCompletion::Success.new(
|
301
|
+
successful: Bridge::Api::WorkflowCompletion::Success.new(
|
302
|
+
commands: @commands, versioning_behavior: @definition_options.versioning_behavior
|
303
|
+
)
|
291
304
|
)
|
292
305
|
end
|
293
306
|
ensure
|
@@ -299,7 +312,8 @@ module Temporalio
|
|
299
312
|
# Convert workflow arguments
|
300
313
|
@workflow_arguments = convert_args(payload_array: @init_job.arguments,
|
301
314
|
method_name: :execute,
|
302
|
-
raw_args: @definition.raw_args
|
315
|
+
raw_args: @definition.raw_args,
|
316
|
+
arg_hints: @definition.arg_hints)
|
303
317
|
|
304
318
|
# Initialize interceptors
|
305
319
|
@inbound = @interceptors.reverse_each.reduce(InboundImplementation.new(self)) do |acc, int|
|
@@ -308,11 +322,24 @@ module Temporalio
|
|
308
322
|
@inbound.init(OutboundImplementation.new(self))
|
309
323
|
|
310
324
|
# Create the user instance
|
311
|
-
if @definition.init
|
312
|
-
|
313
|
-
|
314
|
-
|
325
|
+
instance = if @definition.init
|
326
|
+
@definition.workflow_class.new(*@workflow_arguments)
|
327
|
+
else
|
328
|
+
@definition.workflow_class.new
|
329
|
+
end
|
330
|
+
|
331
|
+
# Run Dynamic config getter
|
332
|
+
if @definition.dynamic_options_method
|
333
|
+
dynamic_options = instance.send(@definition.dynamic_options_method)
|
334
|
+
if dynamic_options&.versioning_behavior
|
335
|
+
@definition_options.versioning_behavior = dynamic_options.versioning_behavior
|
336
|
+
end
|
337
|
+
if dynamic_options&.failure_exception_types
|
338
|
+
@definition_options.failure_exception_types = dynamic_options.failure_exception_types
|
339
|
+
end
|
315
340
|
end
|
341
|
+
|
342
|
+
instance
|
316
343
|
end
|
317
344
|
|
318
345
|
def apply(job)
|
@@ -394,6 +421,7 @@ module Temporalio
|
|
394
421
|
end
|
395
422
|
|
396
423
|
def apply_query(job)
|
424
|
+
result_hint = nil
|
397
425
|
schedule do
|
398
426
|
# If it's a built-in, run it without interceptors, otherwise do normal behavior
|
399
427
|
result = if job.query_type == '__stack_trace'
|
@@ -411,6 +439,7 @@ module Temporalio
|
|
411
439
|
raise "Query handler for #{job.query_type} expected but not found, " \
|
412
440
|
"known queries: [#{query_handlers.keys.compact.sort.join(', ')}]"
|
413
441
|
end
|
442
|
+
result_hint = defn.result_hint
|
414
443
|
|
415
444
|
with_context_frozen do
|
416
445
|
@inbound.handle_query(
|
@@ -434,7 +463,7 @@ module Temporalio
|
|
434
463
|
respond_to_query: Bridge::Api::WorkflowCommands::QueryResult.new(
|
435
464
|
query_id: job.query_id,
|
436
465
|
succeeded: Bridge::Api::WorkflowCommands::QuerySuccess.new(
|
437
|
-
response: @payload_converter.to_payload(result)
|
466
|
+
response: @payload_converter.to_payload(result, hint: result_hint)
|
438
467
|
)
|
439
468
|
)
|
440
469
|
)
|
@@ -523,7 +552,7 @@ module Temporalio
|
|
523
552
|
Bridge::Api::WorkflowCommands::WorkflowCommand.new(
|
524
553
|
update_response: Bridge::Api::WorkflowCommands::UpdateResponse.new(
|
525
554
|
protocol_instance_id: job.protocol_instance_id,
|
526
|
-
completed: @payload_converter.to_payload(result)
|
555
|
+
completed: @payload_converter.to_payload(result, hint: defn.result_hint)
|
527
556
|
)
|
528
557
|
)
|
529
558
|
)
|
@@ -553,7 +582,7 @@ module Temporalio
|
|
553
582
|
add_command(
|
554
583
|
Bridge::Api::WorkflowCommands::WorkflowCommand.new(
|
555
584
|
complete_workflow_execution: Bridge::Api::WorkflowCommands::CompleteWorkflowExecution.new(
|
556
|
-
result: @payload_converter.to_payload(result)
|
585
|
+
result: @payload_converter.to_payload(result, hint: @definition.result_hint)
|
557
586
|
)
|
558
587
|
)
|
559
588
|
)
|
@@ -581,14 +610,19 @@ module Temporalio
|
|
581
610
|
def on_top_level_exception(err)
|
582
611
|
if err.is_a?(Workflow::ContinueAsNewError)
|
583
612
|
@logger.debug('Workflow requested continue as new')
|
613
|
+
workflow_type, defn_arg_hints, =
|
614
|
+
if err.workflow
|
615
|
+
Workflow::Definition._workflow_type_and_hints_from_workflow_parameter(err.workflow)
|
616
|
+
else
|
617
|
+
[nil, @definition.arg_hints, nil]
|
618
|
+
end
|
584
619
|
add_command(
|
585
620
|
Bridge::Api::WorkflowCommands::WorkflowCommand.new(
|
586
621
|
continue_as_new_workflow_execution: Bridge::Api::WorkflowCommands::ContinueAsNewWorkflowExecution.new(
|
587
|
-
workflow_type
|
588
|
-
Workflow::Definition._workflow_type_from_workflow_parameter(err.workflow)
|
589
|
-
end,
|
622
|
+
workflow_type:,
|
590
623
|
task_queue: err.task_queue,
|
591
|
-
arguments: ProtoUtils.convert_to_payload_array(payload_converter, err.args
|
624
|
+
arguments: ProtoUtils.convert_to_payload_array(payload_converter, err.args,
|
625
|
+
hints: err.arg_hints || defn_arg_hints),
|
592
626
|
workflow_run_timeout: ProtoUtils.seconds_to_duration(err.run_timeout),
|
593
627
|
workflow_task_timeout: ProtoUtils.seconds_to_duration(err.task_timeout),
|
594
628
|
memo: ProtoUtils.memo_to_proto_hash(err.memo, payload_converter),
|
@@ -626,9 +660,9 @@ module Temporalio
|
|
626
660
|
end
|
627
661
|
|
628
662
|
def failure_exception?(err)
|
629
|
-
err.is_a?(Error::Failure) || err.is_a?(Timeout::Error) ||
|
630
|
-
err.is_a?(cls)
|
631
|
-
|
663
|
+
err.is_a?(Error::Failure) || err.is_a?(Timeout::Error) ||
|
664
|
+
@workflow_failure_exception_types&.any? { |cls| err.is_a?(cls) } ||
|
665
|
+
@definition_options.failure_exception_types&.any? { |cls| err.is_a?(cls) }
|
632
666
|
end
|
633
667
|
|
634
668
|
def with_context_frozen(&)
|
@@ -643,11 +677,12 @@ module Temporalio
|
|
643
677
|
payload_array:,
|
644
678
|
method_name: defn.to_invoke.is_a?(Symbol) ? defn.to_invoke : nil,
|
645
679
|
raw_args: defn.raw_args,
|
680
|
+
arg_hints: defn.arg_hints,
|
646
681
|
ignore_first_param: defn.name.nil? # Dynamic
|
647
682
|
)
|
648
683
|
end
|
649
684
|
|
650
|
-
def convert_args(payload_array:, method_name:, raw_args:, ignore_first_param: false)
|
685
|
+
def convert_args(payload_array:, method_name:, raw_args:, arg_hints:, ignore_first_param: false)
|
651
686
|
# Just in case it is not an array
|
652
687
|
payload_array = payload_array.to_ary
|
653
688
|
|
@@ -687,7 +722,7 @@ module Temporalio
|
|
687
722
|
if raw_args
|
688
723
|
payload_array.map { |p| Converters::RawValue.new(p) }
|
689
724
|
else
|
690
|
-
ProtoUtils.convert_from_payload_array(@payload_converter, payload_array)
|
725
|
+
ProtoUtils.convert_from_payload_array(@payload_converter, payload_array, hints: arg_hints)
|
691
726
|
end
|
692
727
|
end
|
693
728
|
|
@@ -13,7 +13,7 @@ module Temporalio
|
|
13
13
|
module Worker
|
14
14
|
# Worker for handling workflow activations. Most activation work is delegated to the workflow executor.
|
15
15
|
class WorkflowWorker
|
16
|
-
def self.workflow_definitions(workflows)
|
16
|
+
def self.workflow_definitions(workflows, should_enforce_versioning_behavior:)
|
17
17
|
workflows.each_with_object({}) do |workflow, hash|
|
18
18
|
# Load definition
|
19
19
|
defn = begin
|
@@ -29,6 +29,12 @@ module Temporalio
|
|
29
29
|
# Confirm name not in use
|
30
30
|
raise ArgumentError, "Multiple workflows named #{defn.name || '<dynamic>'}" if hash.key?(defn.name)
|
31
31
|
|
32
|
+
# Enforce versioning behavior is set when versioning is on
|
33
|
+
if should_enforce_versioning_behavior &&
|
34
|
+
defn.versioning_behavior == VersioningBehavior::UNSPECIFIED && !defn.dynamic_options_method
|
35
|
+
raise ArgumentError, "Workflow #{defn.name} must specify a versioning behavior"
|
36
|
+
end
|
37
|
+
|
32
38
|
hash[defn.name] = defn
|
33
39
|
end
|
34
40
|
end
|
@@ -69,7 +75,7 @@ module Temporalio
|
|
69
75
|
workflow_payload_codec_thread_pool:,
|
70
76
|
unsafe_workflow_io_enabled:,
|
71
77
|
debug_mode:,
|
72
|
-
on_eviction: nil
|
78
|
+
assert_valid_local_activity:, on_eviction: nil
|
73
79
|
)
|
74
80
|
@executor = workflow_executor
|
75
81
|
|
@@ -105,13 +111,14 @@ module Temporalio
|
|
105
111
|
disable_eager_activity_execution:,
|
106
112
|
workflow_interceptors:,
|
107
113
|
workflow_failure_exception_types: workflow_failure_exception_types.map do |t|
|
108
|
-
unless t.is_a?(Class) && t
|
114
|
+
unless t.is_a?(Class) && t <= Exception
|
109
115
|
raise ArgumentError, 'All failure types must classes inheriting Exception'
|
110
116
|
end
|
111
117
|
|
112
118
|
t
|
113
119
|
end.freeze,
|
114
|
-
unsafe_workflow_io_enabled
|
120
|
+
unsafe_workflow_io_enabled:,
|
121
|
+
assert_valid_local_activity:
|
115
122
|
)
|
116
123
|
@state.on_eviction = on_eviction if on_eviction
|
117
124
|
|
@@ -186,14 +193,16 @@ module Temporalio
|
|
186
193
|
class State
|
187
194
|
attr_reader :workflow_definitions, :bridge_worker, :logger, :metric_meter, :data_converter, :deadlock_timeout,
|
188
195
|
:illegal_calls, :namespace, :task_queue, :disable_eager_activity_execution,
|
189
|
-
:workflow_interceptors, :workflow_failure_exception_types, :unsafe_workflow_io_enabled
|
196
|
+
:workflow_interceptors, :workflow_failure_exception_types, :unsafe_workflow_io_enabled,
|
197
|
+
:assert_valid_local_activity
|
190
198
|
|
191
199
|
attr_writer :on_eviction
|
192
200
|
|
193
201
|
def initialize(
|
194
202
|
workflow_definitions:, bridge_worker:, logger:, metric_meter:, data_converter:, deadlock_timeout:,
|
195
203
|
illegal_calls:, namespace:, task_queue:, disable_eager_activity_execution:,
|
196
|
-
workflow_interceptors:, workflow_failure_exception_types:, unsafe_workflow_io_enabled
|
204
|
+
workflow_interceptors:, workflow_failure_exception_types:, unsafe_workflow_io_enabled:,
|
205
|
+
assert_valid_local_activity:
|
197
206
|
)
|
198
207
|
@workflow_definitions = workflow_definitions
|
199
208
|
@bridge_worker = bridge_worker
|
@@ -208,6 +217,7 @@ module Temporalio
|
|
208
217
|
@workflow_interceptors = workflow_interceptors
|
209
218
|
@workflow_failure_exception_types = workflow_failure_exception_types
|
210
219
|
@unsafe_workflow_io_enabled = unsafe_workflow_io_enabled
|
220
|
+
@assert_valid_local_activity = assert_valid_local_activity
|
211
221
|
|
212
222
|
@running_workflows = {}
|
213
223
|
@running_workflows_mutex = Mutex.new
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'temporalio/api'
|
4
|
+
|
5
|
+
module Temporalio
|
6
|
+
Priority = Data.define(
|
7
|
+
:priority_key
|
8
|
+
)
|
9
|
+
|
10
|
+
# Priority contains metadata that controls relative ordering of task processing when tasks are
|
11
|
+
# backlogged in a queue. Initially, Priority will be used in activity and workflow task
|
12
|
+
# queues, which are typically where backlogs exist. Priority is (for now) attached to
|
13
|
+
# workflows and activities. Activities and child workflows inherit Priority from the workflow
|
14
|
+
# that created them, but may override fields when they are started or modified. For each field
|
15
|
+
# of a Priority on an activity/workflow, not present or equal to zero/empty string means to
|
16
|
+
# inherit the value from the calling workflow, or if there is no calling workflow, then use
|
17
|
+
# the default (documented on the field).
|
18
|
+
#
|
19
|
+
# The overall semantics of Priority are:
|
20
|
+
# 1. First, consider "priority_key": lower number goes first.
|
21
|
+
# (more will be added here later).
|
22
|
+
#
|
23
|
+
# @!attribute priority_key
|
24
|
+
# @return [Integer, nil] The priority key, which is a positive integer from 1 to n, where
|
25
|
+
# smaller integers correspond to higher priorities (tasks run sooner). In general, tasks in a
|
26
|
+
# queue should be processed in close to priority order, although small deviations are possible.
|
27
|
+
# The maximum priority value (minimum priority) is determined by server configuration, and
|
28
|
+
# defaults to 5.
|
29
|
+
#
|
30
|
+
# The default priority is (min+max)/2. With the default max of 5 and min of 1, that comes
|
31
|
+
# out to 3.
|
32
|
+
class Priority
|
33
|
+
# @!visibility private
|
34
|
+
def self._from_proto(priority)
|
35
|
+
return default if priority.nil?
|
36
|
+
|
37
|
+
new(priority_key: priority.priority_key.zero? ? nil : priority.priority_key)
|
38
|
+
end
|
39
|
+
|
40
|
+
# The default priority instance.
|
41
|
+
#
|
42
|
+
# @return [Priority] The default priority
|
43
|
+
def self.default
|
44
|
+
@default ||= new(priority_key: nil)
|
45
|
+
end
|
46
|
+
|
47
|
+
# @!visibility private
|
48
|
+
def _to_proto
|
49
|
+
return nil if priority_key.nil?
|
50
|
+
|
51
|
+
Temporalio::Api::Common::V1::Priority.new(priority_key: priority_key || 0)
|
52
|
+
end
|
53
|
+
|
54
|
+
# @return [Boolean] True if this priority is empty/default
|
55
|
+
def empty?
|
56
|
+
priority_key.nil?
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -21,9 +21,10 @@ module Temporalio
|
|
21
21
|
activity_type: 'unknown',
|
22
22
|
attempt: 1,
|
23
23
|
current_attempt_scheduled_time: Time.at(0),
|
24
|
-
heartbeat_details: [],
|
25
24
|
heartbeat_timeout: nil,
|
26
25
|
local?: false,
|
26
|
+
priority: Temporalio::Priority.default,
|
27
|
+
raw_heartbeat_details: [],
|
27
28
|
schedule_to_close_timeout: 1.0,
|
28
29
|
scheduled_time: Time.at(0),
|
29
30
|
start_to_close_timeout: 1.0,
|
@@ -42,8 +43,10 @@ module Temporalio
|
|
42
43
|
# @param info [Activity::Info] Value for {Activity::Context#info}. Users should not try to instantiate this
|
43
44
|
# themselves, but rather use `with` on {default_info}.
|
44
45
|
# @param on_heartbeat [Proc(Array), nil] Proc that is called with all heartbeat details when
|
45
|
-
# {Activity::Context#heartbeat} is called.
|
46
|
+
# {Activity::Context#heartbeat} is called. Should return a value
|
46
47
|
# @param cancellation [Cancellation] Value for {Activity::Context#cancellation}.
|
48
|
+
# @param on_cancellation_details [Proc, nil] Proc that is called when {Activity::Context#cancellation_details} is
|
49
|
+
# called. Defaults to a proc that returns an instance if canceled with `cancel_requested` as true.
|
47
50
|
# @param worker_shutdown_cancellation [Cancellation] Value for {Activity::Context#worker_shutdown_cancellation}.
|
48
51
|
# @param payload_converter [Converters::PayloadConverter] Value for {Activity::Context#payload_converter}.
|
49
52
|
# @param logger [Logger] Value for {Activity::Context#logger}.
|
@@ -55,6 +58,7 @@ module Temporalio
|
|
55
58
|
info: ActivityEnvironment.default_info,
|
56
59
|
on_heartbeat: nil,
|
57
60
|
cancellation: Cancellation.new,
|
61
|
+
on_cancellation_details: nil,
|
58
62
|
worker_shutdown_cancellation: Cancellation.new,
|
59
63
|
payload_converter: Converters::PayloadConverter.default,
|
60
64
|
logger: Logger.new(nil),
|
@@ -65,6 +69,9 @@ module Temporalio
|
|
65
69
|
@info = info
|
66
70
|
@on_heartbeat = on_heartbeat
|
67
71
|
@cancellation = cancellation
|
72
|
+
@on_cancellation_details = on_cancellation_details || proc do
|
73
|
+
@_cancellation_details ||= Activity::CancellationDetails.new if @cancellation.canceled?
|
74
|
+
end
|
68
75
|
@worker_shutdown_cancellation = worker_shutdown_cancellation
|
69
76
|
@payload_converter = payload_converter
|
70
77
|
@logger = logger
|
@@ -92,6 +99,7 @@ module Temporalio
|
|
92
99
|
defn.instance.is_a?(Proc) ? defn.instance.call : defn.instance,
|
93
100
|
on_heartbeat: @on_heartbeat,
|
94
101
|
cancellation: @cancellation,
|
102
|
+
on_cancellation_details: @on_cancellation_details,
|
95
103
|
worker_shutdown_cancellation: @worker_shutdown_cancellation,
|
96
104
|
payload_converter: @payload_converter,
|
97
105
|
logger: @logger,
|
@@ -121,6 +129,7 @@ module Temporalio
|
|
121
129
|
instance:,
|
122
130
|
on_heartbeat:,
|
123
131
|
cancellation:,
|
132
|
+
on_cancellation_details:,
|
124
133
|
worker_shutdown_cancellation:,
|
125
134
|
payload_converter:,
|
126
135
|
logger:,
|
@@ -131,6 +140,7 @@ module Temporalio
|
|
131
140
|
@instance = instance
|
132
141
|
@on_heartbeat = on_heartbeat
|
133
142
|
@cancellation = cancellation
|
143
|
+
@on_cancellation_details = on_cancellation_details
|
134
144
|
@worker_shutdown_cancellation = worker_shutdown_cancellation
|
135
145
|
@payload_converter = payload_converter
|
136
146
|
@logger = logger
|
@@ -152,6 +162,11 @@ module Temporalio
|
|
152
162
|
def client
|
153
163
|
@client or raise 'No client configured in this test environment'
|
154
164
|
end
|
165
|
+
|
166
|
+
# @!visibility private
|
167
|
+
def cancellation_details
|
168
|
+
@on_cancellation_details.call
|
169
|
+
end
|
155
170
|
end
|
156
171
|
|
157
172
|
private_constant :Context
|
@@ -322,7 +322,7 @@ module Temporalio
|
|
322
322
|
raise 'Block required' unless block_given?
|
323
323
|
return super unless supports_time_skipping?
|
324
324
|
|
325
|
-
already_disabled =
|
325
|
+
already_disabled = !@auto_time_skipping
|
326
326
|
@auto_time_skipping = false
|
327
327
|
begin
|
328
328
|
yield
|
@@ -394,8 +394,8 @@ module Temporalio
|
|
394
394
|
end
|
395
395
|
|
396
396
|
# @!visibility private
|
397
|
-
def result(follow_runs: true, rpc_options: nil)
|
398
|
-
@env.time_skipping_unlocked { super(follow_runs:, rpc_options:) }
|
397
|
+
def result(follow_runs: true, result_hint: nil, rpc_options: nil)
|
398
|
+
@env.time_skipping_unlocked { super(follow_runs:, result_hint:, rpc_options:) }
|
399
399
|
end
|
400
400
|
end
|
401
401
|
end
|
data/lib/temporalio/version.rb
CHANGED
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'temporalio/worker_deployment_version'
|
4
|
+
|
5
|
+
module Temporalio
|
6
|
+
# Base class for version overrides that can be provided in start workflow options.
|
7
|
+
# Used to control the versioning behavior of workflows started with this override.
|
8
|
+
#
|
9
|
+
# WARNING: Experimental API.
|
10
|
+
class VersioningOverride
|
11
|
+
# @!visibility private
|
12
|
+
def _to_proto
|
13
|
+
raise NotImplementedError, 'Subclasses must implement this method'
|
14
|
+
end
|
15
|
+
|
16
|
+
# Represents a versioning override to pin a workflow to a specific version
|
17
|
+
class Pinned < VersioningOverride
|
18
|
+
# The worker deployment version to pin to
|
19
|
+
# @return [WorkerDeploymentVersion]
|
20
|
+
attr_reader :version
|
21
|
+
|
22
|
+
# Create a new pinned versioning override
|
23
|
+
#
|
24
|
+
# @param version [WorkerDeploymentVersion] The worker deployment version to pin to
|
25
|
+
def initialize(version)
|
26
|
+
@version = version
|
27
|
+
super()
|
28
|
+
end
|
29
|
+
|
30
|
+
# TODO: Remove deprecated field setting once removed from server
|
31
|
+
|
32
|
+
# @!visibility private
|
33
|
+
def _to_proto
|
34
|
+
Api::Workflow::V1::VersioningOverride.new(
|
35
|
+
behavior: Api::Enums::V1::VersioningBehavior::VERSIONING_BEHAVIOR_PINNED,
|
36
|
+
pinned_version: @version.to_canonical_string,
|
37
|
+
pinned: Api::Workflow::V1::VersioningOverride::PinnedOverride.new(
|
38
|
+
behavior: Api::Workflow::V1::VersioningOverride::PinnedOverrideBehavior::PINNED_OVERRIDE_BEHAVIOR_PINNED,
|
39
|
+
version: @version._to_proto
|
40
|
+
)
|
41
|
+
)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Represents a versioning override to auto-upgrade a workflow
|
46
|
+
class AutoUpgrade < VersioningOverride
|
47
|
+
# @!visibility private
|
48
|
+
def _to_proto
|
49
|
+
Api::Workflow::V1::VersioningOverride.new(
|
50
|
+
behavior: Api::Enums::V1::VersioningBehavior::VERSIONING_BEHAVIOR_AUTO_UPGRADE,
|
51
|
+
auto_upgrade: true
|
52
|
+
)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|