temporalio 1.0.0-aarch64-linux-musl → 1.2.0-aarch64-linux-musl
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 +9 -4
- data/lib/temporalio/activity/definition.rb +6 -1
- data/lib/temporalio/api/activity/v1/message.rb +11 -2
- data/lib/temporalio/api/cloud/account/v1/message.rb +3 -1
- data/lib/temporalio/api/cloud/cloudservice/v1/request_response.rb +5 -1
- data/lib/temporalio/api/cloud/cloudservice/v1/service.rb +1 -1
- data/lib/temporalio/api/cloud/sink/v1/message.rb +3 -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 +2 -1
- data/lib/temporalio/api/enums/v1/activity.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/task_queue.rb +2 -1
- data/lib/temporalio/api/enums/v1/workflow.rb +3 -1
- data/lib/temporalio/api/errordetails/v1/message.rb +2 -1
- data/lib/temporalio/api/history/v1/message.rb +3 -1
- data/lib/temporalio/api/namespace/v1/message.rb +2 -1
- data/lib/temporalio/api/nexus/v1/message.rb +1 -1
- data/lib/temporalio/api/operatorservice/v1/request_response.rb +1 -1
- data/lib/temporalio/api/payload_visitor.rb +70 -0
- data/lib/temporalio/api/taskqueue/v1/message.rb +1 -1
- data/lib/temporalio/api/worker/v1/message.rb +1 -1
- data/lib/temporalio/api/workflow/v1/message.rb +2 -1
- data/lib/temporalio/api/workflowservice/v1/request_response.rb +27 -1
- data/lib/temporalio/api/workflowservice/v1/service.rb +1 -1
- data/lib/temporalio/client/connection/cloud_service.rb +30 -0
- data/lib/temporalio/client/connection/workflow_service.rb +180 -0
- data/lib/temporalio/client/connection.rb +31 -12
- data/lib/temporalio/client/plugin.rb +42 -0
- data/lib/temporalio/client.rb +83 -14
- data/lib/temporalio/contrib/open_telemetry.rb +78 -25
- data/lib/temporalio/converters/payload_converter/binary_protobuf.rb +4 -1
- data/lib/temporalio/converters/payload_converter/composite.rb +1 -0
- data/lib/temporalio/converters/payload_converter/json_protobuf.rb +5 -2
- data/lib/temporalio/env_config.rb +3 -12
- 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/{3.2 → 4.0}/temporalio_bridge.so +0 -0
- data/lib/temporalio/internal/bridge/api/core_interface.rb +3 -1
- data/lib/temporalio/internal/bridge/api/nexus/nexus.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/runtime.rb +1 -0
- data/lib/temporalio/internal/bridge/worker.rb +5 -3
- data/lib/temporalio/internal/worker/workflow_instance/context.rb +4 -0
- data/lib/temporalio/internal/worker/workflow_instance/externally_immutable_hash.rb +1 -1
- data/lib/temporalio/internal/worker/workflow_instance/handler_hash.rb +1 -1
- data/lib/temporalio/internal/worker/workflow_instance/illegal_call_tracer.rb +8 -4
- data/lib/temporalio/internal/worker/workflow_instance/outbound_implementation.rb +32 -11
- data/lib/temporalio/internal/worker/workflow_instance/replay_safe_logger.rb +2 -1
- data/lib/temporalio/internal/worker/workflow_instance/replay_safe_metric.rb +2 -1
- data/lib/temporalio/internal/worker/workflow_instance/scheduler.rb +10 -1
- data/lib/temporalio/internal/worker/workflow_instance.rb +16 -11
- data/lib/temporalio/runtime.rb +16 -3
- data/lib/temporalio/simple_plugin.rb +192 -0
- data/lib/temporalio/version.rb +1 -1
- data/lib/temporalio/worker/plugin.rb +88 -0
- data/lib/temporalio/worker/tuner.rb +0 -4
- data/lib/temporalio/worker/workflow_replayer.rb +32 -8
- data/lib/temporalio/worker.rb +117 -44
- data/lib/temporalio/workflow/definition.rb +3 -1
- data/lib/temporalio/workflow/info.rb +4 -0
- data/lib/temporalio/workflow.rb +8 -1
- data/temporalio.gemspec +1 -1
- metadata +9 -5
|
@@ -7,8 +7,6 @@ module Temporalio
|
|
|
7
7
|
module Bridge
|
|
8
8
|
class Worker
|
|
9
9
|
Options = Struct.new(
|
|
10
|
-
:activity,
|
|
11
|
-
:workflow,
|
|
12
10
|
:namespace,
|
|
13
11
|
:task_queue,
|
|
14
12
|
:tuner,
|
|
@@ -17,7 +15,10 @@ module Temporalio
|
|
|
17
15
|
:workflow_task_poller_behavior,
|
|
18
16
|
:nonsticky_to_sticky_poll_ratio,
|
|
19
17
|
:activity_task_poller_behavior,
|
|
20
|
-
:
|
|
18
|
+
:enable_workflows,
|
|
19
|
+
:enable_local_activities,
|
|
20
|
+
:enable_remote_activities,
|
|
21
|
+
:enable_nexus,
|
|
21
22
|
:sticky_queue_schedule_to_start_timeout,
|
|
22
23
|
:max_heartbeat_throttle_interval,
|
|
23
24
|
:default_heartbeat_throttle_interval,
|
|
@@ -27,6 +28,7 @@ module Temporalio
|
|
|
27
28
|
:nondeterminism_as_workflow_fail,
|
|
28
29
|
:nondeterminism_as_workflow_fail_for_types,
|
|
29
30
|
:deployment_options,
|
|
31
|
+
:plugins,
|
|
30
32
|
keyword_init: true
|
|
31
33
|
)
|
|
32
34
|
|
|
@@ -9,7 +9,7 @@ module Temporalio
|
|
|
9
9
|
# Delegator to a hash that does not allow external mutations. Used for memo.
|
|
10
10
|
class ExternallyImmutableHash < SimpleDelegator
|
|
11
11
|
def initialize(initial_hash)
|
|
12
|
-
super(initial_hash.freeze)
|
|
12
|
+
super(initial_hash.freeze) # steep:ignore ArgumentTypeMismatch
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def _update(&)
|
|
@@ -7,7 +7,7 @@ module Temporalio
|
|
|
7
7
|
# Hash for handlers that notifies when one is added. Only `[]=` and `store` can be used to mutate it.
|
|
8
8
|
class HandlerHash < SimpleDelegator
|
|
9
9
|
def initialize(initial_frozen_hash, definition_class, &on_new_definition)
|
|
10
|
-
super(initial_frozen_hash)
|
|
10
|
+
super(initial_frozen_hash) # steep:ignore ArgumentTypeMismatch
|
|
11
11
|
@definition_class = definition_class
|
|
12
12
|
@on_new_definition = on_new_definition
|
|
13
13
|
end
|
|
@@ -13,7 +13,7 @@ module Temporalio
|
|
|
13
13
|
illegal_calls.to_h do |key, val|
|
|
14
14
|
raise TypeError, 'Invalid illegal call map, top-level key must be a String' unless key.is_a?(String)
|
|
15
15
|
|
|
16
|
-
# @type var fixed_val: :all | Worker::IllegalWorkflowCallValidator | Hash[Symbol,
|
|
16
|
+
# @type var fixed_val: :all | Temporalio::Worker::IllegalWorkflowCallValidator | Hash[Symbol, (true | Temporalio::Worker::IllegalWorkflowCallValidator)]
|
|
17
17
|
fixed_val = case val
|
|
18
18
|
when Temporalio::Worker::IllegalWorkflowCallValidator
|
|
19
19
|
if val.method_name
|
|
@@ -86,21 +86,25 @@ module Temporalio
|
|
|
86
86
|
when Temporalio::Worker::IllegalWorkflowCallValidator
|
|
87
87
|
disable_temporarily do
|
|
88
88
|
vals.block.call(Temporalio::Worker::IllegalWorkflowCallValidator::CallInfo.new(
|
|
89
|
-
class_name:,
|
|
89
|
+
class_name:,
|
|
90
|
+
method_name: tp.callee_id || :__unknown__,
|
|
91
|
+
trace_point: tp
|
|
90
92
|
))
|
|
91
93
|
nil
|
|
92
94
|
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
93
95
|
", reason: #{e}"
|
|
94
96
|
end
|
|
95
97
|
else
|
|
96
|
-
per_method = vals&.[](tp.callee_id)
|
|
98
|
+
per_method = vals&.[](tp.callee_id || :__unknown__)
|
|
97
99
|
case per_method
|
|
98
100
|
when true
|
|
99
101
|
''
|
|
100
102
|
when Temporalio::Worker::IllegalWorkflowCallValidator
|
|
101
103
|
disable_temporarily do
|
|
102
104
|
per_method.block.call(Temporalio::Worker::IllegalWorkflowCallValidator::CallInfo.new(
|
|
103
|
-
class_name:,
|
|
105
|
+
class_name:,
|
|
106
|
+
method_name: tp.callee_id || :__unknown__,
|
|
107
|
+
trace_point: tp
|
|
104
108
|
))
|
|
105
109
|
nil
|
|
106
110
|
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
@@ -43,7 +43,12 @@ module Temporalio
|
|
|
43
43
|
@instance.pending_external_cancels[seq] = Fiber.current
|
|
44
44
|
|
|
45
45
|
# Wait
|
|
46
|
-
resolution =
|
|
46
|
+
resolution = begin
|
|
47
|
+
Fiber.yield
|
|
48
|
+
ensure
|
|
49
|
+
# Remove pending
|
|
50
|
+
@instance.pending_external_cancels.delete(seq)
|
|
51
|
+
end
|
|
47
52
|
|
|
48
53
|
# Raise if resolution has failure
|
|
49
54
|
return unless resolution.failure
|
|
@@ -169,10 +174,13 @@ module Temporalio
|
|
|
169
174
|
end
|
|
170
175
|
|
|
171
176
|
# Wait
|
|
172
|
-
resolution =
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
177
|
+
resolution = begin
|
|
178
|
+
Fiber.yield
|
|
179
|
+
ensure
|
|
180
|
+
# Remove pending and cancel callback
|
|
181
|
+
@instance.pending_activities.delete(seq)
|
|
182
|
+
cancellation.remove_cancel_callback(cancel_callback_key)
|
|
183
|
+
end
|
|
176
184
|
|
|
177
185
|
case resolution.status
|
|
178
186
|
when :completed
|
|
@@ -254,10 +262,13 @@ module Temporalio
|
|
|
254
262
|
end
|
|
255
263
|
|
|
256
264
|
# Wait
|
|
257
|
-
resolution =
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
265
|
+
resolution = begin
|
|
266
|
+
Fiber.yield
|
|
267
|
+
ensure
|
|
268
|
+
# Remove pending and cancel callback
|
|
269
|
+
@instance.pending_external_signals.delete(seq)
|
|
270
|
+
cancellation.remove_cancel_callback(cancel_callback_key)
|
|
271
|
+
end
|
|
261
272
|
|
|
262
273
|
# Raise if resolution has failure
|
|
263
274
|
return unless resolution.failure
|
|
@@ -317,7 +328,12 @@ module Temporalio
|
|
|
317
328
|
end
|
|
318
329
|
|
|
319
330
|
# Wait
|
|
320
|
-
|
|
331
|
+
begin
|
|
332
|
+
Fiber.yield
|
|
333
|
+
ensure
|
|
334
|
+
# Remove pending
|
|
335
|
+
@instance.pending_timers.delete(seq)
|
|
336
|
+
end
|
|
321
337
|
|
|
322
338
|
# Remove cancellation callback (only needed on success)
|
|
323
339
|
input.cancellation.remove_cancel_callback(cancel_callback_key)
|
|
@@ -374,7 +390,12 @@ module Temporalio
|
|
|
374
390
|
end
|
|
375
391
|
|
|
376
392
|
# Wait for start
|
|
377
|
-
resolution =
|
|
393
|
+
resolution = begin
|
|
394
|
+
Fiber.yield
|
|
395
|
+
ensure
|
|
396
|
+
# Remove pending
|
|
397
|
+
@instance.pending_child_workflow_starts.delete(seq)
|
|
398
|
+
end
|
|
378
399
|
|
|
379
400
|
case resolution.status
|
|
380
401
|
when :succeeded
|
|
@@ -23,7 +23,8 @@ module Temporalio
|
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
def add(...)
|
|
26
|
-
if !@replay_safety_disabled && Temporalio::Workflow.in_workflow? &&
|
|
26
|
+
if !@replay_safety_disabled && Temporalio::Workflow.in_workflow? &&
|
|
27
|
+
Temporalio::Workflow::Unsafe.replaying_history_events?
|
|
27
28
|
return true
|
|
28
29
|
end
|
|
29
30
|
|
|
@@ -9,7 +9,8 @@ module Temporalio
|
|
|
9
9
|
# Wrapper for a metric that does not log on replay.
|
|
10
10
|
class ReplaySafeMetric < SimpleDelegator
|
|
11
11
|
def record(value, additional_attributes: nil)
|
|
12
|
-
return if Temporalio::Workflow.in_workflow? &&
|
|
12
|
+
return if Temporalio::Workflow.in_workflow? &&
|
|
13
|
+
Temporalio::Workflow::Unsafe.replaying_history_events?
|
|
13
14
|
|
|
14
15
|
super
|
|
15
16
|
end
|
|
@@ -78,7 +78,12 @@ module Temporalio
|
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
# This blocks until a resume is called on this fiber
|
|
81
|
-
result =
|
|
81
|
+
result = begin
|
|
82
|
+
Fiber.yield
|
|
83
|
+
ensure
|
|
84
|
+
# Remove pending
|
|
85
|
+
@wait_conditions.delete(seq)
|
|
86
|
+
end
|
|
82
87
|
|
|
83
88
|
# Remove cancellation callback (only needed on success)
|
|
84
89
|
cancellation&.remove_cancel_callback(cancel_callback_key) if cancel_callback_key
|
|
@@ -141,6 +146,10 @@ module Temporalio
|
|
|
141
146
|
fiber
|
|
142
147
|
end
|
|
143
148
|
|
|
149
|
+
def fiber_interrupt(fiber, exception)
|
|
150
|
+
fiber.raise(exception) if fiber.alive?
|
|
151
|
+
end
|
|
152
|
+
|
|
144
153
|
def io_wait(io, events, timeout)
|
|
145
154
|
# Do not allow if IO disabled
|
|
146
155
|
unless @instance.io_enabled
|
|
@@ -57,7 +57,8 @@ module Temporalio
|
|
|
57
57
|
:pending_external_signals, :pending_external_cancels, :in_progress_handlers, :payload_converter,
|
|
58
58
|
:failure_converter, :cancellation, :continue_as_new_suggested, :current_deployment_version,
|
|
59
59
|
:current_history_length, :current_history_size, :replaying, :random,
|
|
60
|
-
:signal_handlers, :query_handlers, :update_handlers, :context_frozen, :assert_valid_local_activity
|
|
60
|
+
:signal_handlers, :query_handlers, :update_handlers, :context_frozen, :assert_valid_local_activity,
|
|
61
|
+
:in_query_or_validator
|
|
61
62
|
attr_accessor :io_enabled, :current_details
|
|
62
63
|
|
|
63
64
|
def initialize(details)
|
|
@@ -91,6 +92,7 @@ module Temporalio
|
|
|
91
92
|
@current_history_length = 0
|
|
92
93
|
@current_history_size = 0
|
|
93
94
|
@replaying = false
|
|
95
|
+
@in_query_or_validator = false
|
|
94
96
|
@workflow_failure_exception_types = details.workflow_failure_exception_types
|
|
95
97
|
@signal_handlers = HandlerHash.new(
|
|
96
98
|
details.definition.signals,
|
|
@@ -133,6 +135,7 @@ module Temporalio
|
|
|
133
135
|
last_result: if @init_job.last_completion_result
|
|
134
136
|
@payload_converter.from_payloads(@init_job.last_completion_result).first
|
|
135
137
|
end,
|
|
138
|
+
has_last_result?: !@init_job.last_completion_result.nil?,
|
|
136
139
|
namespace: details.namespace,
|
|
137
140
|
parent: if @init_job.parent_workflow_info
|
|
138
141
|
Workflow::Info::ParentInfo.new(
|
|
@@ -181,7 +184,7 @@ module Temporalio
|
|
|
181
184
|
# Apply jobs and run event loop
|
|
182
185
|
begin
|
|
183
186
|
# Create instance if it doesn't already exist
|
|
184
|
-
@instance ||= with_context_frozen { create_instance }
|
|
187
|
+
@instance ||= with_context_frozen(in_query_or_validator: false) { create_instance }
|
|
185
188
|
|
|
186
189
|
# Apply jobs
|
|
187
190
|
activation.jobs.each { |job| apply(job) }
|
|
@@ -344,7 +347,7 @@ module Temporalio
|
|
|
344
347
|
when :initialize_workflow
|
|
345
348
|
# Ignore
|
|
346
349
|
when :fire_timer
|
|
347
|
-
pending_timers
|
|
350
|
+
pending_timers[job.fire_timer.seq]&.resume
|
|
348
351
|
when :update_random_seed
|
|
349
352
|
@random = illegal_call_tracing_disabled { Random.new(job.update_random_seed.randomness_seed) }
|
|
350
353
|
when :query_workflow
|
|
@@ -355,23 +358,23 @@ module Temporalio
|
|
|
355
358
|
when :signal_workflow
|
|
356
359
|
apply_signal(job.signal_workflow)
|
|
357
360
|
when :resolve_activity
|
|
358
|
-
pending_activities
|
|
361
|
+
pending_activities[job.resolve_activity.seq]&.resume(job.resolve_activity.result)
|
|
359
362
|
when :notify_has_patch
|
|
360
363
|
@patches_notified << job.notify_has_patch.patch_id
|
|
361
364
|
when :resolve_child_workflow_execution_start
|
|
362
|
-
pending_child_workflow_starts
|
|
365
|
+
pending_child_workflow_starts[job.resolve_child_workflow_execution_start.seq]&.resume(
|
|
363
366
|
job.resolve_child_workflow_execution_start
|
|
364
367
|
)
|
|
365
368
|
when :resolve_child_workflow_execution
|
|
366
|
-
pending_child_workflows
|
|
369
|
+
pending_child_workflows[job.resolve_child_workflow_execution.seq]&._resolve(
|
|
367
370
|
job.resolve_child_workflow_execution.result
|
|
368
371
|
)
|
|
369
372
|
when :resolve_signal_external_workflow
|
|
370
|
-
pending_external_signals
|
|
373
|
+
pending_external_signals[job.resolve_signal_external_workflow.seq]&.resume(
|
|
371
374
|
job.resolve_signal_external_workflow
|
|
372
375
|
)
|
|
373
376
|
when :resolve_request_cancel_external_workflow
|
|
374
|
-
pending_external_cancels
|
|
377
|
+
pending_external_cancels[job.resolve_request_cancel_external_workflow.seq]&.resume(
|
|
375
378
|
job.resolve_request_cancel_external_workflow
|
|
376
379
|
)
|
|
377
380
|
when :do_update
|
|
@@ -438,7 +441,7 @@ module Temporalio
|
|
|
438
441
|
end
|
|
439
442
|
result_hint = defn.result_hint
|
|
440
443
|
|
|
441
|
-
with_context_frozen do
|
|
444
|
+
with_context_frozen(in_query_or_validator: true) do
|
|
442
445
|
@inbound.handle_query(
|
|
443
446
|
Temporalio::Worker::Interceptor::Workflow::HandleQueryInput.new(
|
|
444
447
|
id: job.query_id,
|
|
@@ -501,7 +504,7 @@ module Temporalio
|
|
|
501
504
|
# other SDKs, we are re-converting the args between validate and update to disallow user mutation in
|
|
502
505
|
# validator/interceptor.
|
|
503
506
|
if job.run_validator && defn.validator_to_invoke
|
|
504
|
-
with_context_frozen do
|
|
507
|
+
with_context_frozen(in_query_or_validator: true) do
|
|
505
508
|
@inbound.validate_update(
|
|
506
509
|
Temporalio::Worker::Interceptor::Workflow::HandleUpdateInput.new(
|
|
507
510
|
id: job.id,
|
|
@@ -662,11 +665,13 @@ module Temporalio
|
|
|
662
665
|
@definition_options.failure_exception_types&.any? { |cls| err.is_a?(cls) }
|
|
663
666
|
end
|
|
664
667
|
|
|
665
|
-
def with_context_frozen(&)
|
|
668
|
+
def with_context_frozen(in_query_or_validator:, &)
|
|
666
669
|
@context_frozen = true
|
|
670
|
+
@in_query_or_validator = in_query_or_validator
|
|
667
671
|
yield
|
|
668
672
|
ensure
|
|
669
673
|
@context_frozen = false
|
|
674
|
+
@in_query_or_validator = false
|
|
670
675
|
end
|
|
671
676
|
|
|
672
677
|
def convert_handler_args(payload_array:, defn:)
|
data/lib/temporalio/runtime.rb
CHANGED
|
@@ -101,7 +101,8 @@ module Temporalio
|
|
|
101
101
|
# @!visibility private
|
|
102
102
|
def _to_bridge
|
|
103
103
|
# @type self: LoggingFilterOptions
|
|
104
|
-
"#{other_level},
|
|
104
|
+
"#{other_level},temporalio_sdk_core=#{core_level},temporalio_client=#{core_level}," \
|
|
105
|
+
"temporalio_sdk=#{core_level},temporalio_bridge=#{core_level}"
|
|
105
106
|
end
|
|
106
107
|
end
|
|
107
108
|
|
|
@@ -329,12 +330,24 @@ module Temporalio
|
|
|
329
330
|
# pool, this also consumes a Ruby thread for its lifetime.
|
|
330
331
|
#
|
|
331
332
|
# @param telemetry [TelemetryOptions] Telemetry options to set.
|
|
332
|
-
|
|
333
|
+
# @param worker_heartbeat_interval [Float, nil] Interval for worker heartbeats in seconds. Can be nil to disable
|
|
334
|
+
# heartbeating. Interval must be between 1s and 60s.
|
|
335
|
+
def initialize(
|
|
336
|
+
telemetry: TelemetryOptions.new,
|
|
337
|
+
worker_heartbeat_interval: 60
|
|
338
|
+
)
|
|
339
|
+
if !worker_heartbeat_interval.nil? && !worker_heartbeat_interval.positive?
|
|
340
|
+
raise 'Worker heartbeat interval must be positive'
|
|
341
|
+
end
|
|
342
|
+
|
|
333
343
|
# Set runtime on the buffer which will fail if the buffer is used on another runtime
|
|
334
344
|
telemetry.metrics&.buffer&._set_runtime(self)
|
|
335
345
|
|
|
336
346
|
@core_runtime = Internal::Bridge::Runtime.new(
|
|
337
|
-
Internal::Bridge::Runtime::Options.new(
|
|
347
|
+
Internal::Bridge::Runtime::Options.new(
|
|
348
|
+
telemetry: telemetry._to_bridge,
|
|
349
|
+
worker_heartbeat_interval:
|
|
350
|
+
)
|
|
338
351
|
)
|
|
339
352
|
@metric_meter = Internal::Metric::Meter.create_from_runtime(self) || Metric::Meter.null
|
|
340
353
|
# We need a thread to run the command loop
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'temporalio/client'
|
|
4
|
+
require 'temporalio/worker'
|
|
5
|
+
|
|
6
|
+
module Temporalio
|
|
7
|
+
# Plugin that implements both {Client::Plugin} and {Worker::Plugin} and provides a simplified common set of settings
|
|
8
|
+
# for configuring both.
|
|
9
|
+
#
|
|
10
|
+
# WARNING: Plugins are experimental.
|
|
11
|
+
class SimplePlugin
|
|
12
|
+
include Client::Plugin
|
|
13
|
+
include Worker::Plugin
|
|
14
|
+
|
|
15
|
+
Options = Data.define(
|
|
16
|
+
:name,
|
|
17
|
+
:data_converter,
|
|
18
|
+
:client_interceptors,
|
|
19
|
+
:activities,
|
|
20
|
+
:workflows,
|
|
21
|
+
:worker_interceptors,
|
|
22
|
+
:workflow_failure_exception_types,
|
|
23
|
+
:run_context
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
# Options as returned from {options} representing the options passed to the constructor.
|
|
27
|
+
class Options; end # rubocop:disable Lint/EmptyClass
|
|
28
|
+
|
|
29
|
+
# @return [Options] Frozen options for this plugin which has the same attributes as {initialize}.
|
|
30
|
+
attr_reader :options
|
|
31
|
+
|
|
32
|
+
# Create a simple plugin.
|
|
33
|
+
#
|
|
34
|
+
# @param name [String] Required string name for this plugin.
|
|
35
|
+
# @param data_converter [Converters::DataConverter, Proc, nil] Data converter to apply to clients and workflow
|
|
36
|
+
# replayers. This can be a proc that accepts the existing data converter and returns a new one.
|
|
37
|
+
# @param client_interceptors [Array<Client::Integerceptor>, Proc, nil] Client interceptors that are appended to the
|
|
38
|
+
# existing client set (which means if they implement worker interceptors they are applied for the workers too). A
|
|
39
|
+
# proc can be provided that accepts the existing array and returns a new one.
|
|
40
|
+
# @param activities [Array<Activity::Definition, Class<Activity::Definition>, Activity::Definition::Info>, Proc,
|
|
41
|
+
# nil] Activities to append to each worker activity set. A proc can be provided that accepts the existing array
|
|
42
|
+
# and returns a new one.
|
|
43
|
+
# @param workflows [Array<Class<Workflow::Definition>>, Proc, nil] Workflows to append to each worker workflow set.
|
|
44
|
+
# A proc can be provided that accepts the existing array and returns a new one.
|
|
45
|
+
# @param worker_interceptors [Array<Interceptor::Activity, Interceptor::Workflow>, Proc, nil] Worker interceptors
|
|
46
|
+
# that are appended to the existing worker or workflow replayer set. A proc can be provided that accepts the
|
|
47
|
+
# existing array and returns a new one.
|
|
48
|
+
# @param workflow_failure_exception_types [Array<Class<Exception>>] Workflow failure exception types that are
|
|
49
|
+
# appended to the existing worker or workflow replayer set. A proc can be provided that accepts the existing array
|
|
50
|
+
# and returns a new one.
|
|
51
|
+
# @param run_context [Proc, nil] A proc that intercepts both {run_worker} or {with_workflow_replay_worker}. The proc
|
|
52
|
+
# should accept two positional parameters: options and next_call. The options are either
|
|
53
|
+
# {Worker::Plugin::RunWorkerOptions} or {Worker::Plugin::WithWorkflowReplayWorkerOptions}. The next_call is a proc
|
|
54
|
+
# itself that accepts the options and returns a value. This run_context proc should return the result of the
|
|
55
|
+
# next_call.
|
|
56
|
+
def initialize(
|
|
57
|
+
name:,
|
|
58
|
+
data_converter: nil,
|
|
59
|
+
client_interceptors: nil,
|
|
60
|
+
activities: nil,
|
|
61
|
+
workflows: nil,
|
|
62
|
+
worker_interceptors: nil,
|
|
63
|
+
workflow_failure_exception_types: nil,
|
|
64
|
+
run_context: nil
|
|
65
|
+
)
|
|
66
|
+
@options = Options.new(
|
|
67
|
+
name:,
|
|
68
|
+
data_converter:,
|
|
69
|
+
client_interceptors:,
|
|
70
|
+
activities:,
|
|
71
|
+
workflows:,
|
|
72
|
+
worker_interceptors:,
|
|
73
|
+
workflow_failure_exception_types:,
|
|
74
|
+
run_context:
|
|
75
|
+
).freeze
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Implements {Client::Plugin#name} and {Worker::Plugin#name}.
|
|
79
|
+
def name
|
|
80
|
+
@options.name
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Implements {Client::Plugin#configure_client}.
|
|
84
|
+
def configure_client(options)
|
|
85
|
+
if (data_converter = _single_option(new: @options.data_converter, existing: options.data_converter,
|
|
86
|
+
type: Converters::DataConverter, name: 'data converter'))
|
|
87
|
+
options = options.with(data_converter:)
|
|
88
|
+
end
|
|
89
|
+
if (interceptors = _array_option(new: @options.client_interceptors, existing: options.interceptors,
|
|
90
|
+
name: 'client interceptor'))
|
|
91
|
+
options = options.with(interceptors:)
|
|
92
|
+
end
|
|
93
|
+
options
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Implements {Client::Plugin#connect_client}.
|
|
97
|
+
def connect_client(options, next_call)
|
|
98
|
+
next_call.call(options)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Implements {Worker::Plugin#configure_worker}.
|
|
102
|
+
def configure_worker(options)
|
|
103
|
+
if (activities = _array_option(new: @options.activities, existing: options.activities, name: 'activity'))
|
|
104
|
+
options = options.with(activities:)
|
|
105
|
+
end
|
|
106
|
+
if (workflows = _array_option(new: @options.workflows, existing: options.workflows, name: 'workflow'))
|
|
107
|
+
options = options.with(workflows:)
|
|
108
|
+
end
|
|
109
|
+
if (interceptors = _array_option(new: @options.worker_interceptors, existing: options.interceptors,
|
|
110
|
+
name: 'worker interceptor'))
|
|
111
|
+
options = options.with(interceptors:)
|
|
112
|
+
end
|
|
113
|
+
if (workflow_failure_exception_types = _array_option(new: @options.workflow_failure_exception_types,
|
|
114
|
+
existing: options.workflow_failure_exception_types,
|
|
115
|
+
name: 'workflow failure exception types'))
|
|
116
|
+
options = options.with(workflow_failure_exception_types:)
|
|
117
|
+
end
|
|
118
|
+
options
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Implements {Worker::Plugin#run_worker}.
|
|
122
|
+
def run_worker(options, next_call)
|
|
123
|
+
if @options.run_context
|
|
124
|
+
@options.run_context.call(options, next_call) # steep:ignore NoMethod
|
|
125
|
+
else
|
|
126
|
+
next_call.call(options)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Implements {Worker::Plugin#configure_workflow_replayer}.
|
|
131
|
+
def configure_workflow_replayer(options)
|
|
132
|
+
if (data_converter = _single_option(new: @options.data_converter, existing: options.data_converter,
|
|
133
|
+
type: Converters::DataConverter, name: 'data converter'))
|
|
134
|
+
options = options.with(data_converter:)
|
|
135
|
+
end
|
|
136
|
+
if (workflows = _array_option(new: @options.workflows, existing: options.workflows, name: 'workflow'))
|
|
137
|
+
options = options.with(workflows:)
|
|
138
|
+
end
|
|
139
|
+
if (interceptors = _array_option(new: @options.worker_interceptors, existing: options.interceptors,
|
|
140
|
+
name: 'worker interceptor'))
|
|
141
|
+
options = options.with(interceptors:)
|
|
142
|
+
end
|
|
143
|
+
if (workflow_failure_exception_types = _array_option(new: @options.workflow_failure_exception_types,
|
|
144
|
+
existing: options.workflow_failure_exception_types,
|
|
145
|
+
name: 'workflow failure exception types'))
|
|
146
|
+
options = options.with(workflow_failure_exception_types:)
|
|
147
|
+
end
|
|
148
|
+
options
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Implements {Worker::Plugin#with_workflow_replay_worker}.
|
|
152
|
+
def with_workflow_replay_worker(options, next_call)
|
|
153
|
+
if @options.run_context
|
|
154
|
+
@options.run_context.call(options, next_call) # steep:ignore NoMethod
|
|
155
|
+
else
|
|
156
|
+
next_call.call(options)
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# @!visibility private
|
|
161
|
+
def _single_option(new:, existing:, type:, name:)
|
|
162
|
+
case new
|
|
163
|
+
when nil
|
|
164
|
+
nil
|
|
165
|
+
when Proc
|
|
166
|
+
new.call(existing).tap do |val| # steep:ignore NoMethod
|
|
167
|
+
raise "Instance of #{name} required" unless val.is_a?(type)
|
|
168
|
+
end
|
|
169
|
+
when type
|
|
170
|
+
new
|
|
171
|
+
else
|
|
172
|
+
raise "Unrecognized #{name} type #{new.class}"
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# @!visibility private
|
|
177
|
+
def _array_option(new:, existing:, name:)
|
|
178
|
+
case new
|
|
179
|
+
when nil
|
|
180
|
+
nil
|
|
181
|
+
when Proc
|
|
182
|
+
new.call(existing).tap do |conv| # steep:ignore NoMethod
|
|
183
|
+
raise "Array for #{name} required" unless conv.is_a?(Array)
|
|
184
|
+
end
|
|
185
|
+
when Array
|
|
186
|
+
existing + new # steep:ignore NoMethod
|
|
187
|
+
else
|
|
188
|
+
raise "Unrecognized #{name} type #{new.class}"
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
data/lib/temporalio/version.rb
CHANGED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Temporalio
|
|
4
|
+
class Worker
|
|
5
|
+
# Plugin mixin to include for configuring workers and workflow replayers, and intercepting the running of them.
|
|
6
|
+
#
|
|
7
|
+
# This is a low-level implementation that requires abstract methods herein to be implemented. Many implementers may
|
|
8
|
+
# prefer {SimplePlugin} which includes this.
|
|
9
|
+
#
|
|
10
|
+
# WARNING: Plugins are experimental.
|
|
11
|
+
module Plugin
|
|
12
|
+
RunWorkerOptions = Data.define(
|
|
13
|
+
:worker,
|
|
14
|
+
:cancellation,
|
|
15
|
+
:shutdown_signals,
|
|
16
|
+
:raise_in_block_on_shutdown
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
# Options for {run_worker}.
|
|
20
|
+
#
|
|
21
|
+
# The options contain the worker and some other options from {Worker#run}/{Worker.run_all}. Unlike other memebers
|
|
22
|
+
# in this class, mutating the worker member before invoking the next call in the chain has no effect.
|
|
23
|
+
#
|
|
24
|
+
# @note Additional required attributes of this class may be added in the future. Users should never instantiate
|
|
25
|
+
# this class, but instead use `with` on it in {run_worker}.
|
|
26
|
+
class RunWorkerOptions; end # rubocop:disable Lint/EmptyClass
|
|
27
|
+
|
|
28
|
+
WithWorkflowReplayWorkerOptions = Data.define(
|
|
29
|
+
:worker
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# Options for {with_workflow_replay_worker}.
|
|
33
|
+
#
|
|
34
|
+
# @note Additional required attributes of this class may be added in the future. Users should never instantiate
|
|
35
|
+
# this class, but instead use `with` on it in {with_workflow_replay_worker}.
|
|
36
|
+
#
|
|
37
|
+
# @!attribute worker
|
|
38
|
+
# @return [WorkflowReplayer::ReplayWorker] Replay worker.
|
|
39
|
+
class WithWorkflowReplayWorkerOptions; end # rubocop:disable Lint/EmptyClass
|
|
40
|
+
|
|
41
|
+
# @abstract
|
|
42
|
+
# @return [String] Name of the plugin.
|
|
43
|
+
def name
|
|
44
|
+
raise NotImplementedError
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Configure a worker.
|
|
48
|
+
#
|
|
49
|
+
# @abstract
|
|
50
|
+
# @param options [Options] Current immutable options set.
|
|
51
|
+
# @return [Options] Options to use, possibly updated from original.
|
|
52
|
+
def configure_worker(options)
|
|
53
|
+
raise NotImplementedError
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Run a worker.
|
|
57
|
+
#
|
|
58
|
+
# @abstract
|
|
59
|
+
# @param options [RunWorkerOptions] Current immutable options set.
|
|
60
|
+
# @param next_call [Proc] Proc for the next plugin in the chain to call. It accepts the options and returns an
|
|
61
|
+
# arbitrary object that should also be returned from this method.
|
|
62
|
+
# @return [Object] Result of next_call.
|
|
63
|
+
def run_worker(options, next_call)
|
|
64
|
+
raise NotImplementedError
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Configure a workflow replayer.
|
|
68
|
+
#
|
|
69
|
+
# @abstract
|
|
70
|
+
# @param options [WorkflowReplayer::Options] Current immutable options set.
|
|
71
|
+
# @return [WorkflowReplayer::Options] Options to use, possibly updated from original.
|
|
72
|
+
def configure_workflow_replayer(options)
|
|
73
|
+
raise NotImplementedError
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Run a replay worker.
|
|
77
|
+
#
|
|
78
|
+
# @abstract
|
|
79
|
+
# @param options [WithWorkflowReplayWorkerOptions] Current immutable options set.
|
|
80
|
+
# @param next_call [Proc] Proc for the next plugin in the chain to call. It accepts the options and returns an
|
|
81
|
+
# arbitrary object that should also be returned from this method.
|
|
82
|
+
# @return [Object] Result of next_call.
|
|
83
|
+
def with_workflow_replay_worker(options, next_call)
|
|
84
|
+
raise NotImplementedError
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -32,8 +32,6 @@ module Temporalio
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
# A slot supplier that will dynamically adjust the number of slots based on resource usage.
|
|
35
|
-
#
|
|
36
|
-
# @note WARNING: This API is experimental.
|
|
37
35
|
class ResourceBased < SlotSupplier
|
|
38
36
|
attr_reader :tuner_options, :slot_options
|
|
39
37
|
|
|
@@ -66,8 +64,6 @@ module Temporalio
|
|
|
66
64
|
#
|
|
67
65
|
# Users should be cautious when implementing this and make sure it is heavily tested and the documentation for
|
|
68
66
|
# every method is well understood.
|
|
69
|
-
#
|
|
70
|
-
# @note WARNING: This API is experimental.
|
|
71
67
|
class Custom < SlotSupplier
|
|
72
68
|
# Context provided for slot reservation on custom slot supplier.
|
|
73
69
|
#
|