temporalio 1.1.0 → 1.3.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/Cargo.lock +228 -194
- data/Cargo.toml +9 -1
- data/Gemfile +6 -4
- data/README.md +2 -2
- data/ext/Cargo.toml +5 -1
- data/lib/temporalio/activity/definition.rb +6 -1
- data/lib/temporalio/api/activity/v1/message.rb +11 -2
- 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 +64 -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 +23 -1
- data/lib/temporalio/api/workflowservice/v1/service.rb +1 -1
- data/lib/temporalio/client/connection/workflow_service.rb +150 -0
- data/lib/temporalio/client/connection.rb +17 -3
- data/lib/temporalio/client/plugin.rb +42 -0
- data/lib/temporalio/client.rb +82 -15
- data/lib/temporalio/common_enums.rb +0 -2
- data/lib/temporalio/contrib/open_telemetry.rb +21 -0
- data/lib/temporalio/converters/failure_converter.rb +30 -0
- data/lib/temporalio/converters/payload_converter/binary_protobuf.rb +4 -1
- data/lib/temporalio/converters/payload_converter/json_protobuf.rb +4 -1
- data/lib/temporalio/env_config.rb +3 -14
- data/lib/temporalio/error/failure.rb +66 -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_commands/workflow_commands.rb +1 -1
- data/lib/temporalio/internal/bridge/worker.rb +1 -0
- data/lib/temporalio/internal/worker/workflow_instance/context.rb +9 -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/nexus_client.rb +42 -0
- data/lib/temporalio/internal/worker/workflow_instance/nexus_operation_handle.rb +51 -0
- data/lib/temporalio/internal/worker/workflow_instance/outbound_implementation.rb +100 -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 +26 -11
- data/lib/temporalio/simple_plugin.rb +192 -0
- data/lib/temporalio/testing/workflow_environment.rb +40 -0
- data/lib/temporalio/version.rb +1 -1
- data/lib/temporalio/versioning_override.rb +0 -2
- data/lib/temporalio/worker/deployment_options.rb +0 -2
- data/lib/temporalio/worker/interceptor.rb +27 -0
- data/lib/temporalio/worker/plugin.rb +88 -0
- data/lib/temporalio/worker/workflow_executor/thread_pool.rb +1 -1
- data/lib/temporalio/worker/workflow_replayer.rb +28 -5
- data/lib/temporalio/worker.rb +116 -43
- data/lib/temporalio/worker_deployment_version.rb +0 -2
- data/lib/temporalio/workflow/definition.rb +3 -4
- data/lib/temporalio/workflow/nexus_client.rb +81 -0
- data/lib/temporalio/workflow/nexus_operation_cancellation_type.rb +21 -0
- data/lib/temporalio/workflow/nexus_operation_handle.rb +37 -0
- data/lib/temporalio/workflow.rb +22 -1
- data/temporalio.gemspec +1 -1
- metadata +12 -3
data/lib/temporalio/worker.rb
CHANGED
|
@@ -15,6 +15,7 @@ require 'temporalio/worker/activity_executor'
|
|
|
15
15
|
require 'temporalio/worker/deployment_options'
|
|
16
16
|
require 'temporalio/worker/illegal_workflow_call_validator'
|
|
17
17
|
require 'temporalio/worker/interceptor'
|
|
18
|
+
require 'temporalio/worker/plugin'
|
|
18
19
|
require 'temporalio/worker/poller_behavior'
|
|
19
20
|
require 'temporalio/worker/thread_pool'
|
|
20
21
|
require 'temporalio/worker/tuner'
|
|
@@ -35,6 +36,7 @@ module Temporalio
|
|
|
35
36
|
:tuner,
|
|
36
37
|
:activity_executors,
|
|
37
38
|
:workflow_executor,
|
|
39
|
+
:plugins,
|
|
38
40
|
:interceptors,
|
|
39
41
|
:identity,
|
|
40
42
|
:logger,
|
|
@@ -122,6 +124,42 @@ module Temporalio
|
|
|
122
124
|
raise_in_block_on_shutdown: Error::CanceledError.new('Workers finished'),
|
|
123
125
|
wait_block_complete: true,
|
|
124
126
|
&block
|
|
127
|
+
)
|
|
128
|
+
# We have to apply plugins. However, every plugin has a different worker. So we provide them the worker along with
|
|
129
|
+
# other options, but we disregard any mutation of the worker on the next call.
|
|
130
|
+
run_worker = proc do |options|
|
|
131
|
+
# @type var options: Plugin::RunWorkerOptions
|
|
132
|
+
_run_all_root(*workers,
|
|
133
|
+
cancellation: options.cancellation,
|
|
134
|
+
shutdown_signals: options.shutdown_signals,
|
|
135
|
+
raise_in_block_on_shutdown: options.raise_in_block_on_shutdown,
|
|
136
|
+
wait_block_complete:, &block)
|
|
137
|
+
end
|
|
138
|
+
plugins_with_workers = workers.flat_map { |w| w._plugins.map { |p| [p, w] } }
|
|
139
|
+
run_worker = plugins_with_workers.reverse_each.reduce(run_worker) do |next_call, plugin_with_worker|
|
|
140
|
+
plugin, worker = plugin_with_worker
|
|
141
|
+
proc do |options|
|
|
142
|
+
plugin.run_worker(options.with(worker:), next_call) # steep:ignore
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
run_worker.call(Plugin::RunWorkerOptions.new(
|
|
147
|
+
# Intentionally violating typing here because we set this on each call
|
|
148
|
+
worker: nil, # steep:ignore
|
|
149
|
+
cancellation:,
|
|
150
|
+
shutdown_signals:,
|
|
151
|
+
raise_in_block_on_shutdown:
|
|
152
|
+
))
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# @!visibility private
|
|
156
|
+
def self._run_all_root(
|
|
157
|
+
*workers,
|
|
158
|
+
cancellation:,
|
|
159
|
+
shutdown_signals:,
|
|
160
|
+
raise_in_block_on_shutdown:,
|
|
161
|
+
wait_block_complete:,
|
|
162
|
+
&block
|
|
125
163
|
)
|
|
126
164
|
# Confirm there is at least one and they are all workers
|
|
127
165
|
raise ArgumentError, 'At least one worker required' if workers.empty?
|
|
@@ -301,6 +339,19 @@ module Temporalio
|
|
|
301
339
|
end
|
|
302
340
|
end
|
|
303
341
|
|
|
342
|
+
# @!visibility private
|
|
343
|
+
def self._validate_plugins!(plugins)
|
|
344
|
+
plugins.each do |plugin|
|
|
345
|
+
raise ArgumentError, "#{plugin.class} does not implement Worker::Plugin" unless plugin.is_a?(Plugin)
|
|
346
|
+
|
|
347
|
+
# Validate plugin has implemented expected methods
|
|
348
|
+
missing = Plugin.instance_methods(false).select { |m| plugin.method(m).owner == Plugin }
|
|
349
|
+
unless missing.empty?
|
|
350
|
+
raise ArgumentError, "#{plugin.class} missing the following worker plugin method(s): #{missing.join(', ')}"
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
|
|
304
355
|
# @return [Options] Options for this worker which has the same attributes as {initialize}.
|
|
305
356
|
attr_reader :options
|
|
306
357
|
|
|
@@ -315,6 +366,9 @@ module Temporalio
|
|
|
315
366
|
# @param activity_executors [Hash<Symbol, Worker::ActivityExecutor>] Executors that activities can run within.
|
|
316
367
|
# @param workflow_executor [WorkflowExecutor] Workflow executor that workflow tasks run within. This must be a
|
|
317
368
|
# {WorkflowExecutor::ThreadPool} currently.
|
|
369
|
+
# @param plugins [Array<Plugin>] Plugins to use for configuring workers and intercepting the running of workers. Any
|
|
370
|
+
# plugins that were set on the client that include {Plugin} will automatically be applied to the worker and
|
|
371
|
+
# should not be configured explicitly via this option. WARNING: Plugins are experimental.
|
|
318
372
|
# @param interceptors [Array<Interceptor::Activity, Interceptor::Workflow>] Interceptors specific to this worker.
|
|
319
373
|
# Note, interceptors set on the client that include the {Interceptor::Activity} or {Interceptor::Workflow} module
|
|
320
374
|
# are automatically included here, so no need to specify them again.
|
|
@@ -371,7 +425,6 @@ module Temporalio
|
|
|
371
425
|
# scheduler will fail. Instead of setting this to true, users are encouraged to use {Workflow::Unsafe.io_enabled}
|
|
372
426
|
# with a block for narrower enabling of IO.
|
|
373
427
|
# @param deployment_options [DeploymentOptions, nil] Deployment options for the worker.
|
|
374
|
-
# WARNING: This is an experimental feature and may change in the future.
|
|
375
428
|
# @param workflow_task_poller_behavior [PollerBehavior] Specify the behavior of workflow task
|
|
376
429
|
# polling. Defaults to a 5-poller maximum.
|
|
377
430
|
# @param activity_task_poller_behavior [PollerBehavior] Specify the behavior of activity task
|
|
@@ -387,6 +440,7 @@ module Temporalio
|
|
|
387
440
|
tuner: Tuner.create_fixed,
|
|
388
441
|
activity_executors: ActivityExecutor.defaults,
|
|
389
442
|
workflow_executor: WorkflowExecutor::ThreadPool.default,
|
|
443
|
+
plugins: [],
|
|
390
444
|
interceptors: [],
|
|
391
445
|
identity: nil,
|
|
392
446
|
logger: client.options.logger,
|
|
@@ -411,8 +465,6 @@ module Temporalio
|
|
|
411
465
|
activity_task_poller_behavior: PollerBehavior::SimpleMaximum.new(max_concurrent_activity_task_polls),
|
|
412
466
|
debug_mode: %w[true 1].include?(ENV['TEMPORAL_DEBUG'].to_s.downcase)
|
|
413
467
|
)
|
|
414
|
-
raise ArgumentError, 'Must have at least one activity or workflow' if activities.empty? && workflows.empty?
|
|
415
|
-
|
|
416
468
|
Internal::ProtoUtils.assert_non_reserved_name(task_queue)
|
|
417
469
|
|
|
418
470
|
@options = Options.new(
|
|
@@ -423,6 +475,7 @@ module Temporalio
|
|
|
423
475
|
tuner:,
|
|
424
476
|
activity_executors:,
|
|
425
477
|
workflow_executor:,
|
|
478
|
+
plugins:,
|
|
426
479
|
interceptors:,
|
|
427
480
|
identity:,
|
|
428
481
|
logger:,
|
|
@@ -447,53 +500,68 @@ module Temporalio
|
|
|
447
500
|
activity_task_poller_behavior:,
|
|
448
501
|
debug_mode:
|
|
449
502
|
).freeze
|
|
503
|
+
# Collect applicable client plugins and worker plugins, then validate and apply to options
|
|
504
|
+
@plugins = client.options.plugins.grep(Plugin) + plugins
|
|
505
|
+
Worker._validate_plugins!(@plugins)
|
|
506
|
+
@options = @plugins.reduce(@options) { |options, plugin| plugin.configure_worker(options) }
|
|
507
|
+
# Initialize the worker for the given options
|
|
508
|
+
_initialize_from_options
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
# @!visibility private
|
|
512
|
+
def _initialize_from_options
|
|
513
|
+
if @options.activities.empty? && @options.workflows.empty?
|
|
514
|
+
raise ArgumentError, 'Must have at least one activity or workflow'
|
|
515
|
+
end
|
|
450
516
|
|
|
451
517
|
should_enforce_versioning_behavior =
|
|
452
|
-
deployment_options.use_worker_versioning &&
|
|
453
|
-
deployment_options.default_versioning_behavior == VersioningBehavior::UNSPECIFIED
|
|
518
|
+
@options.deployment_options.use_worker_versioning &&
|
|
519
|
+
@options.deployment_options.default_versioning_behavior == VersioningBehavior::UNSPECIFIED
|
|
454
520
|
# Preload workflow definitions and some workflow settings for the bridge
|
|
455
521
|
workflow_definitions = Internal::Worker::WorkflowWorker.workflow_definitions(
|
|
456
|
-
workflows,
|
|
457
|
-
should_enforce_versioning_behavior:
|
|
522
|
+
@options.workflows,
|
|
523
|
+
should_enforce_versioning_behavior:
|
|
458
524
|
)
|
|
459
525
|
nondeterminism_as_workflow_fail, nondeterminism_as_workflow_fail_for_types =
|
|
460
526
|
Internal::Worker::WorkflowWorker.bridge_workflow_failure_exception_type_options(
|
|
461
|
-
workflow_failure_exception_types
|
|
527
|
+
workflow_failure_exception_types: @options.workflow_failure_exception_types,
|
|
528
|
+
workflow_definitions:
|
|
462
529
|
)
|
|
463
530
|
|
|
464
531
|
# Create the bridge worker
|
|
465
532
|
@bridge_worker = Internal::Bridge::Worker.new(
|
|
466
|
-
client.connection._core_client,
|
|
533
|
+
@options.client.connection._core_client,
|
|
467
534
|
Internal::Bridge::Worker::Options.new(
|
|
468
|
-
namespace: client.namespace,
|
|
469
|
-
task_queue
|
|
470
|
-
tuner: tuner._to_bridge_options,
|
|
471
|
-
identity_override: identity,
|
|
472
|
-
max_cached_workflows
|
|
473
|
-
workflow_task_poller_behavior: workflow_task_poller_behavior._to_bridge_options,
|
|
474
|
-
nonsticky_to_sticky_poll_ratio
|
|
475
|
-
activity_task_poller_behavior: activity_task_poller_behavior._to_bridge_options,
|
|
476
|
-
enable_workflows:
|
|
477
|
-
enable_local_activities:
|
|
478
|
-
enable_remote_activities:
|
|
535
|
+
namespace: @options.client.namespace,
|
|
536
|
+
task_queue: @options.task_queue,
|
|
537
|
+
tuner: @options.tuner._to_bridge_options,
|
|
538
|
+
identity_override: @options.identity,
|
|
539
|
+
max_cached_workflows: @options.max_cached_workflows,
|
|
540
|
+
workflow_task_poller_behavior: @options.workflow_task_poller_behavior._to_bridge_options,
|
|
541
|
+
nonsticky_to_sticky_poll_ratio: @options.nonsticky_to_sticky_poll_ratio,
|
|
542
|
+
activity_task_poller_behavior: @options.activity_task_poller_behavior._to_bridge_options,
|
|
543
|
+
enable_workflows: !@options.workflows.empty?,
|
|
544
|
+
enable_local_activities: !@options.workflows.empty? && !@options.activities.empty?,
|
|
545
|
+
enable_remote_activities: !@options.activities.empty? && !@options.no_remote_activities,
|
|
479
546
|
enable_nexus: false,
|
|
480
|
-
sticky_queue_schedule_to_start_timeout
|
|
481
|
-
max_heartbeat_throttle_interval
|
|
482
|
-
default_heartbeat_throttle_interval
|
|
483
|
-
max_worker_activities_per_second: max_activities_per_second,
|
|
484
|
-
max_task_queue_activities_per_second
|
|
485
|
-
graceful_shutdown_period
|
|
547
|
+
sticky_queue_schedule_to_start_timeout: @options.sticky_queue_schedule_to_start_timeout,
|
|
548
|
+
max_heartbeat_throttle_interval: @options.max_heartbeat_throttle_interval,
|
|
549
|
+
default_heartbeat_throttle_interval: @options.default_heartbeat_throttle_interval,
|
|
550
|
+
max_worker_activities_per_second: @options.max_activities_per_second,
|
|
551
|
+
max_task_queue_activities_per_second: @options.max_task_queue_activities_per_second,
|
|
552
|
+
graceful_shutdown_period: @options.graceful_shutdown_period,
|
|
486
553
|
nondeterminism_as_workflow_fail:,
|
|
487
554
|
nondeterminism_as_workflow_fail_for_types:,
|
|
488
|
-
deployment_options: deployment_options._to_bridge_options
|
|
555
|
+
deployment_options: @options.deployment_options._to_bridge_options,
|
|
556
|
+
plugins: (@options.client.options.plugins + @options.plugins).map(&:name).uniq.sort
|
|
489
557
|
)
|
|
490
558
|
)
|
|
491
559
|
|
|
492
560
|
# Collect interceptors from client and params
|
|
493
|
-
@activity_interceptors = (client.options.interceptors + interceptors).select do |i|
|
|
561
|
+
@activity_interceptors = (@options.client.options.interceptors + @options.interceptors).select do |i|
|
|
494
562
|
i.is_a?(Interceptor::Activity)
|
|
495
563
|
end
|
|
496
|
-
@workflow_interceptors = (client.options.interceptors + interceptors).select do |i|
|
|
564
|
+
@workflow_interceptors = (@options.client.options.interceptors + @options.interceptors).select do |i|
|
|
497
565
|
i.is_a?(Interceptor::Workflow)
|
|
498
566
|
end
|
|
499
567
|
|
|
@@ -501,27 +569,27 @@ module Temporalio
|
|
|
501
569
|
@worker_shutdown_cancellation = Cancellation.new
|
|
502
570
|
|
|
503
571
|
# Create workers
|
|
504
|
-
unless activities.empty?
|
|
572
|
+
unless @options.activities.empty?
|
|
505
573
|
@activity_worker = Internal::Worker::ActivityWorker.new(worker: self,
|
|
506
574
|
bridge_worker: @bridge_worker)
|
|
507
575
|
end
|
|
508
|
-
unless workflows.empty?
|
|
576
|
+
unless @options.workflows.empty?
|
|
509
577
|
@workflow_worker = Internal::Worker::WorkflowWorker.new(
|
|
510
578
|
bridge_worker: @bridge_worker,
|
|
511
|
-
namespace: client.namespace,
|
|
512
|
-
task_queue
|
|
579
|
+
namespace: @options.client.namespace,
|
|
580
|
+
task_queue: @options.task_queue,
|
|
513
581
|
workflow_definitions:,
|
|
514
|
-
workflow_executor
|
|
515
|
-
logger
|
|
516
|
-
data_converter: client.data_converter,
|
|
517
|
-
metric_meter: client.connection.options.runtime.metric_meter,
|
|
582
|
+
workflow_executor: @options.workflow_executor,
|
|
583
|
+
logger: @options.logger,
|
|
584
|
+
data_converter: @options.client.data_converter,
|
|
585
|
+
metric_meter: @options.client.connection.options.runtime.metric_meter,
|
|
518
586
|
workflow_interceptors: @workflow_interceptors,
|
|
519
|
-
disable_eager_activity_execution
|
|
520
|
-
illegal_workflow_calls
|
|
521
|
-
workflow_failure_exception_types
|
|
522
|
-
workflow_payload_codec_thread_pool
|
|
523
|
-
unsafe_workflow_io_enabled
|
|
524
|
-
debug_mode
|
|
587
|
+
disable_eager_activity_execution: @options.disable_eager_activity_execution,
|
|
588
|
+
illegal_workflow_calls: @options.illegal_workflow_calls,
|
|
589
|
+
workflow_failure_exception_types: @options.workflow_failure_exception_types,
|
|
590
|
+
workflow_payload_codec_thread_pool: @options.workflow_payload_codec_thread_pool,
|
|
591
|
+
unsafe_workflow_io_enabled: @options.unsafe_workflow_io_enabled,
|
|
592
|
+
debug_mode: @options.debug_mode,
|
|
525
593
|
assert_valid_local_activity: ->(activity) { _assert_valid_local_activity(activity) }
|
|
526
594
|
)
|
|
527
595
|
end
|
|
@@ -643,5 +711,10 @@ module Temporalio
|
|
|
643
711
|
"Activity #{activity} " \
|
|
644
712
|
'is not registered on this worker, no available activities.'
|
|
645
713
|
end
|
|
714
|
+
|
|
715
|
+
# @!visibility private
|
|
716
|
+
def _plugins
|
|
717
|
+
@plugins
|
|
718
|
+
end
|
|
646
719
|
end
|
|
647
720
|
end
|
|
@@ -9,8 +9,6 @@ module Temporalio
|
|
|
9
9
|
)
|
|
10
10
|
|
|
11
11
|
# Represents the version of a specific worker deployment.
|
|
12
|
-
#
|
|
13
|
-
# WARNING: Experimental API.
|
|
14
12
|
class WorkerDeploymentVersion
|
|
15
13
|
# Parse a version from a canonical string, which must be in the format
|
|
16
14
|
# `<deployment_name>.<build_id>`. Deployment name must not have a `.` in it.
|
|
@@ -102,14 +102,14 @@ module Temporalio
|
|
|
102
102
|
|
|
103
103
|
# Just run this as if done manually
|
|
104
104
|
workflow_query(description:)
|
|
105
|
-
define_method(attr_name)
|
|
105
|
+
define_method(attr_name) do
|
|
106
|
+
instance_variable_get("@#{attr_name}") # steep:ignore NoMethod
|
|
107
|
+
end
|
|
106
108
|
end
|
|
107
109
|
end
|
|
108
110
|
|
|
109
111
|
# Set the versioning behavior of this workflow.
|
|
110
112
|
#
|
|
111
|
-
# WARNING: This method is experimental and may change in future versions.
|
|
112
|
-
#
|
|
113
113
|
# @param behavior [VersioningBehavior] The versioning behavior.
|
|
114
114
|
def workflow_versioning_behavior(behavior)
|
|
115
115
|
@versioning_behavior = behavior
|
|
@@ -730,7 +730,6 @@ module Temporalio
|
|
|
730
730
|
# @!attribute versioning_behavior
|
|
731
731
|
# Dynamic equivalent of {Definition.workflow_versioning_behavior}.
|
|
732
732
|
# Will override any behavior set there if set.
|
|
733
|
-
# WARNING: Deployment-based versioning is experimental and APIs may change.
|
|
734
733
|
# @return [VersioningBehavior, nil] The versioning behavior
|
|
735
734
|
#
|
|
736
735
|
# @return [VersioningBehavior, nil] The versioning behavior
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Temporalio
|
|
4
|
+
module Workflow
|
|
5
|
+
# Client for executing Nexus operations from workflows.
|
|
6
|
+
#
|
|
7
|
+
# This is created via {Workflow.create_nexus_client}, it is never instantiated directly.
|
|
8
|
+
#
|
|
9
|
+
# WARNING: Nexus support is experimental.
|
|
10
|
+
class NexusClient
|
|
11
|
+
# @!visibility private
|
|
12
|
+
def initialize
|
|
13
|
+
raise NotImplementedError, 'Cannot instantiate a Nexus client directly'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @return [String] Endpoint name for this client.
|
|
17
|
+
def endpoint
|
|
18
|
+
raise NotImplementedError
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @return [String] Service name for this client.
|
|
22
|
+
def service
|
|
23
|
+
raise NotImplementedError
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Start a Nexus operation and return a handle.
|
|
27
|
+
#
|
|
28
|
+
# @param operation [Symbol, String] Operation name.
|
|
29
|
+
# @param arg [Object] Argument for the operation.
|
|
30
|
+
# @param schedule_to_close_timeout [Float, nil] Total timeout for the operation in seconds.
|
|
31
|
+
# @param cancellation_type [NexusOperationCancellationType] How the operation will react to cancellation.
|
|
32
|
+
# @param summary [String, nil] Optional summary for the operation (appears in UI/CLI).
|
|
33
|
+
# @param cancellation [Cancellation] Cancellation for the operation.
|
|
34
|
+
# @param arg_hint [Object, nil] Converter hint for the argument.
|
|
35
|
+
# @param result_hint [Object, nil] Converter hint for the result.
|
|
36
|
+
# @return [NexusOperationHandle] Handle to the started operation.
|
|
37
|
+
def start_operation(
|
|
38
|
+
operation,
|
|
39
|
+
arg,
|
|
40
|
+
schedule_to_close_timeout: nil,
|
|
41
|
+
cancellation_type: NexusOperationCancellationType::WAIT_CANCELLATION_COMPLETED,
|
|
42
|
+
summary: nil,
|
|
43
|
+
cancellation: Workflow.cancellation,
|
|
44
|
+
arg_hint: nil,
|
|
45
|
+
result_hint: nil
|
|
46
|
+
)
|
|
47
|
+
raise NotImplementedError
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Execute a Nexus operation and wait for the result.
|
|
51
|
+
#
|
|
52
|
+
# This is a convenience method that calls {#start_operation} and immediately waits for the result.
|
|
53
|
+
#
|
|
54
|
+
# @param operation [Symbol, String] Operation name.
|
|
55
|
+
# @param arg [Object] Argument for the operation.
|
|
56
|
+
# @param schedule_to_close_timeout [Float, nil] Total timeout for the operation in seconds.
|
|
57
|
+
# @param cancellation_type [NexusOperationCancellationType] How the operation will react to cancellation.
|
|
58
|
+
# @param summary [String, nil] Optional summary for the operation (appears in UI/CLI).
|
|
59
|
+
# @param cancellation [Cancellation] Cancellation for the operation.
|
|
60
|
+
# @param arg_hint [Object, nil] Converter hint for the argument.
|
|
61
|
+
# @param result_hint [Object, nil] Converter hint for the result.
|
|
62
|
+
# @return [Object] Result of the operation.
|
|
63
|
+
# @raise [Error::NexusOperationError] Operation failed.
|
|
64
|
+
def execute_operation(
|
|
65
|
+
operation,
|
|
66
|
+
arg,
|
|
67
|
+
schedule_to_close_timeout: nil,
|
|
68
|
+
cancellation_type: NexusOperationCancellationType::WAIT_CANCELLATION_COMPLETED,
|
|
69
|
+
summary: nil,
|
|
70
|
+
cancellation: Workflow.cancellation,
|
|
71
|
+
arg_hint: nil,
|
|
72
|
+
result_hint: nil
|
|
73
|
+
)
|
|
74
|
+
start_operation(
|
|
75
|
+
operation, arg, schedule_to_close_timeout:, cancellation_type:, summary:, cancellation:,
|
|
76
|
+
arg_hint:, result_hint:
|
|
77
|
+
).result
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'temporalio/internal/bridge/api'
|
|
4
|
+
|
|
5
|
+
module Temporalio
|
|
6
|
+
module Workflow
|
|
7
|
+
# How a Nexus operation should handle cancellation.
|
|
8
|
+
#
|
|
9
|
+
# WARNING: Nexus support is experimental.
|
|
10
|
+
module NexusOperationCancellationType
|
|
11
|
+
# Wait for cancellation to complete (default).
|
|
12
|
+
WAIT_CANCELLATION_COMPLETED = Internal::Bridge::Api::Nexus::NexusOperationCancellationType::WAIT_CANCELLATION_COMPLETED
|
|
13
|
+
# Abandon the operation without sending a cancellation request.
|
|
14
|
+
ABANDON = Internal::Bridge::Api::Nexus::NexusOperationCancellationType::ABANDON
|
|
15
|
+
# Send a cancellation request but do not wait for confirmation.
|
|
16
|
+
TRY_CANCEL = Internal::Bridge::Api::Nexus::NexusOperationCancellationType::TRY_CANCEL
|
|
17
|
+
# Wait for the server to confirm the cancellation request was delivered.
|
|
18
|
+
WAIT_CANCELLATION_REQUESTED = Internal::Bridge::Api::Nexus::NexusOperationCancellationType::WAIT_CANCELLATION_REQUESTED
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Temporalio
|
|
4
|
+
module Workflow
|
|
5
|
+
# Handle for interacting with a Nexus operation.
|
|
6
|
+
#
|
|
7
|
+
# This is created via {NexusClient#start_operation}, it is never instantiated directly.
|
|
8
|
+
#
|
|
9
|
+
# WARNING: Nexus support is experimental.
|
|
10
|
+
class NexusOperationHandle
|
|
11
|
+
# @!visibility private
|
|
12
|
+
def initialize
|
|
13
|
+
raise NotImplementedError, 'Cannot instantiate a Nexus operation handle directly'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @return [String, nil] Operation token for async operations, nil for sync operations.
|
|
17
|
+
def operation_token
|
|
18
|
+
raise NotImplementedError
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @return [Object, nil] Hint for the result if any.
|
|
22
|
+
def result_hint
|
|
23
|
+
raise NotImplementedError
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Wait for the result.
|
|
27
|
+
#
|
|
28
|
+
# @param result_hint [Object, nil] Override the result hint, or if nil uses the one on the handle.
|
|
29
|
+
# @return [Object] Result of the Nexus operation.
|
|
30
|
+
#
|
|
31
|
+
# @raise [Error::NexusOperationError] Operation failed with +cause+ as the cause.
|
|
32
|
+
def result(result_hint: nil)
|
|
33
|
+
raise NotImplementedError
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
data/lib/temporalio/workflow.rb
CHANGED
|
@@ -12,6 +12,9 @@ require 'temporalio/workflow/external_workflow_handle'
|
|
|
12
12
|
require 'temporalio/workflow/future'
|
|
13
13
|
require 'temporalio/workflow/handler_unfinished_policy'
|
|
14
14
|
require 'temporalio/workflow/info'
|
|
15
|
+
require 'temporalio/workflow/nexus_client'
|
|
16
|
+
require 'temporalio/workflow/nexus_operation_cancellation_type'
|
|
17
|
+
require 'temporalio/workflow/nexus_operation_handle'
|
|
15
18
|
require 'temporalio/workflow/parent_close_policy'
|
|
16
19
|
require 'temporalio/workflow/update_info'
|
|
17
20
|
require 'timeout'
|
|
@@ -40,6 +43,17 @@ module Temporalio
|
|
|
40
43
|
_current.continue_as_new_suggested
|
|
41
44
|
end
|
|
42
45
|
|
|
46
|
+
# Create a Nexus client for executing operations.
|
|
47
|
+
#
|
|
48
|
+
# WARNING: Nexus support is experimental.
|
|
49
|
+
#
|
|
50
|
+
# @param endpoint [Symbol, String] Endpoint name.
|
|
51
|
+
# @param service [Symbol, String] Service name.
|
|
52
|
+
# @return [NexusClient] Client for executing Nexus operations.
|
|
53
|
+
def self.create_nexus_client(endpoint:, service:)
|
|
54
|
+
_current.create_nexus_client(endpoint:, service:)
|
|
55
|
+
end
|
|
56
|
+
|
|
43
57
|
# Get current details for this workflow that may appear in UI/CLI. Unlike static details set at start, this value
|
|
44
58
|
# can be updated throughout the life of the workflow. This can be in Temporal markdown format and can span multiple
|
|
45
59
|
# lines. This is currently experimental.
|
|
@@ -533,11 +547,18 @@ module Temporalio
|
|
|
533
547
|
# Unsafe module contains only-in-workflow methods that are considered unsafe. These should not be used unless the
|
|
534
548
|
# consequences are understood.
|
|
535
549
|
module Unsafe
|
|
536
|
-
# @return [Boolean] True if the workflow is replaying
|
|
550
|
+
# @return [Boolean] True if the workflow is replaying (including during queries and update validators), false
|
|
551
|
+
# otherwise. Most code should not check this value.
|
|
537
552
|
def self.replaying?
|
|
538
553
|
Workflow._current.replaying?
|
|
539
554
|
end
|
|
540
555
|
|
|
556
|
+
# @return [Boolean] True if the workflow is replaying history events (excluding queries and update validators),
|
|
557
|
+
# false otherwise. Most code should not check this value.
|
|
558
|
+
def self.replaying_history_events?
|
|
559
|
+
Workflow._current.replaying_history_events?
|
|
560
|
+
end
|
|
561
|
+
|
|
541
562
|
# Run a block of code with illegal call tracing disabled. Users should be cautious about using this as it can
|
|
542
563
|
# often signify unsafe code.
|
|
543
564
|
#
|
data/temporalio.gemspec
CHANGED
|
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
|
|
|
23
23
|
spec.require_paths = ['lib']
|
|
24
24
|
spec.extensions = ['ext/Cargo.toml']
|
|
25
25
|
spec.metadata['rubygems_mfa_required'] = 'true'
|
|
26
|
-
spec.required_ruby_version = '>= 3.
|
|
26
|
+
spec.required_ruby_version = '>= 3.3.0'
|
|
27
27
|
|
|
28
28
|
spec.add_dependency 'google-protobuf', '>= 3.25.0'
|
|
29
29
|
spec.add_dependency 'logger'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: temporalio
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Temporal Technologies Inc
|
|
@@ -79,6 +79,7 @@ files:
|
|
|
79
79
|
- lib/temporalio/api/common/v1/grpc_status.rb
|
|
80
80
|
- lib/temporalio/api/common/v1/message.rb
|
|
81
81
|
- lib/temporalio/api/deployment/v1/message.rb
|
|
82
|
+
- lib/temporalio/api/enums/v1/activity.rb
|
|
82
83
|
- lib/temporalio/api/enums/v1/batch_operation.rb
|
|
83
84
|
- lib/temporalio/api/enums/v1/command_type.rb
|
|
84
85
|
- lib/temporalio/api/enums/v1/common.rb
|
|
@@ -135,6 +136,7 @@ files:
|
|
|
135
136
|
- lib/temporalio/client/connection/test_service.rb
|
|
136
137
|
- lib/temporalio/client/connection/workflow_service.rb
|
|
137
138
|
- lib/temporalio/client/interceptor.rb
|
|
139
|
+
- lib/temporalio/client/plugin.rb
|
|
138
140
|
- lib/temporalio/client/schedule.rb
|
|
139
141
|
- lib/temporalio/client/schedule_handle.rb
|
|
140
142
|
- lib/temporalio/client/with_start_workflow_operation.rb
|
|
@@ -195,6 +197,8 @@ files:
|
|
|
195
197
|
- lib/temporalio/internal/worker/workflow_instance/handler_hash.rb
|
|
196
198
|
- lib/temporalio/internal/worker/workflow_instance/illegal_call_tracer.rb
|
|
197
199
|
- lib/temporalio/internal/worker/workflow_instance/inbound_implementation.rb
|
|
200
|
+
- lib/temporalio/internal/worker/workflow_instance/nexus_client.rb
|
|
201
|
+
- lib/temporalio/internal/worker/workflow_instance/nexus_operation_handle.rb
|
|
198
202
|
- lib/temporalio/internal/worker/workflow_instance/outbound_implementation.rb
|
|
199
203
|
- lib/temporalio/internal/worker/workflow_instance/replay_safe_logger.rb
|
|
200
204
|
- lib/temporalio/internal/worker/workflow_instance/replay_safe_metric.rb
|
|
@@ -207,6 +211,7 @@ files:
|
|
|
207
211
|
- lib/temporalio/runtime/metric_buffer.rb
|
|
208
212
|
- lib/temporalio/scoped_logger.rb
|
|
209
213
|
- lib/temporalio/search_attributes.rb
|
|
214
|
+
- lib/temporalio/simple_plugin.rb
|
|
210
215
|
- lib/temporalio/testing.rb
|
|
211
216
|
- lib/temporalio/testing/activity_environment.rb
|
|
212
217
|
- lib/temporalio/testing/workflow_environment.rb
|
|
@@ -219,6 +224,7 @@ files:
|
|
|
219
224
|
- lib/temporalio/worker/deployment_options.rb
|
|
220
225
|
- lib/temporalio/worker/illegal_workflow_call_validator.rb
|
|
221
226
|
- lib/temporalio/worker/interceptor.rb
|
|
227
|
+
- lib/temporalio/worker/plugin.rb
|
|
222
228
|
- lib/temporalio/worker/poller_behavior.rb
|
|
223
229
|
- lib/temporalio/worker/thread_pool.rb
|
|
224
230
|
- lib/temporalio/worker/tuner.rb
|
|
@@ -235,6 +241,9 @@ files:
|
|
|
235
241
|
- lib/temporalio/workflow/future.rb
|
|
236
242
|
- lib/temporalio/workflow/handler_unfinished_policy.rb
|
|
237
243
|
- lib/temporalio/workflow/info.rb
|
|
244
|
+
- lib/temporalio/workflow/nexus_client.rb
|
|
245
|
+
- lib/temporalio/workflow/nexus_operation_cancellation_type.rb
|
|
246
|
+
- lib/temporalio/workflow/nexus_operation_handle.rb
|
|
238
247
|
- lib/temporalio/workflow/parent_close_policy.rb
|
|
239
248
|
- lib/temporalio/workflow/update_info.rb
|
|
240
249
|
- lib/temporalio/workflow_history.rb
|
|
@@ -253,14 +262,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
253
262
|
requirements:
|
|
254
263
|
- - ">="
|
|
255
264
|
- !ruby/object:Gem::Version
|
|
256
|
-
version: 3.
|
|
265
|
+
version: 3.3.0
|
|
257
266
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
258
267
|
requirements:
|
|
259
268
|
- - ">="
|
|
260
269
|
- !ruby/object:Gem::Version
|
|
261
270
|
version: '0'
|
|
262
271
|
requirements: []
|
|
263
|
-
rubygems_version:
|
|
272
|
+
rubygems_version: 4.0.3
|
|
264
273
|
specification_version: 4
|
|
265
274
|
summary: Temporal.io Ruby SDK
|
|
266
275
|
test_files: []
|