temporalio 0.3.0-x86_64-linux → 0.4.0-x86_64-linux
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/Gemfile +4 -0
- data/Rakefile +1 -1
- data/lib/temporalio/activity/context.rb +13 -0
- data/lib/temporalio/activity/definition.rb +22 -5
- data/lib/temporalio/activity/info.rb +3 -0
- data/lib/temporalio/api/batch/v1/message.rb +6 -1
- data/lib/temporalio/api/command/v1/message.rb +1 -1
- data/lib/temporalio/api/common/v1/message.rb +2 -1
- data/lib/temporalio/api/deployment/v1/message.rb +38 -0
- data/lib/temporalio/api/enums/v1/batch_operation.rb +1 -1
- data/lib/temporalio/api/enums/v1/common.rb +1 -1
- data/lib/temporalio/api/enums/v1/deployment.rb +23 -0
- 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/nexus.rb +21 -0
- data/lib/temporalio/api/enums/v1/reset.rb +1 -1
- data/lib/temporalio/api/enums/v1/workflow.rb +2 -1
- data/lib/temporalio/api/errordetails/v1/message.rb +3 -1
- data/lib/temporalio/api/failure/v1/message.rb +3 -1
- data/lib/temporalio/api/history/v1/message.rb +3 -1
- data/lib/temporalio/api/nexus/v1/message.rb +2 -1
- data/lib/temporalio/api/payload_visitor.rb +75 -7
- data/lib/temporalio/api/query/v1/message.rb +2 -1
- data/lib/temporalio/api/taskqueue/v1/message.rb +4 -1
- data/lib/temporalio/api/workflow/v1/message.rb +9 -1
- data/lib/temporalio/api/workflowservice/v1/request_response.rb +40 -11
- data/lib/temporalio/api/workflowservice/v1/service.rb +1 -1
- data/lib/temporalio/api.rb +1 -0
- data/lib/temporalio/client/connection/workflow_service.rb +238 -28
- data/lib/temporalio/client/interceptor.rb +39 -0
- data/lib/temporalio/client/schedule.rb +25 -1
- data/lib/temporalio/client/with_start_workflow_operation.rb +115 -0
- data/lib/temporalio/client/workflow_execution.rb +19 -0
- data/lib/temporalio/client/workflow_handle.rb +3 -3
- data/lib/temporalio/client.rb +125 -2
- data/lib/temporalio/contrib/open_telemetry.rb +470 -0
- data/lib/temporalio/error.rb +1 -0
- data/lib/temporalio/internal/bridge/3.2/temporalio_bridge.so +0 -0
- data/lib/temporalio/internal/bridge/3.3/temporalio_bridge.so +0 -0
- data/lib/temporalio/internal/bridge/3.4/temporalio_bridge.so +0 -0
- data/lib/temporalio/internal/bridge/api/activity_task/activity_task.rb +1 -1
- data/lib/temporalio/internal/bridge/api/common/common.rb +2 -1
- data/lib/temporalio/internal/bridge/api/workflow_activation/workflow_activation.rb +1 -1
- data/lib/temporalio/internal/bridge/api/workflow_commands/workflow_commands.rb +1 -1
- data/lib/temporalio/internal/bridge/api/workflow_completion/workflow_completion.rb +2 -1
- data/lib/temporalio/internal/bridge/runtime.rb +3 -0
- data/lib/temporalio/internal/bridge/testing.rb +3 -0
- data/lib/temporalio/internal/client/implementation.rb +232 -10
- data/lib/temporalio/internal/proto_utils.rb +34 -2
- data/lib/temporalio/internal/worker/activity_worker.rb +20 -8
- data/lib/temporalio/internal/worker/multi_runner.rb +2 -2
- data/lib/temporalio/internal/worker/workflow_instance/context.rb +57 -3
- data/lib/temporalio/internal/worker/workflow_instance/details.rb +4 -2
- data/lib/temporalio/internal/worker/workflow_instance/outbound_implementation.rb +11 -26
- data/lib/temporalio/internal/worker/workflow_instance/scheduler.rb +22 -2
- data/lib/temporalio/internal/worker/workflow_instance.rb +76 -32
- data/lib/temporalio/internal/worker/workflow_worker.rb +62 -19
- data/lib/temporalio/runtime/metric_buffer.rb +94 -0
- data/lib/temporalio/runtime.rb +48 -10
- data/lib/temporalio/search_attributes.rb +13 -0
- data/lib/temporalio/testing/activity_environment.rb +42 -14
- data/lib/temporalio/testing/workflow_environment.rb +26 -3
- data/lib/temporalio/version.rb +1 -1
- data/lib/temporalio/worker/interceptor.rb +3 -0
- data/lib/temporalio/worker/thread_pool.rb +5 -5
- data/lib/temporalio/worker/tuner.rb +38 -0
- data/lib/temporalio/worker/workflow_executor/thread_pool.rb +13 -8
- data/lib/temporalio/worker/workflow_executor.rb +1 -1
- data/lib/temporalio/worker/workflow_replayer.rb +350 -0
- data/lib/temporalio/worker.rb +58 -52
- data/lib/temporalio/workflow/definition.rb +40 -8
- data/lib/temporalio/workflow/future.rb +2 -2
- data/lib/temporalio/workflow/info.rb +22 -0
- data/lib/temporalio/workflow.rb +60 -8
- data/lib/temporalio/workflow_history.rb +26 -1
- data/temporalio.gemspec +2 -1
- metadata +25 -4
@@ -93,8 +93,10 @@ module Temporalio
|
|
93
93
|
def handle_start_task(task_token, start)
|
94
94
|
set_running_activity(task_token, nil)
|
95
95
|
|
96
|
-
# Find activity definition, falling back to dynamic if
|
97
|
-
defn = @activities[start.activity_type]
|
96
|
+
# Find activity definition, falling back to dynamic if not found and not reserved name
|
97
|
+
defn = @activities[start.activity_type]
|
98
|
+
defn = @activities[nil] if !defn && !Internal::ProtoUtils.reserved_name?(start.activity_type)
|
99
|
+
|
98
100
|
if defn.nil?
|
99
101
|
raise Error::ApplicationError.new(
|
100
102
|
"Activity #{start.activity_type} for workflow #{start.workflow_execution.workflow_id} " \
|
@@ -114,7 +116,7 @@ module Temporalio
|
|
114
116
|
# Unset at the end
|
115
117
|
Activity::Context._current_executor = nil
|
116
118
|
end
|
117
|
-
rescue Exception => e # rubocop:disable Lint/RescueException We are intending to catch everything here
|
119
|
+
rescue Exception => e # rubocop:disable Lint/RescueException -- We are intending to catch everything here
|
118
120
|
remove_running_activity(task_token)
|
119
121
|
@scoped_logger.warn("Failed starting activity #{start.activity_type}")
|
120
122
|
@scoped_logger.warn(e)
|
@@ -201,6 +203,7 @@ module Temporalio
|
|
201
203
|
|
202
204
|
# Run
|
203
205
|
activity = RunningActivity.new(
|
206
|
+
worker: @worker,
|
204
207
|
info:,
|
205
208
|
cancellation: Cancellation.new,
|
206
209
|
worker_shutdown_cancellation: @worker._worker_shutdown_cancellation,
|
@@ -210,8 +213,8 @@ module Temporalio
|
|
210
213
|
)
|
211
214
|
Activity::Context._current_executor&.set_activity_context(defn, activity)
|
212
215
|
set_running_activity(task_token, activity)
|
213
|
-
run_activity(activity, input)
|
214
|
-
rescue Exception => e # rubocop:disable Lint/RescueException We are intending to catch everything here
|
216
|
+
run_activity(defn, activity, input)
|
217
|
+
rescue Exception => e # rubocop:disable Lint/RescueException -- We are intending to catch everything here
|
215
218
|
@scoped_logger.warn("Failed starting or sending completion for activity #{start.activity_type}")
|
216
219
|
@scoped_logger.warn(e)
|
217
220
|
# This means that the activity couldn't start or send completion (run
|
@@ -236,8 +239,11 @@ module Temporalio
|
|
236
239
|
remove_running_activity(task_token)
|
237
240
|
end
|
238
241
|
|
239
|
-
def run_activity(activity, input)
|
242
|
+
def run_activity(defn, activity, input)
|
240
243
|
result = begin
|
244
|
+
# Create the instance. We choose to do this before interceptors so that it is available in the interceptor.
|
245
|
+
activity.instance = defn.instance.is_a?(Proc) ? defn.instance.call : defn.instance # steep:ignore
|
246
|
+
|
241
247
|
# Build impl with interceptors
|
242
248
|
# @type var impl: Temporalio::Worker::Interceptor::Activity::Inbound
|
243
249
|
impl = InboundImplementation.new(self)
|
@@ -255,7 +261,7 @@ module Temporalio
|
|
255
261
|
result: @worker.options.client.data_converter.to_payload(result)
|
256
262
|
)
|
257
263
|
)
|
258
|
-
rescue Exception => e # rubocop:disable Lint/RescueException We are intending to catch everything here
|
264
|
+
rescue Exception => e # rubocop:disable Lint/RescueException -- We are intending to catch everything here
|
259
265
|
if e.is_a?(Activity::CompleteAsyncError)
|
260
266
|
# Wanting to complete async
|
261
267
|
@scoped_logger.debug('Completing activity asynchronously')
|
@@ -293,9 +299,10 @@ module Temporalio
|
|
293
299
|
|
294
300
|
class RunningActivity < Activity::Context
|
295
301
|
attr_reader :info, :cancellation, :worker_shutdown_cancellation, :payload_converter, :logger
|
296
|
-
attr_accessor :_outbound_impl, :_server_requested_cancel
|
302
|
+
attr_accessor :instance, :_outbound_impl, :_server_requested_cancel
|
297
303
|
|
298
304
|
def initialize( # rubocop:disable Lint/MissingSuper
|
305
|
+
worker:,
|
299
306
|
info:,
|
300
307
|
cancellation:,
|
301
308
|
worker_shutdown_cancellation:,
|
@@ -303,6 +310,7 @@ module Temporalio
|
|
303
310
|
logger:,
|
304
311
|
runtime_metric_meter:
|
305
312
|
)
|
313
|
+
@worker = worker
|
306
314
|
@info = info
|
307
315
|
@cancellation = cancellation
|
308
316
|
@worker_shutdown_cancellation = worker_shutdown_cancellation
|
@@ -331,6 +339,10 @@ module Temporalio
|
|
331
339
|
}
|
332
340
|
)
|
333
341
|
end
|
342
|
+
|
343
|
+
def client
|
344
|
+
@worker.client
|
345
|
+
end
|
334
346
|
end
|
335
347
|
|
336
348
|
class InboundImplementation < Temporalio::Worker::Interceptor::Activity::Inbound
|
@@ -34,7 +34,7 @@ module Temporalio
|
|
34
34
|
rescue InjectEventForTesting => e
|
35
35
|
@queue.push(e.event)
|
36
36
|
@queue.push(Event::BlockSuccess.new(result: e))
|
37
|
-
rescue Exception => e # rubocop:disable Lint/RescueException Intentionally catch all
|
37
|
+
rescue Exception => e # rubocop:disable Lint/RescueException -- Intentionally catch all
|
38
38
|
@queue.push(Event::BlockFailure.new(error: e))
|
39
39
|
end
|
40
40
|
else
|
@@ -43,7 +43,7 @@ module Temporalio
|
|
43
43
|
rescue InjectEventForTesting => e
|
44
44
|
@queue.push(e.event)
|
45
45
|
@queue.push(Event::BlockSuccess.new(result: e))
|
46
|
-
rescue Exception => e # rubocop:disable Lint/RescueException Intentionally catch all
|
46
|
+
rescue Exception => e # rubocop:disable Lint/RescueException -- Intentionally catch all
|
47
47
|
@queue.push(Event::BlockFailure.new(error: e))
|
48
48
|
end
|
49
49
|
end
|
@@ -32,6 +32,16 @@ module Temporalio
|
|
32
32
|
@instance.continue_as_new_suggested
|
33
33
|
end
|
34
34
|
|
35
|
+
def current_details
|
36
|
+
@instance.current_details || ''
|
37
|
+
end
|
38
|
+
|
39
|
+
def current_details=(details)
|
40
|
+
raise 'Details must be a String' unless details.nil? || details.is_a?(String)
|
41
|
+
|
42
|
+
@instance.current_details = (details || '')
|
43
|
+
end
|
44
|
+
|
35
45
|
def current_history_length
|
36
46
|
@instance.current_history_length
|
37
47
|
end
|
@@ -52,6 +62,7 @@ module Temporalio
|
|
52
62
|
activity,
|
53
63
|
*args,
|
54
64
|
task_queue:,
|
65
|
+
summary:,
|
55
66
|
schedule_to_close_timeout:,
|
56
67
|
schedule_to_start_timeout:,
|
57
68
|
start_to_close_timeout:,
|
@@ -62,11 +73,22 @@ module Temporalio
|
|
62
73
|
activity_id:,
|
63
74
|
disable_eager_execution:
|
64
75
|
)
|
76
|
+
activity = case activity
|
77
|
+
when Class
|
78
|
+
Activity::Definition::Info.from_activity(activity).name&.to_s
|
79
|
+
when Symbol, String
|
80
|
+
activity.to_s
|
81
|
+
else
|
82
|
+
raise ArgumentError, 'Activity must be a definition class, or a symbol/string'
|
83
|
+
end
|
84
|
+
raise 'Cannot invoke dynamic activities' unless activity
|
85
|
+
|
65
86
|
@outbound.execute_activity(
|
66
87
|
Temporalio::Worker::Interceptor::Workflow::ExecuteActivityInput.new(
|
67
88
|
activity:,
|
68
89
|
args:,
|
69
90
|
task_queue: task_queue || info.task_queue,
|
91
|
+
summary:,
|
70
92
|
schedule_to_close_timeout:,
|
71
93
|
schedule_to_start_timeout:,
|
72
94
|
start_to_close_timeout:,
|
@@ -93,6 +115,16 @@ module Temporalio
|
|
93
115
|
cancellation_type:,
|
94
116
|
activity_id:
|
95
117
|
)
|
118
|
+
activity = case activity
|
119
|
+
when Class
|
120
|
+
Activity::Definition::Info.from_activity(activity).name&.to_s
|
121
|
+
when Symbol, String
|
122
|
+
activity.to_s
|
123
|
+
else
|
124
|
+
raise ArgumentError, 'Activity must be a definition class, or a symbol/string'
|
125
|
+
end
|
126
|
+
raise 'Cannot invoke dynamic activities' unless activity
|
127
|
+
|
96
128
|
@outbound.execute_local_activity(
|
97
129
|
Temporalio::Worker::Interceptor::Workflow::ExecuteLocalActivityInput.new(
|
98
130
|
activity:,
|
@@ -122,12 +154,26 @@ module Temporalio
|
|
122
154
|
@instance.info
|
123
155
|
end
|
124
156
|
|
157
|
+
def instance
|
158
|
+
@instance.instance
|
159
|
+
end
|
160
|
+
|
125
161
|
def initialize_continue_as_new_error(error)
|
126
162
|
@outbound.initialize_continue_as_new_error(
|
127
163
|
Temporalio::Worker::Interceptor::Workflow::InitializeContinueAsNewErrorInput.new(error:)
|
128
164
|
)
|
129
165
|
end
|
130
166
|
|
167
|
+
def io_enabled(&)
|
168
|
+
prev = @instance.io_enabled
|
169
|
+
@instance.io_enabled = true
|
170
|
+
begin
|
171
|
+
yield
|
172
|
+
ensure
|
173
|
+
@instance.io_enabled = prev
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
131
177
|
def logger
|
132
178
|
@instance.logger
|
133
179
|
end
|
@@ -187,6 +233,8 @@ module Temporalio
|
|
187
233
|
*args,
|
188
234
|
id:,
|
189
235
|
task_queue:,
|
236
|
+
static_summary:,
|
237
|
+
static_details:,
|
190
238
|
cancellation:,
|
191
239
|
cancellation_type:,
|
192
240
|
parent_close_policy:,
|
@@ -201,10 +249,12 @@ module Temporalio
|
|
201
249
|
)
|
202
250
|
@outbound.start_child_workflow(
|
203
251
|
Temporalio::Worker::Interceptor::Workflow::StartChildWorkflowInput.new(
|
204
|
-
workflow
|
252
|
+
workflow: Workflow::Definition._workflow_type_from_workflow_parameter(workflow),
|
205
253
|
args:,
|
206
254
|
id:,
|
207
255
|
task_queue:,
|
256
|
+
static_summary:,
|
257
|
+
static_details:,
|
208
258
|
cancellation:,
|
209
259
|
cancellation_type:,
|
210
260
|
parent_close_policy:,
|
@@ -221,6 +271,10 @@ module Temporalio
|
|
221
271
|
)
|
222
272
|
end
|
223
273
|
|
274
|
+
def storage
|
275
|
+
@storage ||= {}
|
276
|
+
end
|
277
|
+
|
224
278
|
def timeout(duration, exception_class, *exception_args, summary:, &)
|
225
279
|
raise 'Block required for timeout' unless block_given?
|
226
280
|
|
@@ -302,7 +356,7 @@ module Temporalio
|
|
302
356
|
@outbound.signal_child_workflow(
|
303
357
|
Temporalio::Worker::Interceptor::Workflow::SignalChildWorkflowInput.new(
|
304
358
|
id:,
|
305
|
-
signal
|
359
|
+
signal: Workflow::Definition::Signal._name_from_parameter(signal),
|
306
360
|
args:,
|
307
361
|
cancellation:,
|
308
362
|
headers: {}
|
@@ -315,7 +369,7 @@ module Temporalio
|
|
315
369
|
Temporalio::Worker::Interceptor::Workflow::SignalExternalWorkflowInput.new(
|
316
370
|
id:,
|
317
371
|
run_id:,
|
318
|
-
signal
|
372
|
+
signal: Workflow::Definition::Signal._name_from_parameter(signal),
|
319
373
|
args:,
|
320
374
|
cancellation:,
|
321
375
|
headers: {}
|
@@ -8,7 +8,7 @@ module Temporalio
|
|
8
8
|
class Details
|
9
9
|
attr_reader :namespace, :task_queue, :definition, :initial_activation, :logger, :metric_meter,
|
10
10
|
:payload_converter, :failure_converter, :interceptors, :disable_eager_activity_execution,
|
11
|
-
:illegal_calls, :workflow_failure_exception_types
|
11
|
+
:illegal_calls, :workflow_failure_exception_types, :unsafe_workflow_io_enabled
|
12
12
|
|
13
13
|
def initialize(
|
14
14
|
namespace:,
|
@@ -22,7 +22,8 @@ module Temporalio
|
|
22
22
|
interceptors:,
|
23
23
|
disable_eager_activity_execution:,
|
24
24
|
illegal_calls:,
|
25
|
-
workflow_failure_exception_types
|
25
|
+
workflow_failure_exception_types:,
|
26
|
+
unsafe_workflow_io_enabled:
|
26
27
|
)
|
27
28
|
@namespace = namespace
|
28
29
|
@task_queue = task_queue
|
@@ -36,6 +37,7 @@ module Temporalio
|
|
36
37
|
@disable_eager_activity_execution = disable_eager_activity_execution
|
37
38
|
@illegal_calls = illegal_calls
|
38
39
|
@workflow_failure_exception_types = workflow_failure_exception_types
|
40
|
+
@unsafe_workflow_io_enabled = unsafe_workflow_io_enabled
|
39
41
|
end
|
40
42
|
end
|
41
43
|
end
|
@@ -56,16 +56,6 @@ module Temporalio
|
|
56
56
|
raise ArgumentError, 'Activity must have schedule_to_close_timeout or start_to_close_timeout'
|
57
57
|
end
|
58
58
|
|
59
|
-
activity_type = case input.activity
|
60
|
-
when Class
|
61
|
-
Activity::Definition::Info.from_activity(input.activity).name
|
62
|
-
when Symbol, String
|
63
|
-
input.activity.to_s
|
64
|
-
else
|
65
|
-
raise ArgumentError, 'Activity must be a definition class, or a symbol/string'
|
66
|
-
end
|
67
|
-
raise 'Cannot invoke dynamic activities' unless activity_type
|
68
|
-
|
69
59
|
execute_activity_with_local_backoffs(local: false, cancellation: input.cancellation) do
|
70
60
|
seq = (@activity_counter += 1)
|
71
61
|
@instance.add_command(
|
@@ -73,7 +63,7 @@ module Temporalio
|
|
73
63
|
schedule_activity: Bridge::Api::WorkflowCommands::ScheduleActivity.new(
|
74
64
|
seq:,
|
75
65
|
activity_id: input.activity_id || seq.to_s,
|
76
|
-
activity_type
|
66
|
+
activity_type: input.activity,
|
77
67
|
task_queue: input.task_queue,
|
78
68
|
headers: ProtoUtils.headers_to_proto_hash(input.headers, @instance.payload_converter),
|
79
69
|
arguments: ProtoUtils.convert_to_payload_array(@instance.payload_converter, input.args),
|
@@ -84,7 +74,8 @@ module Temporalio
|
|
84
74
|
retry_policy: input.retry_policy&._to_proto,
|
85
75
|
cancellation_type: input.cancellation_type,
|
86
76
|
do_not_eagerly_execute: input.disable_eager_execution
|
87
|
-
)
|
77
|
+
),
|
78
|
+
user_metadata: ProtoUtils.to_user_metadata(input.summary, nil, @instance.payload_converter)
|
88
79
|
)
|
89
80
|
)
|
90
81
|
seq
|
@@ -96,16 +87,6 @@ module Temporalio
|
|
96
87
|
raise ArgumentError, 'Activity must have schedule_to_close_timeout or start_to_close_timeout'
|
97
88
|
end
|
98
89
|
|
99
|
-
activity_type = case input.activity
|
100
|
-
when Class
|
101
|
-
Activity::Definition::Info.from_activity(input.activity).name
|
102
|
-
when Symbol, String
|
103
|
-
input.activity.to_s
|
104
|
-
else
|
105
|
-
raise ArgumentError, 'Activity must be a definition class, or a symbol/string'
|
106
|
-
end
|
107
|
-
raise 'Cannot invoke dynamic activities' unless activity_type
|
108
|
-
|
109
90
|
execute_activity_with_local_backoffs(local: true, cancellation: input.cancellation) do |do_backoff|
|
110
91
|
seq = (@activity_counter += 1)
|
111
92
|
@instance.add_command(
|
@@ -113,7 +94,7 @@ module Temporalio
|
|
113
94
|
schedule_local_activity: Bridge::Api::WorkflowCommands::ScheduleLocalActivity.new(
|
114
95
|
seq:,
|
115
96
|
activity_id: input.activity_id || seq.to_s,
|
116
|
-
activity_type
|
97
|
+
activity_type: input.activity,
|
117
98
|
headers: ProtoUtils.headers_to_proto_hash(input.headers, @instance.payload_converter),
|
118
99
|
arguments: ProtoUtils.convert_to_payload_array(@instance.payload_converter, input.args),
|
119
100
|
schedule_to_close_timeout: ProtoUtils.seconds_to_duration(input.schedule_to_close_timeout),
|
@@ -232,7 +213,7 @@ module Temporalio
|
|
232
213
|
seq = (@external_signal_counter += 1)
|
233
214
|
cmd = Bridge::Api::WorkflowCommands::SignalExternalWorkflowExecution.new(
|
234
215
|
seq:,
|
235
|
-
signal_name:
|
216
|
+
signal_name: signal,
|
236
217
|
args: ProtoUtils.convert_to_payload_array(@instance.payload_converter, args),
|
237
218
|
headers: ProtoUtils.headers_to_proto_hash(headers, @instance.payload_converter)
|
238
219
|
)
|
@@ -300,7 +281,8 @@ module Temporalio
|
|
300
281
|
start_timer: Bridge::Api::WorkflowCommands::StartTimer.new(
|
301
282
|
seq:,
|
302
283
|
start_to_fire_timeout: ProtoUtils.seconds_to_duration(duration)
|
303
|
-
)
|
284
|
+
),
|
285
|
+
user_metadata: ProtoUtils.to_user_metadata(input.summary, nil, @instance.payload_converter)
|
304
286
|
)
|
305
287
|
)
|
306
288
|
@instance.pending_timers[seq] = Fiber.current
|
@@ -340,7 +322,7 @@ module Temporalio
|
|
340
322
|
seq:,
|
341
323
|
namespace: @instance.info.namespace,
|
342
324
|
workflow_id: input.id,
|
343
|
-
workflow_type:
|
325
|
+
workflow_type: input.workflow,
|
344
326
|
task_queue: input.task_queue,
|
345
327
|
input: ProtoUtils.convert_to_payload_array(@instance.payload_converter, input.args),
|
346
328
|
workflow_execution_timeout: ProtoUtils.seconds_to_duration(input.execution_timeout),
|
@@ -354,6 +336,9 @@ module Temporalio
|
|
354
336
|
memo: ProtoUtils.memo_to_proto_hash(input.memo, @instance.payload_converter),
|
355
337
|
search_attributes: input.search_attributes&._to_proto_hash,
|
356
338
|
cancellation_type: input.cancellation_type
|
339
|
+
),
|
340
|
+
user_metadata: ProtoUtils.to_user_metadata(
|
341
|
+
input.static_summary, input.static_details, @instance.payload_converter
|
357
342
|
)
|
358
343
|
)
|
359
344
|
)
|
@@ -137,8 +137,28 @@ module Temporalio
|
|
137
137
|
end
|
138
138
|
|
139
139
|
def io_wait(io, events, timeout)
|
140
|
-
#
|
141
|
-
|
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
|
142
162
|
end
|
143
163
|
|
144
164
|
def kernel_sleep(duration = nil)
|
@@ -4,6 +4,7 @@ require 'json'
|
|
4
4
|
require 'temporalio'
|
5
5
|
require 'temporalio/activity/definition'
|
6
6
|
require 'temporalio/api'
|
7
|
+
require 'temporalio/converters/payload_converter'
|
7
8
|
require 'temporalio/converters/raw_value'
|
8
9
|
require 'temporalio/error'
|
9
10
|
require 'temporalio/internal/bridge/api'
|
@@ -56,6 +57,7 @@ module Temporalio
|
|
56
57
|
:failure_converter, :cancellation, :continue_as_new_suggested, :current_history_length,
|
57
58
|
:current_history_size, :replaying, :random, :signal_handlers, :query_handlers, :update_handlers,
|
58
59
|
:context_frozen
|
60
|
+
attr_accessor :io_enabled, :current_details
|
59
61
|
|
60
62
|
def initialize(details)
|
61
63
|
# Initialize general state
|
@@ -66,6 +68,7 @@ module Temporalio
|
|
66
68
|
@logger = ReplaySafeLogger.new(logger: details.logger, instance: self)
|
67
69
|
@logger.scoped_values_getter = proc { scoped_logger_info }
|
68
70
|
@runtime_metric_meter = details.metric_meter
|
71
|
+
@io_enabled = details.unsafe_workflow_io_enabled
|
69
72
|
@scheduler = Scheduler.new(self)
|
70
73
|
@payload_converter = details.payload_converter
|
71
74
|
@failure_converter = details.failure_converter
|
@@ -115,6 +118,7 @@ module Temporalio
|
|
115
118
|
continued_run_id: ProtoUtils.string_or(@init_job.continued_from_execution_run_id),
|
116
119
|
cron_schedule: ProtoUtils.string_or(@init_job.cron_schedule),
|
117
120
|
execution_timeout: ProtoUtils.duration_to_seconds(@init_job.workflow_execution_timeout),
|
121
|
+
headers: ProtoUtils.headers_from_proto_map(@init_job.headers, @payload_converter) || {},
|
118
122
|
last_failure: if @init_job.continued_failure
|
119
123
|
@failure_converter.from_failure(@init_job.continued_failure, @payload_converter)
|
120
124
|
end,
|
@@ -130,6 +134,12 @@ module Temporalio
|
|
130
134
|
)
|
131
135
|
end,
|
132
136
|
retry_policy: (RetryPolicy._from_proto(@init_job.retry_policy) if @init_job.retry_policy),
|
137
|
+
root: if @init_job.root_workflow
|
138
|
+
Workflow::Info::RootInfo.new(
|
139
|
+
run_id: @init_job.root_workflow.run_id,
|
140
|
+
workflow_id: @init_job.root_workflow.workflow_id
|
141
|
+
)
|
142
|
+
end,
|
133
143
|
run_id: details.initial_activation.run_id,
|
134
144
|
run_timeout: ProtoUtils.duration_to_seconds(@init_job.workflow_run_timeout),
|
135
145
|
start_time: ProtoUtils.timestamp_to_time(details.initial_activation.timestamp) || raise,
|
@@ -348,7 +358,10 @@ module Temporalio
|
|
348
358
|
end
|
349
359
|
|
350
360
|
def apply_signal(job)
|
351
|
-
|
361
|
+
# Get signal definition, falling back to dynamic if not present and not reserved
|
362
|
+
defn = signal_handlers[job.signal_name]
|
363
|
+
defn = signal_handlers[nil] if !defn && !Internal::ProtoUtils.reserved_name?(job.signal_name)
|
364
|
+
|
352
365
|
handler_exec =
|
353
366
|
if defn
|
354
367
|
HandlerExecution.new(name: job.signal_name, update_id: nil, unfinished_policy: defn.unfinished_policy)
|
@@ -381,37 +394,41 @@ module Temporalio
|
|
381
394
|
end
|
382
395
|
|
383
396
|
def apply_query(job)
|
384
|
-
# TODO(cretz): __temporal_workflow_metadata
|
385
|
-
defn = case job.query_type
|
386
|
-
when '__stack_trace'
|
387
|
-
Workflow::Definition::Query.new(
|
388
|
-
name: '__stack_trace',
|
389
|
-
to_invoke: proc { scheduler.stack_trace }
|
390
|
-
)
|
391
|
-
else
|
392
|
-
query_handlers[job.query_type] || query_handlers[nil]
|
393
|
-
end
|
394
397
|
schedule do
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
398
|
+
# If it's a built-in, run it without interceptors, otherwise do normal behavior
|
399
|
+
result = if job.query_type == '__stack_trace'
|
400
|
+
# Use raw value built from default converter because we don't want to use user-conversion
|
401
|
+
Converters::RawValue.new(Converters::PayloadConverter.default.to_payload(scheduler.stack_trace))
|
402
|
+
elsif job.query_type == '__temporal_workflow_metadata'
|
403
|
+
# Use raw value built from default converter because we don't want to use user-conversion
|
404
|
+
Converters::RawValue.new(Converters::PayloadConverter.default.to_payload(workflow_metadata))
|
405
|
+
else
|
406
|
+
# Get query definition, falling back to dynamic if not present and not reserved
|
407
|
+
defn = query_handlers[job.query_type]
|
408
|
+
defn = query_handlers[nil] if !defn && !Internal::ProtoUtils.reserved_name?(job.query_type)
|
409
|
+
|
410
|
+
unless defn
|
411
|
+
raise "Query handler for #{job.query_type} expected but not found, " \
|
412
|
+
"known queries: [#{query_handlers.keys.compact.sort.join(', ')}]"
|
413
|
+
end
|
414
|
+
|
415
|
+
with_context_frozen do
|
416
|
+
@inbound.handle_query(
|
417
|
+
Temporalio::Worker::Interceptor::Workflow::HandleQueryInput.new(
|
418
|
+
id: job.query_id,
|
419
|
+
query: job.query_type,
|
420
|
+
args: begin
|
421
|
+
convert_handler_args(payload_array: job.arguments, defn:)
|
422
|
+
rescue StandardError => e
|
423
|
+
raise "Failed converting query input arguments: #{e}"
|
424
|
+
end,
|
425
|
+
definition: defn,
|
426
|
+
headers: ProtoUtils.headers_from_proto_map(job.headers, @payload_converter) || {}
|
427
|
+
)
|
428
|
+
)
|
429
|
+
end
|
430
|
+
end
|
399
431
|
|
400
|
-
result = with_context_frozen do
|
401
|
-
@inbound.handle_query(
|
402
|
-
Temporalio::Worker::Interceptor::Workflow::HandleQueryInput.new(
|
403
|
-
id: job.query_id,
|
404
|
-
query: job.query_type,
|
405
|
-
args: begin
|
406
|
-
convert_handler_args(payload_array: job.arguments, defn:)
|
407
|
-
rescue StandardError => e
|
408
|
-
raise "Failed converting query input arguments: #{e}"
|
409
|
-
end,
|
410
|
-
definition: defn,
|
411
|
-
headers: ProtoUtils.headers_from_proto_map(job.headers, @payload_converter) || {}
|
412
|
-
)
|
413
|
-
)
|
414
|
-
end
|
415
432
|
add_command(
|
416
433
|
Bridge::Api::WorkflowCommands::WorkflowCommand.new(
|
417
434
|
respond_to_query: Bridge::Api::WorkflowCommands::QueryResult.new(
|
@@ -435,7 +452,10 @@ module Temporalio
|
|
435
452
|
end
|
436
453
|
|
437
454
|
def apply_update(job)
|
438
|
-
|
455
|
+
# Get update definition, falling back to dynamic if not present and not reserved
|
456
|
+
defn = update_handlers[job.name]
|
457
|
+
defn = update_handlers[nil] if !defn && !Internal::ProtoUtils.reserved_name?(job.name)
|
458
|
+
|
439
459
|
handler_exec =
|
440
460
|
(HandlerExecution.new(name: job.name, update_id: job.id, unfinished_policy: defn.unfinished_policy) if defn)
|
441
461
|
schedule(handler_exec:) do
|
@@ -527,7 +547,7 @@ module Temporalio
|
|
527
547
|
result = @inbound.execute(
|
528
548
|
Temporalio::Worker::Interceptor::Workflow::ExecuteInput.new(
|
529
549
|
args: @workflow_arguments,
|
530
|
-
headers:
|
550
|
+
headers: @info.headers
|
531
551
|
)
|
532
552
|
)
|
533
553
|
add_command(
|
@@ -671,6 +691,30 @@ module Temporalio
|
|
671
691
|
end
|
672
692
|
end
|
673
693
|
|
694
|
+
def workflow_metadata
|
695
|
+
Temporalio::Api::Sdk::V1::WorkflowMetadata.new(
|
696
|
+
definition: Temporalio::Api::Sdk::V1::WorkflowDefinition.new(
|
697
|
+
type: info.workflow_type,
|
698
|
+
query_definitions: query_handlers.values.map do |defn|
|
699
|
+
Temporalio::Api::Sdk::V1::WorkflowInteractionDefinition.new(
|
700
|
+
name: defn.name || '', description: defn.description || ''
|
701
|
+
)
|
702
|
+
end,
|
703
|
+
signal_definitions: signal_handlers.values.map do |defn|
|
704
|
+
Temporalio::Api::Sdk::V1::WorkflowInteractionDefinition.new(
|
705
|
+
name: defn.name || '', description: defn.description || ''
|
706
|
+
)
|
707
|
+
end,
|
708
|
+
update_definitions: update_handlers.values.map do |defn|
|
709
|
+
Temporalio::Api::Sdk::V1::WorkflowInteractionDefinition.new(
|
710
|
+
name: defn.name || '', description: defn.description || ''
|
711
|
+
)
|
712
|
+
end
|
713
|
+
),
|
714
|
+
current_details: current_details || ''
|
715
|
+
)
|
716
|
+
end
|
717
|
+
|
674
718
|
def scoped_logger_info
|
675
719
|
@scoped_logger_info ||= {
|
676
720
|
attempt: info.attempt,
|