temporalio 0.0.1
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 +7 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +130 -0
- data/bridge/Cargo.lock +2865 -0
- data/bridge/Cargo.toml +26 -0
- data/bridge/sdk-core/ARCHITECTURE.md +76 -0
- data/bridge/sdk-core/Cargo.lock +2606 -0
- data/bridge/sdk-core/Cargo.toml +2 -0
- data/bridge/sdk-core/LICENSE.txt +23 -0
- data/bridge/sdk-core/README.md +107 -0
- data/bridge/sdk-core/arch_docs/diagrams/README.md +10 -0
- data/bridge/sdk-core/arch_docs/diagrams/sticky_queues.puml +40 -0
- data/bridge/sdk-core/arch_docs/diagrams/workflow_internals.svg +1 -0
- data/bridge/sdk-core/arch_docs/sticky_queues.md +51 -0
- data/bridge/sdk-core/bridge-ffi/Cargo.toml +24 -0
- data/bridge/sdk-core/bridge-ffi/LICENSE.txt +23 -0
- data/bridge/sdk-core/bridge-ffi/build.rs +25 -0
- data/bridge/sdk-core/bridge-ffi/include/sdk-core-bridge.h +249 -0
- data/bridge/sdk-core/bridge-ffi/src/lib.rs +825 -0
- data/bridge/sdk-core/bridge-ffi/src/wrappers.rs +211 -0
- data/bridge/sdk-core/client/Cargo.toml +40 -0
- data/bridge/sdk-core/client/LICENSE.txt +23 -0
- data/bridge/sdk-core/client/src/lib.rs +1294 -0
- data/bridge/sdk-core/client/src/metrics.rs +165 -0
- data/bridge/sdk-core/client/src/raw.rs +931 -0
- data/bridge/sdk-core/client/src/retry.rs +674 -0
- data/bridge/sdk-core/client/src/workflow_handle/mod.rs +185 -0
- data/bridge/sdk-core/core/Cargo.toml +116 -0
- data/bridge/sdk-core/core/LICENSE.txt +23 -0
- data/bridge/sdk-core/core/benches/workflow_replay.rs +73 -0
- data/bridge/sdk-core/core/src/abstractions.rs +166 -0
- data/bridge/sdk-core/core/src/core_tests/activity_tasks.rs +911 -0
- data/bridge/sdk-core/core/src/core_tests/child_workflows.rs +221 -0
- data/bridge/sdk-core/core/src/core_tests/determinism.rs +107 -0
- data/bridge/sdk-core/core/src/core_tests/local_activities.rs +515 -0
- data/bridge/sdk-core/core/src/core_tests/mod.rs +100 -0
- data/bridge/sdk-core/core/src/core_tests/queries.rs +736 -0
- data/bridge/sdk-core/core/src/core_tests/replay_flag.rs +65 -0
- data/bridge/sdk-core/core/src/core_tests/workers.rs +259 -0
- data/bridge/sdk-core/core/src/core_tests/workflow_cancels.rs +124 -0
- data/bridge/sdk-core/core/src/core_tests/workflow_tasks.rs +2070 -0
- data/bridge/sdk-core/core/src/ephemeral_server/mod.rs +515 -0
- data/bridge/sdk-core/core/src/lib.rs +175 -0
- data/bridge/sdk-core/core/src/log_export.rs +62 -0
- data/bridge/sdk-core/core/src/pollers/mod.rs +54 -0
- data/bridge/sdk-core/core/src/pollers/poll_buffer.rs +297 -0
- data/bridge/sdk-core/core/src/protosext/mod.rs +428 -0
- data/bridge/sdk-core/core/src/replay/mod.rs +71 -0
- data/bridge/sdk-core/core/src/retry_logic.rs +202 -0
- data/bridge/sdk-core/core/src/telemetry/metrics.rs +383 -0
- data/bridge/sdk-core/core/src/telemetry/mod.rs +412 -0
- data/bridge/sdk-core/core/src/telemetry/prometheus_server.rs +77 -0
- data/bridge/sdk-core/core/src/test_help/mod.rs +875 -0
- data/bridge/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +580 -0
- data/bridge/sdk-core/core/src/worker/activities/local_activities.rs +1042 -0
- data/bridge/sdk-core/core/src/worker/activities.rs +464 -0
- data/bridge/sdk-core/core/src/worker/client/mocks.rs +87 -0
- data/bridge/sdk-core/core/src/worker/client.rs +347 -0
- data/bridge/sdk-core/core/src/worker/mod.rs +566 -0
- data/bridge/sdk-core/core/src/worker/workflow/bridge.rs +37 -0
- data/bridge/sdk-core/core/src/worker/workflow/driven_workflow.rs +110 -0
- data/bridge/sdk-core/core/src/worker/workflow/history_update.rs +458 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +911 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +298 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +171 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +860 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +140 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +161 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +133 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +1448 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/mod.rs +342 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/mutable_side_effect_state_machine.rs +127 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +712 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/side_effect_state_machine.rs +71 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +443 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +439 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +169 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +246 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +96 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +1184 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +277 -0
- data/bridge/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +198 -0
- data/bridge/sdk-core/core/src/worker/workflow/managed_run.rs +647 -0
- data/bridge/sdk-core/core/src/worker/workflow/mod.rs +1143 -0
- data/bridge/sdk-core/core/src/worker/workflow/run_cache.rs +145 -0
- data/bridge/sdk-core/core/src/worker/workflow/wft_poller.rs +88 -0
- data/bridge/sdk-core/core/src/worker/workflow/workflow_stream.rs +940 -0
- data/bridge/sdk-core/core-api/Cargo.toml +31 -0
- data/bridge/sdk-core/core-api/LICENSE.txt +23 -0
- data/bridge/sdk-core/core-api/src/errors.rs +95 -0
- data/bridge/sdk-core/core-api/src/lib.rs +151 -0
- data/bridge/sdk-core/core-api/src/worker.rs +135 -0
- data/bridge/sdk-core/etc/deps.svg +187 -0
- data/bridge/sdk-core/etc/dynamic-config.yaml +2 -0
- data/bridge/sdk-core/etc/otel-collector-config.yaml +36 -0
- data/bridge/sdk-core/etc/prometheus.yaml +6 -0
- data/bridge/sdk-core/fsm/Cargo.toml +18 -0
- data/bridge/sdk-core/fsm/LICENSE.txt +23 -0
- data/bridge/sdk-core/fsm/README.md +3 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/Cargo.toml +27 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/LICENSE.txt +23 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +647 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/progress.rs +8 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.rs +18 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.stderr +12 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dynamic_dest_pass.rs +41 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/forgot_name_fail.rs +14 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/forgot_name_fail.stderr +11 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/handler_arg_pass.rs +32 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/handler_pass.rs +31 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/medium_complex_pass.rs +46 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.rs +29 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +12 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/simple_pass.rs +32 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/struct_event_variant_fail.rs +18 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/struct_event_variant_fail.stderr +5 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.rs +11 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.stderr +5 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.rs +11 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.stderr +5 -0
- data/bridge/sdk-core/fsm/rustfsm_trait/Cargo.toml +14 -0
- data/bridge/sdk-core/fsm/rustfsm_trait/LICENSE.txt +23 -0
- data/bridge/sdk-core/fsm/rustfsm_trait/src/lib.rs +249 -0
- data/bridge/sdk-core/fsm/src/lib.rs +2 -0
- data/bridge/sdk-core/histories/fail_wf_task.bin +0 -0
- data/bridge/sdk-core/histories/timer_workflow_history.bin +0 -0
- data/bridge/sdk-core/integ-with-otel.sh +7 -0
- data/bridge/sdk-core/protos/api_upstream/README.md +9 -0
- data/bridge/sdk-core/protos/api_upstream/api-linter.yaml +40 -0
- data/bridge/sdk-core/protos/api_upstream/buf.yaml +12 -0
- data/bridge/sdk-core/protos/api_upstream/dependencies/gogoproto/gogo.proto +141 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +86 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/cluster/v1/message.proto +83 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +259 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +112 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +46 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/cluster.proto +40 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +57 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +55 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +168 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +97 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +51 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +50 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +41 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +60 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +59 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +51 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +122 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +108 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +114 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +56 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +751 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +97 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +161 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +99 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +61 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +55 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +300 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +108 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +46 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +59 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +145 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +1124 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +401 -0
- data/bridge/sdk-core/protos/grpc/health/v1/health.proto +63 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +78 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +79 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +210 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +77 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/common/common.proto +15 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +30 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +30 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +261 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +297 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +29 -0
- data/bridge/sdk-core/protos/testsrv_upstream/api-linter.yaml +38 -0
- data/bridge/sdk-core/protos/testsrv_upstream/buf.yaml +13 -0
- data/bridge/sdk-core/protos/testsrv_upstream/dependencies/gogoproto/gogo.proto +141 -0
- data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +63 -0
- data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +90 -0
- data/bridge/sdk-core/rustfmt.toml +1 -0
- data/bridge/sdk-core/sdk/Cargo.toml +47 -0
- data/bridge/sdk-core/sdk/LICENSE.txt +23 -0
- data/bridge/sdk-core/sdk/src/activity_context.rs +230 -0
- data/bridge/sdk-core/sdk/src/app_data.rs +37 -0
- data/bridge/sdk-core/sdk/src/conversions.rs +8 -0
- data/bridge/sdk-core/sdk/src/interceptors.rs +17 -0
- data/bridge/sdk-core/sdk/src/lib.rs +792 -0
- data/bridge/sdk-core/sdk/src/payload_converter.rs +11 -0
- data/bridge/sdk-core/sdk/src/workflow_context/options.rs +295 -0
- data/bridge/sdk-core/sdk/src/workflow_context.rs +683 -0
- data/bridge/sdk-core/sdk/src/workflow_future.rs +503 -0
- data/bridge/sdk-core/sdk-core-protos/Cargo.toml +30 -0
- data/bridge/sdk-core/sdk-core-protos/LICENSE.txt +23 -0
- data/bridge/sdk-core/sdk-core-protos/build.rs +108 -0
- data/bridge/sdk-core/sdk-core-protos/src/constants.rs +7 -0
- data/bridge/sdk-core/sdk-core-protos/src/history_builder.rs +497 -0
- data/bridge/sdk-core/sdk-core-protos/src/history_info.rs +230 -0
- data/bridge/sdk-core/sdk-core-protos/src/lib.rs +1910 -0
- data/bridge/sdk-core/sdk-core-protos/src/task_token.rs +38 -0
- data/bridge/sdk-core/sdk-core-protos/src/utilities.rs +14 -0
- data/bridge/sdk-core/test-utils/Cargo.toml +35 -0
- data/bridge/sdk-core/test-utils/src/canned_histories.rs +1579 -0
- data/bridge/sdk-core/test-utils/src/histfetch.rs +28 -0
- data/bridge/sdk-core/test-utils/src/lib.rs +598 -0
- data/bridge/sdk-core/tests/integ_tests/client_tests.rs +36 -0
- data/bridge/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +128 -0
- data/bridge/sdk-core/tests/integ_tests/heartbeat_tests.rs +218 -0
- data/bridge/sdk-core/tests/integ_tests/polling_tests.rs +146 -0
- data/bridge/sdk-core/tests/integ_tests/queries_tests.rs +437 -0
- data/bridge/sdk-core/tests/integ_tests/visibility_tests.rs +93 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/activities.rs +878 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +61 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +59 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +58 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +50 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +60 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +54 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +634 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/patches.rs +113 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/replay.rs +137 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/resets.rs +93 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/signals.rs +167 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +99 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/timers.rs +131 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +75 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests.rs +587 -0
- data/bridge/sdk-core/tests/load_tests.rs +191 -0
- data/bridge/sdk-core/tests/main.rs +111 -0
- data/bridge/sdk-core/tests/runner.rs +93 -0
- data/bridge/src/connection.rs +167 -0
- data/bridge/src/lib.rs +180 -0
- data/bridge/src/runtime.rs +47 -0
- data/bridge/src/worker.rs +73 -0
- data/ext/Rakefile +9 -0
- data/lib/bridge.so +0 -0
- data/lib/gen/dependencies/gogoproto/gogo_pb.rb +14 -0
- data/lib/gen/temporal/api/batch/v1/message_pb.rb +48 -0
- data/lib/gen/temporal/api/cluster/v1/message_pb.rb +67 -0
- data/lib/gen/temporal/api/command/v1/message_pb.rb +166 -0
- data/lib/gen/temporal/api/common/v1/message_pb.rb +69 -0
- data/lib/gen/temporal/api/enums/v1/batch_operation_pb.rb +32 -0
- data/lib/gen/temporal/api/enums/v1/cluster_pb.rb +26 -0
- data/lib/gen/temporal/api/enums/v1/command_type_pb.rb +37 -0
- data/lib/gen/temporal/api/enums/v1/common_pb.rb +41 -0
- data/lib/gen/temporal/api/enums/v1/event_type_pb.rb +67 -0
- data/lib/gen/temporal/api/enums/v1/failed_cause_pb.rb +71 -0
- data/lib/gen/temporal/api/enums/v1/namespace_pb.rb +37 -0
- data/lib/gen/temporal/api/enums/v1/query_pb.rb +31 -0
- data/lib/gen/temporal/api/enums/v1/reset_pb.rb +24 -0
- data/lib/gen/temporal/api/enums/v1/schedule_pb.rb +28 -0
- data/lib/gen/temporal/api/enums/v1/task_queue_pb.rb +30 -0
- data/lib/gen/temporal/api/enums/v1/update_pb.rb +28 -0
- data/lib/gen/temporal/api/enums/v1/workflow_pb.rb +89 -0
- data/lib/gen/temporal/api/errordetails/v1/message_pb.rb +84 -0
- data/lib/gen/temporal/api/failure/v1/message_pb.rb +83 -0
- data/lib/gen/temporal/api/filter/v1/message_pb.rb +40 -0
- data/lib/gen/temporal/api/history/v1/message_pb.rb +489 -0
- data/lib/gen/temporal/api/namespace/v1/message_pb.rb +63 -0
- data/lib/gen/temporal/api/operatorservice/v1/request_response_pb.rb +125 -0
- data/lib/gen/temporal/api/operatorservice/v1/service_pb.rb +20 -0
- data/lib/gen/temporal/api/query/v1/message_pb.rb +38 -0
- data/lib/gen/temporal/api/replication/v1/message_pb.rb +37 -0
- data/lib/gen/temporal/api/schedule/v1/message_pb.rb +128 -0
- data/lib/gen/temporal/api/taskqueue/v1/message_pb.rb +73 -0
- data/lib/gen/temporal/api/update/v1/message_pb.rb +26 -0
- data/lib/gen/temporal/api/version/v1/message_pb.rb +41 -0
- data/lib/gen/temporal/api/workflow/v1/message_pb.rb +110 -0
- data/lib/gen/temporal/api/workflowservice/v1/request_response_pb.rb +771 -0
- data/lib/gen/temporal/api/workflowservice/v1/service_pb.rb +20 -0
- data/lib/gen/temporal/sdk/core/activity_result/activity_result_pb.rb +58 -0
- data/lib/gen/temporal/sdk/core/activity_task/activity_task_pb.rb +57 -0
- data/lib/gen/temporal/sdk/core/bridge/bridge_pb.rb +222 -0
- data/lib/gen/temporal/sdk/core/child_workflow/child_workflow_pb.rb +57 -0
- data/lib/gen/temporal/sdk/core/common/common_pb.rb +22 -0
- data/lib/gen/temporal/sdk/core/core_interface_pb.rb +34 -0
- data/lib/gen/temporal/sdk/core/external_data/external_data_pb.rb +27 -0
- data/lib/gen/temporal/sdk/core/workflow_activation/workflow_activation_pb.rb +164 -0
- data/lib/gen/temporal/sdk/core/workflow_commands/workflow_commands_pb.rb +192 -0
- data/lib/gen/temporal/sdk/core/workflow_completion/workflow_completion_pb.rb +34 -0
- data/lib/temporal/bridge.rb +14 -0
- data/lib/temporal/client/implementation.rb +339 -0
- data/lib/temporal/client/workflow_handle.rb +243 -0
- data/lib/temporal/client.rb +144 -0
- data/lib/temporal/connection.rb +736 -0
- data/lib/temporal/data_converter.rb +150 -0
- data/lib/temporal/error/failure.rb +194 -0
- data/lib/temporal/error/workflow_failure.rb +17 -0
- data/lib/temporal/errors.rb +22 -0
- data/lib/temporal/failure_converter/base.rb +26 -0
- data/lib/temporal/failure_converter/basic.rb +313 -0
- data/lib/temporal/failure_converter.rb +8 -0
- data/lib/temporal/interceptor/chain.rb +27 -0
- data/lib/temporal/interceptor/client.rb +102 -0
- data/lib/temporal/payload_codec/base.rb +32 -0
- data/lib/temporal/payload_converter/base.rb +24 -0
- data/lib/temporal/payload_converter/bytes.rb +26 -0
- data/lib/temporal/payload_converter/composite.rb +47 -0
- data/lib/temporal/payload_converter/encoding_base.rb +35 -0
- data/lib/temporal/payload_converter/json.rb +25 -0
- data/lib/temporal/payload_converter/nil.rb +25 -0
- data/lib/temporal/payload_converter.rb +14 -0
- data/lib/temporal/retry_policy.rb +82 -0
- data/lib/temporal/retry_state.rb +35 -0
- data/lib/temporal/runtime.rb +22 -0
- data/lib/temporal/timeout_type.rb +29 -0
- data/lib/temporal/version.rb +3 -0
- data/lib/temporal/workflow/execution_info.rb +54 -0
- data/lib/temporal/workflow/execution_status.rb +36 -0
- data/lib/temporal/workflow/id_reuse_policy.rb +36 -0
- data/lib/temporal/workflow/query_reject_condition.rb +33 -0
- data/lib/temporal.rb +8 -0
- data/lib/temporalio.rb +3 -0
- data/lib/thermite_patch.rb +23 -0
- data/temporalio.gemspec +41 -0
- metadata +583 -0
|
@@ -0,0 +1,1294 @@
|
|
|
1
|
+
#![warn(missing_docs)] // error if there are missing docs
|
|
2
|
+
|
|
3
|
+
//! This crate contains client implementations that can be used to contact the Temporal service.
|
|
4
|
+
//!
|
|
5
|
+
//! It implements auto-retry behavior and metrics collection.
|
|
6
|
+
|
|
7
|
+
#[macro_use]
|
|
8
|
+
extern crate tracing;
|
|
9
|
+
|
|
10
|
+
mod metrics;
|
|
11
|
+
mod raw;
|
|
12
|
+
mod retry;
|
|
13
|
+
mod workflow_handle;
|
|
14
|
+
|
|
15
|
+
pub use crate::retry::{CallType, RetryClient, RETRYABLE_ERROR_CODES};
|
|
16
|
+
pub use raw::{HealthService, OperatorService, TestService, WorkflowService};
|
|
17
|
+
pub use temporal_sdk_core_protos::temporal::api::{
|
|
18
|
+
filter::v1::{StartTimeFilter, StatusFilter, WorkflowExecutionFilter, WorkflowTypeFilter},
|
|
19
|
+
workflowservice::v1::{
|
|
20
|
+
list_closed_workflow_executions_request::Filters as ListClosedFilters,
|
|
21
|
+
list_open_workflow_executions_request::Filters as ListOpenFilters,
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
pub use workflow_handle::{WorkflowExecutionInfo, WorkflowExecutionResult};
|
|
25
|
+
|
|
26
|
+
use crate::{
|
|
27
|
+
metrics::{GrpcMetricSvc, MetricsContext},
|
|
28
|
+
raw::{sealed::RawClientLike, AttachMetricLabels},
|
|
29
|
+
sealed::WfHandleClient,
|
|
30
|
+
workflow_handle::UntypedWorkflowHandle,
|
|
31
|
+
};
|
|
32
|
+
use backoff::{exponential, ExponentialBackoff, SystemClock};
|
|
33
|
+
use http::uri::InvalidUri;
|
|
34
|
+
use once_cell::sync::OnceCell;
|
|
35
|
+
use opentelemetry::metrics::Meter;
|
|
36
|
+
use parking_lot::RwLock;
|
|
37
|
+
use std::{
|
|
38
|
+
collections::HashMap,
|
|
39
|
+
fmt::{Debug, Formatter},
|
|
40
|
+
ops::{Deref, DerefMut},
|
|
41
|
+
str::FromStr,
|
|
42
|
+
sync::Arc,
|
|
43
|
+
time::{Duration, Instant},
|
|
44
|
+
};
|
|
45
|
+
use temporal_sdk_core_protos::{
|
|
46
|
+
coresdk::{workflow_commands::QueryResult, IntoPayloadsExt},
|
|
47
|
+
grpc::health::v1::health_client::HealthClient,
|
|
48
|
+
temporal::api::{
|
|
49
|
+
command::v1::Command,
|
|
50
|
+
common::v1::{Header, Payload, Payloads, WorkflowExecution, WorkflowType},
|
|
51
|
+
enums::v1::{TaskQueueKind, WorkflowIdReusePolicy, WorkflowTaskFailedCause},
|
|
52
|
+
failure::v1::Failure,
|
|
53
|
+
operatorservice::v1::operator_service_client::OperatorServiceClient,
|
|
54
|
+
query::v1::WorkflowQuery,
|
|
55
|
+
taskqueue::v1::{StickyExecutionAttributes, TaskQueue},
|
|
56
|
+
testservice::v1::test_service_client::TestServiceClient,
|
|
57
|
+
workflowservice::v1::{workflow_service_client::WorkflowServiceClient, *},
|
|
58
|
+
},
|
|
59
|
+
TaskToken,
|
|
60
|
+
};
|
|
61
|
+
use tonic::{
|
|
62
|
+
body::BoxBody,
|
|
63
|
+
client::GrpcService,
|
|
64
|
+
codegen::InterceptedService,
|
|
65
|
+
metadata::{MetadataKey, MetadataValue},
|
|
66
|
+
service::Interceptor,
|
|
67
|
+
transport::{Certificate, Channel, Endpoint, Identity},
|
|
68
|
+
Code, Status,
|
|
69
|
+
};
|
|
70
|
+
use tower::ServiceBuilder;
|
|
71
|
+
use url::Url;
|
|
72
|
+
use uuid::Uuid;
|
|
73
|
+
|
|
74
|
+
static CLIENT_NAME_HEADER_KEY: &str = "client-name";
|
|
75
|
+
static CLIENT_VERSION_HEADER_KEY: &str = "client-version";
|
|
76
|
+
/// These must match the gRPC method names, not the snake case versions that exist in the Rust code.
|
|
77
|
+
static LONG_POLL_METHOD_NAMES: [&str; 2] = ["PollWorkflowTaskQueue", "PollActivityTaskQueue"];
|
|
78
|
+
/// The server times out polls after 60 seconds. Set our timeout to be slightly beyond that.
|
|
79
|
+
const LONG_POLL_TIMEOUT: Duration = Duration::from_secs(70);
|
|
80
|
+
const OTHER_CALL_TIMEOUT: Duration = Duration::from_secs(30);
|
|
81
|
+
|
|
82
|
+
type Result<T, E = tonic::Status> = std::result::Result<T, E>;
|
|
83
|
+
|
|
84
|
+
/// Options for the connection to the temporal server. Construct with [ClientOptionsBuilder]
|
|
85
|
+
#[derive(Clone, Debug, derive_builder::Builder)]
|
|
86
|
+
#[non_exhaustive]
|
|
87
|
+
pub struct ClientOptions {
|
|
88
|
+
/// The URL of the Temporal server to connect to
|
|
89
|
+
#[builder(setter(into))]
|
|
90
|
+
pub target_url: Url,
|
|
91
|
+
|
|
92
|
+
/// The name of the SDK being implemented on top of core. Is set as `client-name` header in
|
|
93
|
+
/// all RPC calls
|
|
94
|
+
#[builder(setter(into))]
|
|
95
|
+
pub client_name: String,
|
|
96
|
+
|
|
97
|
+
/// The version of the SDK being implemented on top of core. Is set as `client-version` header
|
|
98
|
+
/// in all RPC calls. The server decides if the client is supported based on this.
|
|
99
|
+
#[builder(setter(into))]
|
|
100
|
+
pub client_version: String,
|
|
101
|
+
|
|
102
|
+
/// A human-readable string that can identify this process. Defaults to empty string.
|
|
103
|
+
#[builder(default)]
|
|
104
|
+
pub identity: String,
|
|
105
|
+
|
|
106
|
+
/// If specified, use TLS as configured by the [TlsConfig] struct. If this is set core will
|
|
107
|
+
/// attempt to use TLS when connecting to the Temporal server. Lang SDK is expected to pass any
|
|
108
|
+
/// certs or keys as bytes, loading them from disk itself if needed.
|
|
109
|
+
#[builder(setter(strip_option), default)]
|
|
110
|
+
pub tls_cfg: Option<TlsConfig>,
|
|
111
|
+
|
|
112
|
+
/// Retry configuration for the server client. Default is [RetryConfig::default]
|
|
113
|
+
#[builder(default)]
|
|
114
|
+
pub retry_config: RetryConfig,
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/// Configuration options for TLS
|
|
118
|
+
#[derive(Clone, Debug, Default)]
|
|
119
|
+
pub struct TlsConfig {
|
|
120
|
+
/// Bytes representing the root CA certificate used by the server. If not set, and the server's
|
|
121
|
+
/// cert is issued by someone the operating system trusts, verification will still work (ex:
|
|
122
|
+
/// Cloud offering).
|
|
123
|
+
pub server_root_ca_cert: Option<Vec<u8>>,
|
|
124
|
+
/// Sets the domain name against which to verify the server's TLS certificate. If not provided,
|
|
125
|
+
/// the domain name will be extracted from the URL used to connect.
|
|
126
|
+
pub domain: Option<String>,
|
|
127
|
+
/// TLS info for the client. If specified, core will attempt to use mTLS.
|
|
128
|
+
pub client_tls_config: Option<ClientTlsConfig>,
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/// If using mTLS, both the client cert and private key must be specified, this contains them.
|
|
132
|
+
#[derive(Clone)]
|
|
133
|
+
pub struct ClientTlsConfig {
|
|
134
|
+
/// The certificate for this client
|
|
135
|
+
pub client_cert: Vec<u8>,
|
|
136
|
+
/// The private key for this client
|
|
137
|
+
pub client_private_key: Vec<u8>,
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/// Configuration for retrying requests to the server
|
|
141
|
+
#[derive(Clone, Debug)]
|
|
142
|
+
pub struct RetryConfig {
|
|
143
|
+
/// initial wait time before the first retry.
|
|
144
|
+
pub initial_interval: Duration,
|
|
145
|
+
/// randomization jitter that is used as a multiplier for the current retry interval
|
|
146
|
+
/// and is added or subtracted from the interval length.
|
|
147
|
+
pub randomization_factor: f64,
|
|
148
|
+
/// rate at which retry time should be increased, until it reaches max_interval.
|
|
149
|
+
pub multiplier: f64,
|
|
150
|
+
/// maximum amount of time to wait between retries.
|
|
151
|
+
pub max_interval: Duration,
|
|
152
|
+
/// maximum total amount of time requests should be retried for, if None is set then no limit
|
|
153
|
+
/// will be used.
|
|
154
|
+
pub max_elapsed_time: Option<Duration>,
|
|
155
|
+
/// maximum number of retry attempts.
|
|
156
|
+
pub max_retries: usize,
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
impl Default for RetryConfig {
|
|
160
|
+
fn default() -> Self {
|
|
161
|
+
Self {
|
|
162
|
+
initial_interval: Duration::from_millis(100), // 100 ms wait by default.
|
|
163
|
+
randomization_factor: 0.2, // +-20% jitter.
|
|
164
|
+
multiplier: 1.5, // each next retry delay will increase by 50%
|
|
165
|
+
max_interval: Duration::from_secs(5), // until it reaches 5 seconds.
|
|
166
|
+
max_elapsed_time: Some(Duration::from_secs(10)), // 10 seconds total allocated time for all retries.
|
|
167
|
+
max_retries: 10,
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
impl RetryConfig {
|
|
173
|
+
pub(crate) const fn poll_retry_policy() -> Self {
|
|
174
|
+
Self {
|
|
175
|
+
initial_interval: Duration::from_millis(200),
|
|
176
|
+
randomization_factor: 0.2,
|
|
177
|
+
multiplier: 2.0,
|
|
178
|
+
max_interval: Duration::from_secs(10),
|
|
179
|
+
max_elapsed_time: None,
|
|
180
|
+
max_retries: 0,
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
pub(crate) fn into_exp_backoff<C>(self, clock: C) -> exponential::ExponentialBackoff<C> {
|
|
185
|
+
exponential::ExponentialBackoff {
|
|
186
|
+
current_interval: self.initial_interval,
|
|
187
|
+
initial_interval: self.initial_interval,
|
|
188
|
+
randomization_factor: self.randomization_factor,
|
|
189
|
+
multiplier: self.multiplier,
|
|
190
|
+
max_interval: self.max_interval,
|
|
191
|
+
max_elapsed_time: self.max_elapsed_time,
|
|
192
|
+
clock,
|
|
193
|
+
start_time: Instant::now(),
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
impl From<RetryConfig> for ExponentialBackoff {
|
|
199
|
+
fn from(c: RetryConfig) -> Self {
|
|
200
|
+
c.into_exp_backoff(SystemClock::default())
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
impl Debug for ClientTlsConfig {
|
|
205
|
+
// Intentionally omit details here since they could leak a key if ever printed
|
|
206
|
+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
207
|
+
write!(f, "ClientTlsConfig(..)")
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/// Errors thrown while attempting to establish a connection to the server
|
|
212
|
+
#[derive(thiserror::Error, Debug)]
|
|
213
|
+
pub enum ClientInitError {
|
|
214
|
+
/// Invalid URI. Configuration error, fatal.
|
|
215
|
+
#[error("Invalid URI: {0:?}")]
|
|
216
|
+
InvalidUri(#[from] InvalidUri),
|
|
217
|
+
/// Server connection error. Crashing and restarting the worker is likely best.
|
|
218
|
+
#[error("Server connection error: {0:?}")]
|
|
219
|
+
TonicTransportError(#[from] tonic::transport::Error),
|
|
220
|
+
/// We couldn't successfully make the `get_system_info` call at connection time to establish
|
|
221
|
+
/// server capabilities / verify server is responding.
|
|
222
|
+
#[error("`get_system_info` call error after connection: {0:?}")]
|
|
223
|
+
SystemInfoCallError(tonic::Status),
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/// A client with [ClientOptions] attached, which can be passed to initialize workers,
|
|
227
|
+
/// or can be used directly. Is cheap to clone.
|
|
228
|
+
#[derive(Clone, Debug)]
|
|
229
|
+
pub struct ConfiguredClient<C> {
|
|
230
|
+
client: C,
|
|
231
|
+
options: Arc<ClientOptions>,
|
|
232
|
+
headers: Arc<RwLock<HashMap<String, String>>>,
|
|
233
|
+
/// Capabilities as read from the `get_system_info` RPC call made on client connection
|
|
234
|
+
capabilities: Option<get_system_info_response::Capabilities>,
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
impl<C> ConfiguredClient<C> {
|
|
238
|
+
/// Set HTTP request headers overwriting previous headers
|
|
239
|
+
pub fn set_headers(&self, headers: HashMap<String, String>) {
|
|
240
|
+
let mut guard = self.headers.write();
|
|
241
|
+
*guard = headers;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/// Returns the options the client is configured with
|
|
245
|
+
pub fn options(&self) -> &ClientOptions {
|
|
246
|
+
&self.options
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/// Returns the server capabilities we (may have) learned about when establishing an initial
|
|
250
|
+
/// connection
|
|
251
|
+
pub fn capabilities(&self) -> Option<&get_system_info_response::Capabilities> {
|
|
252
|
+
self.capabilities.as_ref()
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// The configured client is effectively a "smart" (dumb) pointer
|
|
257
|
+
impl<C> Deref for ConfiguredClient<C> {
|
|
258
|
+
type Target = C;
|
|
259
|
+
|
|
260
|
+
fn deref(&self) -> &Self::Target {
|
|
261
|
+
&self.client
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
impl<C> DerefMut for ConfiguredClient<C> {
|
|
265
|
+
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
266
|
+
&mut self.client
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
impl ClientOptions {
|
|
271
|
+
/// Attempt to establish a connection to the Temporal server in a specific namespace. The
|
|
272
|
+
/// returned client is bound to that namespace.
|
|
273
|
+
pub async fn connect(
|
|
274
|
+
&self,
|
|
275
|
+
namespace: impl Into<String>,
|
|
276
|
+
metrics_meter: Option<&Meter>,
|
|
277
|
+
headers: Option<Arc<RwLock<HashMap<String, String>>>>,
|
|
278
|
+
) -> Result<RetryClient<Client>, ClientInitError> {
|
|
279
|
+
let client = self
|
|
280
|
+
.connect_no_namespace(metrics_meter, headers)
|
|
281
|
+
.await?
|
|
282
|
+
.into_inner();
|
|
283
|
+
let client = Client::new(client, namespace.into());
|
|
284
|
+
let retry_client = RetryClient::new(client, self.retry_config.clone());
|
|
285
|
+
Ok(retry_client)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/// Attempt to establish a connection to the Temporal server and return a gRPC client which is
|
|
289
|
+
/// intercepted with retry, default headers functionality, and metrics if provided.
|
|
290
|
+
///
|
|
291
|
+
/// See [RetryClient] for more
|
|
292
|
+
pub async fn connect_no_namespace(
|
|
293
|
+
&self,
|
|
294
|
+
metrics_meter: Option<&Meter>,
|
|
295
|
+
headers: Option<Arc<RwLock<HashMap<String, String>>>>,
|
|
296
|
+
) -> Result<RetryClient<ConfiguredClient<TemporalServiceClientWithMetrics>>, ClientInitError>
|
|
297
|
+
{
|
|
298
|
+
let channel = Channel::from_shared(self.target_url.to_string())?;
|
|
299
|
+
let channel = self.add_tls_to_channel(channel).await?;
|
|
300
|
+
let channel = channel.connect().await?;
|
|
301
|
+
let service = ServiceBuilder::new()
|
|
302
|
+
.layer_fn(|channel| GrpcMetricSvc {
|
|
303
|
+
inner: channel,
|
|
304
|
+
metrics: metrics_meter.map(|mm| MetricsContext::new(vec![], mm)),
|
|
305
|
+
})
|
|
306
|
+
.service(channel);
|
|
307
|
+
let headers = headers.unwrap_or_default();
|
|
308
|
+
let interceptor = ServiceCallInterceptor {
|
|
309
|
+
opts: self.clone(),
|
|
310
|
+
headers: headers.clone(),
|
|
311
|
+
};
|
|
312
|
+
let svc = InterceptedService::new(service, interceptor);
|
|
313
|
+
|
|
314
|
+
let mut client = ConfiguredClient {
|
|
315
|
+
headers,
|
|
316
|
+
client: TemporalServiceClient::new(svc),
|
|
317
|
+
options: Arc::new(self.clone()),
|
|
318
|
+
capabilities: None,
|
|
319
|
+
};
|
|
320
|
+
match client
|
|
321
|
+
.get_system_info(GetSystemInfoRequest::default())
|
|
322
|
+
.await
|
|
323
|
+
{
|
|
324
|
+
Ok(sysinfo) => {
|
|
325
|
+
client.capabilities = sysinfo.into_inner().capabilities;
|
|
326
|
+
}
|
|
327
|
+
Err(status) => match status.code() {
|
|
328
|
+
Code::Unimplemented => {}
|
|
329
|
+
_ => return Err(ClientInitError::SystemInfoCallError(status)),
|
|
330
|
+
},
|
|
331
|
+
};
|
|
332
|
+
Ok(RetryClient::new(client, self.retry_config.clone()))
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/// If TLS is configured, set the appropriate options on the provided channel and return it.
|
|
336
|
+
/// Passes it through if TLS options not set.
|
|
337
|
+
async fn add_tls_to_channel(
|
|
338
|
+
&self,
|
|
339
|
+
channel: Endpoint,
|
|
340
|
+
) -> Result<Endpoint, tonic::transport::Error> {
|
|
341
|
+
if let Some(tls_cfg) = &self.tls_cfg {
|
|
342
|
+
let mut tls = tonic::transport::ClientTlsConfig::new();
|
|
343
|
+
|
|
344
|
+
if let Some(root_cert) = &tls_cfg.server_root_ca_cert {
|
|
345
|
+
let server_root_ca_cert = Certificate::from_pem(root_cert);
|
|
346
|
+
tls = tls.ca_certificate(server_root_ca_cert);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if let Some(domain) = &tls_cfg.domain {
|
|
350
|
+
tls = tls.domain_name(domain);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if let Some(client_opts) = &tls_cfg.client_tls_config {
|
|
354
|
+
let client_identity =
|
|
355
|
+
Identity::from_pem(&client_opts.client_cert, &client_opts.client_private_key);
|
|
356
|
+
tls = tls.identity(client_identity);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return channel.tls_config(tls);
|
|
360
|
+
}
|
|
361
|
+
Ok(channel)
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/// A version of [RespondWorkflowTaskCompletedRequest] that will finish being filled out by the
|
|
366
|
+
/// server client
|
|
367
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
368
|
+
pub struct WorkflowTaskCompletion {
|
|
369
|
+
/// The task token that would've been received from polling for a workflow activation
|
|
370
|
+
pub task_token: TaskToken,
|
|
371
|
+
/// A list of new commands to send to the server, such as starting a timer.
|
|
372
|
+
pub commands: Vec<Command>,
|
|
373
|
+
/// If set, indicate that next task should be queued on sticky queue with given attributes.
|
|
374
|
+
pub sticky_attributes: Option<StickyExecutionAttributes>,
|
|
375
|
+
/// Responses to queries in the `queries` field of the workflow task.
|
|
376
|
+
pub query_responses: Vec<QueryResult>,
|
|
377
|
+
/// Indicate that the task completion should return a new WFT if one is available
|
|
378
|
+
pub return_new_workflow_task: bool,
|
|
379
|
+
/// Force a new WFT to be created after this completion
|
|
380
|
+
pub force_create_new_workflow_task: bool,
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/// Interceptor which attaches common metadata (like "client-name") to every outgoing call
|
|
384
|
+
#[derive(Clone)]
|
|
385
|
+
pub struct ServiceCallInterceptor {
|
|
386
|
+
opts: ClientOptions,
|
|
387
|
+
/// Only accessed as a reader
|
|
388
|
+
headers: Arc<RwLock<HashMap<String, String>>>,
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
impl Interceptor for ServiceCallInterceptor {
|
|
392
|
+
/// This function will get called on each outbound request. Returning a `Status` here will
|
|
393
|
+
/// cancel the request and have that status returned to the caller.
|
|
394
|
+
fn call(&mut self, mut request: tonic::Request<()>) -> Result<tonic::Request<()>, Status> {
|
|
395
|
+
let metadata = request.metadata_mut();
|
|
396
|
+
if !metadata.contains_key(CLIENT_NAME_HEADER_KEY) {
|
|
397
|
+
metadata.insert(
|
|
398
|
+
CLIENT_NAME_HEADER_KEY,
|
|
399
|
+
self.opts
|
|
400
|
+
.client_name
|
|
401
|
+
.parse()
|
|
402
|
+
.unwrap_or_else(|_| MetadataValue::from_static("")),
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
if !metadata.contains_key(CLIENT_VERSION_HEADER_KEY) {
|
|
406
|
+
metadata.insert(
|
|
407
|
+
CLIENT_VERSION_HEADER_KEY,
|
|
408
|
+
self.opts
|
|
409
|
+
.client_version
|
|
410
|
+
.parse()
|
|
411
|
+
.unwrap_or_else(|_| MetadataValue::from_static("")),
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
let headers = &*self.headers.read();
|
|
415
|
+
for (k, v) in headers {
|
|
416
|
+
if metadata.contains_key(k) {
|
|
417
|
+
// Don't overwrite per-request specified headers
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
if let (Ok(k), Ok(v)) = (MetadataKey::from_str(k), v.parse()) {
|
|
421
|
+
metadata.insert(k, v);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
if !metadata.contains_key("grpc-timeout") {
|
|
425
|
+
request.set_timeout(OTHER_CALL_TIMEOUT);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
Ok(request)
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/// Aggregates various services exposed by the Temporal server
|
|
433
|
+
#[derive(Debug, Clone)]
|
|
434
|
+
pub struct TemporalServiceClient<T> {
|
|
435
|
+
svc: T,
|
|
436
|
+
workflow_svc_client: OnceCell<WorkflowServiceClient<T>>,
|
|
437
|
+
operator_svc_client: OnceCell<OperatorServiceClient<T>>,
|
|
438
|
+
test_svc_client: OnceCell<TestServiceClient<T>>,
|
|
439
|
+
health_svc_client: OnceCell<HealthClient<T>>,
|
|
440
|
+
}
|
|
441
|
+
impl<T> TemporalServiceClient<T>
|
|
442
|
+
where
|
|
443
|
+
T: Clone,
|
|
444
|
+
T: GrpcService<BoxBody> + Send + Clone + 'static,
|
|
445
|
+
T::ResponseBody: tonic::codegen::Body<Data = tonic::codegen::Bytes> + Send + 'static,
|
|
446
|
+
T::Error: Into<tonic::codegen::StdError>,
|
|
447
|
+
<T::ResponseBody as tonic::codegen::Body>::Error: Into<tonic::codegen::StdError> + Send,
|
|
448
|
+
{
|
|
449
|
+
fn new(svc: T) -> Self {
|
|
450
|
+
Self {
|
|
451
|
+
svc,
|
|
452
|
+
workflow_svc_client: OnceCell::new(),
|
|
453
|
+
operator_svc_client: OnceCell::new(),
|
|
454
|
+
test_svc_client: OnceCell::new(),
|
|
455
|
+
health_svc_client: OnceCell::new(),
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
/// Get the underlying workflow service client
|
|
459
|
+
pub fn workflow_svc(&self) -> &WorkflowServiceClient<T> {
|
|
460
|
+
self.workflow_svc_client
|
|
461
|
+
.get_or_init(|| WorkflowServiceClient::new(self.svc.clone()))
|
|
462
|
+
}
|
|
463
|
+
/// Get the underlying operator service client
|
|
464
|
+
pub fn operator_svc(&self) -> &OperatorServiceClient<T> {
|
|
465
|
+
self.operator_svc_client
|
|
466
|
+
.get_or_init(|| OperatorServiceClient::new(self.svc.clone()))
|
|
467
|
+
}
|
|
468
|
+
/// Get the underlying test service client
|
|
469
|
+
pub fn test_svc(&self) -> &TestServiceClient<T> {
|
|
470
|
+
self.test_svc_client
|
|
471
|
+
.get_or_init(|| TestServiceClient::new(self.svc.clone()))
|
|
472
|
+
}
|
|
473
|
+
/// Get the underlying health service client
|
|
474
|
+
pub fn health_svc(&self) -> &HealthClient<T> {
|
|
475
|
+
self.health_svc_client
|
|
476
|
+
.get_or_init(|| HealthClient::new(self.svc.clone()))
|
|
477
|
+
}
|
|
478
|
+
/// Get the underlying workflow service client mutably
|
|
479
|
+
pub fn workflow_svc_mut(&mut self) -> &mut WorkflowServiceClient<T> {
|
|
480
|
+
let _ = self.workflow_svc();
|
|
481
|
+
self.workflow_svc_client.get_mut().unwrap()
|
|
482
|
+
}
|
|
483
|
+
/// Get the underlying operator service client mutably
|
|
484
|
+
pub fn operator_svc_mut(&mut self) -> &mut OperatorServiceClient<T> {
|
|
485
|
+
let _ = self.operator_svc();
|
|
486
|
+
self.operator_svc_client.get_mut().unwrap()
|
|
487
|
+
}
|
|
488
|
+
/// Get the underlying test service client mutably
|
|
489
|
+
pub fn test_svc_mut(&mut self) -> &mut TestServiceClient<T> {
|
|
490
|
+
let _ = self.test_svc();
|
|
491
|
+
self.test_svc_client.get_mut().unwrap()
|
|
492
|
+
}
|
|
493
|
+
/// Get the underlying health service client mutably
|
|
494
|
+
pub fn health_svc_mut(&mut self) -> &mut HealthClient<T> {
|
|
495
|
+
let _ = self.health_svc();
|
|
496
|
+
self.health_svc_client.get_mut().unwrap()
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
/// A [WorkflowServiceClient] with the default interceptors attached.
|
|
500
|
+
pub type WorkflowServiceClientWithMetrics = WorkflowServiceClient<InterceptedMetricsSvc>;
|
|
501
|
+
/// An [OperatorServiceClient] with the default interceptors attached.
|
|
502
|
+
pub type OperatorServiceClientWithMetrics = OperatorServiceClient<InterceptedMetricsSvc>;
|
|
503
|
+
/// An [TestServiceClient] with the default interceptors attached.
|
|
504
|
+
pub type TestServiceClientWithMetrics = TestServiceClient<InterceptedMetricsSvc>;
|
|
505
|
+
/// A [TemporalServiceClient] with the default interceptors attached.
|
|
506
|
+
pub type TemporalServiceClientWithMetrics = TemporalServiceClient<InterceptedMetricsSvc>;
|
|
507
|
+
type InterceptedMetricsSvc = InterceptedService<GrpcMetricSvc, ServiceCallInterceptor>;
|
|
508
|
+
|
|
509
|
+
/// Contains an instance of a namespace-bound client for interacting with the Temporal server
|
|
510
|
+
#[derive(Debug, Clone)]
|
|
511
|
+
pub struct Client {
|
|
512
|
+
/// Client for interacting with workflow service
|
|
513
|
+
inner: ConfiguredClient<TemporalServiceClientWithMetrics>,
|
|
514
|
+
/// The namespace this client interacts with
|
|
515
|
+
namespace: String,
|
|
516
|
+
/// If set, attach as the worker build id to relevant calls
|
|
517
|
+
bound_worker_build_id: Option<String>,
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
impl Client {
|
|
521
|
+
/// Create a new client from an existing configured lower level client and a namespace
|
|
522
|
+
pub fn new(
|
|
523
|
+
client: ConfiguredClient<TemporalServiceClientWithMetrics>,
|
|
524
|
+
namespace: String,
|
|
525
|
+
) -> Self {
|
|
526
|
+
Client {
|
|
527
|
+
inner: client,
|
|
528
|
+
namespace,
|
|
529
|
+
bound_worker_build_id: None,
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/// Return an auto-retrying version of the underling grpc client (instrumented with metrics
|
|
534
|
+
/// collection, if enabled).
|
|
535
|
+
///
|
|
536
|
+
/// Note that it is reasonably cheap to clone the returned type if you need to own it. Such
|
|
537
|
+
/// clones will keep re-using the same channel.
|
|
538
|
+
pub fn raw_retry_client(&self) -> RetryClient<WorkflowServiceClientWithMetrics> {
|
|
539
|
+
RetryClient::new(
|
|
540
|
+
self.raw_client().clone(),
|
|
541
|
+
self.inner.options.retry_config.clone(),
|
|
542
|
+
)
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/// Access the underling grpc client. This raw client is not bound to a specific namespace.
|
|
546
|
+
///
|
|
547
|
+
/// Note that it is reasonably cheap to clone the returned type if you need to own it. Such
|
|
548
|
+
/// clones will keep re-using the same channel.
|
|
549
|
+
pub fn raw_client(&self) -> &WorkflowServiceClientWithMetrics {
|
|
550
|
+
self.inner.workflow_svc()
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/// Return the options this client was initialized with
|
|
554
|
+
pub fn options(&self) -> &ClientOptions {
|
|
555
|
+
&self.inner.options
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/// Return the options this client was initialized with mutably
|
|
559
|
+
pub fn options_mut(&mut self) -> &mut ClientOptions {
|
|
560
|
+
Arc::make_mut(&mut self.inner.options)
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/// Set a worker build id to be attached to relevant requests. Unlikely to be useful outside
|
|
564
|
+
/// of core.
|
|
565
|
+
pub fn set_worker_build_id(&mut self, id: String) {
|
|
566
|
+
self.bound_worker_build_id = Some(id)
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/// Returns a reference to the underlying client
|
|
570
|
+
pub fn inner(&self) -> &ConfiguredClient<TemporalServiceClientWithMetrics> {
|
|
571
|
+
&self.inner
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/// Consumes self and returns the underlying client
|
|
575
|
+
pub fn into_inner(self) -> ConfiguredClient<TemporalServiceClientWithMetrics> {
|
|
576
|
+
self.inner
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
fn wf_svc(&self) -> WorkflowServiceClientWithMetrics {
|
|
580
|
+
self.inner.workflow_svc().clone()
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/// Enum to help reference a namespace by either the namespace name or the namespace id
|
|
585
|
+
#[derive(Clone)]
|
|
586
|
+
pub enum Namespace {
|
|
587
|
+
/// Namespace name
|
|
588
|
+
Name(String),
|
|
589
|
+
/// Namespace id
|
|
590
|
+
Id(String),
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
impl Namespace {
|
|
594
|
+
fn into_describe_namespace_request(self) -> DescribeNamespaceRequest {
|
|
595
|
+
let (namespace, id) = match self {
|
|
596
|
+
Namespace::Name(n) => (n, "".to_owned()),
|
|
597
|
+
Namespace::Id(n) => ("".to_owned(), n),
|
|
598
|
+
};
|
|
599
|
+
DescribeNamespaceRequest { namespace, id }
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/// This trait provides higher-level friendlier interaction with the server.
|
|
604
|
+
/// See the [WorkflowService] trait for a lower-level client.
|
|
605
|
+
#[cfg_attr(test, mockall::automock)]
|
|
606
|
+
#[async_trait::async_trait]
|
|
607
|
+
pub trait WorkflowClientTrait {
|
|
608
|
+
/// Starts workflow execution.
|
|
609
|
+
async fn start_workflow(
|
|
610
|
+
&self,
|
|
611
|
+
input: Vec<Payload>,
|
|
612
|
+
task_queue: String,
|
|
613
|
+
workflow_id: String,
|
|
614
|
+
workflow_type: String,
|
|
615
|
+
request_id: Option<String>,
|
|
616
|
+
options: WorkflowOptions,
|
|
617
|
+
) -> Result<StartWorkflowExecutionResponse>;
|
|
618
|
+
|
|
619
|
+
/// Notifies the server that workflow tasks for a given workflow should be sent to the normal
|
|
620
|
+
/// non-sticky task queue. This normally happens when workflow has been evicted from the cache.
|
|
621
|
+
async fn reset_sticky_task_queue(
|
|
622
|
+
&self,
|
|
623
|
+
workflow_id: String,
|
|
624
|
+
run_id: String,
|
|
625
|
+
) -> Result<ResetStickyTaskQueueResponse>;
|
|
626
|
+
|
|
627
|
+
/// Complete activity task by sending response to the server. `task_token` contains activity
|
|
628
|
+
/// identifier that would've been received from polling for an activity task. `result` is a blob
|
|
629
|
+
/// that contains activity response.
|
|
630
|
+
async fn complete_activity_task(
|
|
631
|
+
&self,
|
|
632
|
+
task_token: TaskToken,
|
|
633
|
+
result: Option<Payloads>,
|
|
634
|
+
) -> Result<RespondActivityTaskCompletedResponse>;
|
|
635
|
+
|
|
636
|
+
/// Report activity task heartbeat by sending details to the server. `task_token` contains
|
|
637
|
+
/// activity identifier that would've been received from polling for an activity task. `result`
|
|
638
|
+
/// contains `cancel_requested` flag, which if set to true indicates that activity has been
|
|
639
|
+
/// cancelled.
|
|
640
|
+
async fn record_activity_heartbeat(
|
|
641
|
+
&self,
|
|
642
|
+
task_token: TaskToken,
|
|
643
|
+
details: Option<Payloads>,
|
|
644
|
+
) -> Result<RecordActivityTaskHeartbeatResponse>;
|
|
645
|
+
|
|
646
|
+
/// Cancel activity task by sending response to the server. `task_token` contains activity
|
|
647
|
+
/// identifier that would've been received from polling for an activity task. `details` is a
|
|
648
|
+
/// blob that provides arbitrary user defined cancellation info.
|
|
649
|
+
async fn cancel_activity_task(
|
|
650
|
+
&self,
|
|
651
|
+
task_token: TaskToken,
|
|
652
|
+
details: Option<Payloads>,
|
|
653
|
+
) -> Result<RespondActivityTaskCanceledResponse>;
|
|
654
|
+
|
|
655
|
+
/// Fail activity task by sending response to the server. `task_token` contains activity
|
|
656
|
+
/// identifier that would've been received from polling for an activity task. `failure` provides
|
|
657
|
+
/// failure details, such as message, cause and stack trace.
|
|
658
|
+
async fn fail_activity_task(
|
|
659
|
+
&self,
|
|
660
|
+
task_token: TaskToken,
|
|
661
|
+
failure: Option<Failure>,
|
|
662
|
+
) -> Result<RespondActivityTaskFailedResponse>;
|
|
663
|
+
|
|
664
|
+
/// Fail task by sending the failure to the server. `task_token` is the task token that would've
|
|
665
|
+
/// been received from polling for a workflow activation.
|
|
666
|
+
async fn fail_workflow_task(
|
|
667
|
+
&self,
|
|
668
|
+
task_token: TaskToken,
|
|
669
|
+
cause: WorkflowTaskFailedCause,
|
|
670
|
+
failure: Option<Failure>,
|
|
671
|
+
) -> Result<RespondWorkflowTaskFailedResponse>;
|
|
672
|
+
|
|
673
|
+
/// Send a signal to a certain workflow instance
|
|
674
|
+
async fn signal_workflow_execution(
|
|
675
|
+
&self,
|
|
676
|
+
workflow_id: String,
|
|
677
|
+
run_id: String,
|
|
678
|
+
signal_name: String,
|
|
679
|
+
payloads: Option<Payloads>,
|
|
680
|
+
request_id: Option<String>,
|
|
681
|
+
) -> Result<SignalWorkflowExecutionResponse>;
|
|
682
|
+
|
|
683
|
+
/// Send signal and start workflow transcationally
|
|
684
|
+
//#TODO maybe lift the Signal type from sdk::workflow_context::options
|
|
685
|
+
#[allow(clippy::too_many_arguments)]
|
|
686
|
+
async fn signal_with_start_workflow_execution(
|
|
687
|
+
&self,
|
|
688
|
+
input: Option<Payloads>,
|
|
689
|
+
task_queue: String,
|
|
690
|
+
workflow_id: String,
|
|
691
|
+
workflow_type: String,
|
|
692
|
+
request_id: Option<String>,
|
|
693
|
+
options: WorkflowOptions,
|
|
694
|
+
signal_name: String,
|
|
695
|
+
signal_input: Option<Payloads>,
|
|
696
|
+
signal_header: Option<Header>,
|
|
697
|
+
) -> Result<SignalWithStartWorkflowExecutionResponse>;
|
|
698
|
+
|
|
699
|
+
/// Request a query of a certain workflow instance
|
|
700
|
+
async fn query_workflow_execution(
|
|
701
|
+
&self,
|
|
702
|
+
workflow_id: String,
|
|
703
|
+
run_id: String,
|
|
704
|
+
query: WorkflowQuery,
|
|
705
|
+
) -> Result<QueryWorkflowResponse>;
|
|
706
|
+
|
|
707
|
+
/// Get information about a workflow run
|
|
708
|
+
async fn describe_workflow_execution(
|
|
709
|
+
&self,
|
|
710
|
+
workflow_id: String,
|
|
711
|
+
run_id: Option<String>,
|
|
712
|
+
) -> Result<DescribeWorkflowExecutionResponse>;
|
|
713
|
+
|
|
714
|
+
/// Get history for a particular workflow run
|
|
715
|
+
async fn get_workflow_execution_history(
|
|
716
|
+
&self,
|
|
717
|
+
workflow_id: String,
|
|
718
|
+
run_id: Option<String>,
|
|
719
|
+
page_token: Vec<u8>,
|
|
720
|
+
) -> Result<GetWorkflowExecutionHistoryResponse>;
|
|
721
|
+
|
|
722
|
+
/// Respond to a legacy query-only workflow task
|
|
723
|
+
async fn respond_legacy_query(
|
|
724
|
+
&self,
|
|
725
|
+
task_token: TaskToken,
|
|
726
|
+
query_result: QueryResult,
|
|
727
|
+
) -> Result<RespondQueryTaskCompletedResponse>;
|
|
728
|
+
|
|
729
|
+
/// Cancel a currently executing workflow
|
|
730
|
+
async fn cancel_workflow_execution(
|
|
731
|
+
&self,
|
|
732
|
+
workflow_id: String,
|
|
733
|
+
run_id: Option<String>,
|
|
734
|
+
reason: String,
|
|
735
|
+
request_id: Option<String>,
|
|
736
|
+
) -> Result<RequestCancelWorkflowExecutionResponse>;
|
|
737
|
+
|
|
738
|
+
/// Terminate a currently executing workflow
|
|
739
|
+
async fn terminate_workflow_execution(
|
|
740
|
+
&self,
|
|
741
|
+
workflow_id: String,
|
|
742
|
+
run_id: Option<String>,
|
|
743
|
+
) -> Result<TerminateWorkflowExecutionResponse>;
|
|
744
|
+
|
|
745
|
+
/// Lists all available namespaces
|
|
746
|
+
async fn list_namespaces(&self) -> Result<ListNamespacesResponse>;
|
|
747
|
+
|
|
748
|
+
/// Query namespace details
|
|
749
|
+
async fn describe_namespace(&self, namespace: Namespace) -> Result<DescribeNamespaceResponse>;
|
|
750
|
+
|
|
751
|
+
/// List open workflows with Standard Visibility filtering
|
|
752
|
+
async fn list_open_workflow_executions(
|
|
753
|
+
&self,
|
|
754
|
+
max_page_size: i32,
|
|
755
|
+
next_page_token: Vec<u8>,
|
|
756
|
+
start_time_filter: Option<StartTimeFilter>,
|
|
757
|
+
filters: Option<ListOpenFilters>,
|
|
758
|
+
) -> Result<ListOpenWorkflowExecutionsResponse>;
|
|
759
|
+
|
|
760
|
+
/// List closed workflows Standard Visibility filtering
|
|
761
|
+
async fn list_closed_workflow_executions(
|
|
762
|
+
&self,
|
|
763
|
+
max_page_size: i32,
|
|
764
|
+
next_page_token: Vec<u8>,
|
|
765
|
+
start_time_filter: Option<StartTimeFilter>,
|
|
766
|
+
filters: Option<ListClosedFilters>,
|
|
767
|
+
) -> Result<ListClosedWorkflowExecutionsResponse>;
|
|
768
|
+
|
|
769
|
+
/// List workflows with Advanced Visibility filtering
|
|
770
|
+
async fn list_workflow_executions(
|
|
771
|
+
&self,
|
|
772
|
+
max_page_size: i32,
|
|
773
|
+
next_page_token: Vec<u8>,
|
|
774
|
+
query: String,
|
|
775
|
+
) -> Result<ListWorkflowExecutionsResponse>;
|
|
776
|
+
|
|
777
|
+
/// Returns options that were used to initialize the client
|
|
778
|
+
fn get_options(&self) -> &ClientOptions;
|
|
779
|
+
|
|
780
|
+
/// Returns the namespace this client is bound to
|
|
781
|
+
fn namespace(&self) -> &str;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
/// Optional fields supplied at the start of workflow execution
|
|
785
|
+
#[derive(Debug, Clone, Default)]
|
|
786
|
+
pub struct WorkflowOptions {
|
|
787
|
+
/// Set the policy for reusing the workflow id
|
|
788
|
+
pub id_reuse_policy: WorkflowIdReusePolicy,
|
|
789
|
+
|
|
790
|
+
/// Optionally set the execution timeout for the workflow
|
|
791
|
+
/// <https://docs.temporal.io/workflows/#workflow-execution-timeout>
|
|
792
|
+
pub execution_timeout: Option<Duration>,
|
|
793
|
+
|
|
794
|
+
/// Optionally indicates the default run timeout for a workflow run
|
|
795
|
+
pub run_timeout: Option<Duration>,
|
|
796
|
+
|
|
797
|
+
/// Optionally indicates the default task timeout for a workflow run
|
|
798
|
+
pub task_timeout: Option<Duration>,
|
|
799
|
+
|
|
800
|
+
/// Optionally set a cron schedule for the workflow
|
|
801
|
+
pub cron_schedule: Option<String>,
|
|
802
|
+
|
|
803
|
+
/// Optionally associate extra search attributes with a workflow
|
|
804
|
+
pub search_attributes: Option<HashMap<String, Payload>>,
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
#[async_trait::async_trait]
|
|
808
|
+
impl WorkflowClientTrait for Client {
|
|
809
|
+
async fn start_workflow(
|
|
810
|
+
&self,
|
|
811
|
+
input: Vec<Payload>,
|
|
812
|
+
task_queue: String,
|
|
813
|
+
workflow_id: String,
|
|
814
|
+
workflow_type: String,
|
|
815
|
+
request_id: Option<String>,
|
|
816
|
+
options: WorkflowOptions,
|
|
817
|
+
) -> Result<StartWorkflowExecutionResponse> {
|
|
818
|
+
Ok(self
|
|
819
|
+
.wf_svc()
|
|
820
|
+
.start_workflow_execution(StartWorkflowExecutionRequest {
|
|
821
|
+
namespace: self.namespace.clone(),
|
|
822
|
+
input: input.into_payloads(),
|
|
823
|
+
workflow_id,
|
|
824
|
+
workflow_type: Some(WorkflowType {
|
|
825
|
+
name: workflow_type,
|
|
826
|
+
}),
|
|
827
|
+
task_queue: Some(TaskQueue {
|
|
828
|
+
name: task_queue,
|
|
829
|
+
kind: TaskQueueKind::Unspecified as i32,
|
|
830
|
+
}),
|
|
831
|
+
request_id: request_id.unwrap_or_else(|| Uuid::new_v4().to_string()),
|
|
832
|
+
workflow_id_reuse_policy: options.id_reuse_policy as i32,
|
|
833
|
+
workflow_execution_timeout: options
|
|
834
|
+
.execution_timeout
|
|
835
|
+
.and_then(|d| d.try_into().ok()),
|
|
836
|
+
workflow_run_timeout: options.execution_timeout.and_then(|d| d.try_into().ok()),
|
|
837
|
+
workflow_task_timeout: options.task_timeout.and_then(|d| d.try_into().ok()),
|
|
838
|
+
search_attributes: options.search_attributes.and_then(|d| d.try_into().ok()),
|
|
839
|
+
cron_schedule: options.cron_schedule.unwrap_or_default(),
|
|
840
|
+
..Default::default()
|
|
841
|
+
})
|
|
842
|
+
.await?
|
|
843
|
+
.into_inner())
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
async fn reset_sticky_task_queue(
|
|
847
|
+
&self,
|
|
848
|
+
workflow_id: String,
|
|
849
|
+
run_id: String,
|
|
850
|
+
) -> Result<ResetStickyTaskQueueResponse> {
|
|
851
|
+
let request = ResetStickyTaskQueueRequest {
|
|
852
|
+
namespace: self.namespace.clone(),
|
|
853
|
+
execution: Some(WorkflowExecution {
|
|
854
|
+
workflow_id,
|
|
855
|
+
run_id,
|
|
856
|
+
}),
|
|
857
|
+
};
|
|
858
|
+
Ok(self
|
|
859
|
+
.wf_svc()
|
|
860
|
+
.reset_sticky_task_queue(request)
|
|
861
|
+
.await?
|
|
862
|
+
.into_inner())
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
async fn complete_activity_task(
|
|
866
|
+
&self,
|
|
867
|
+
task_token: TaskToken,
|
|
868
|
+
result: Option<Payloads>,
|
|
869
|
+
) -> Result<RespondActivityTaskCompletedResponse> {
|
|
870
|
+
Ok(self
|
|
871
|
+
.wf_svc()
|
|
872
|
+
.respond_activity_task_completed(RespondActivityTaskCompletedRequest {
|
|
873
|
+
task_token: task_token.0,
|
|
874
|
+
result,
|
|
875
|
+
identity: self.inner.options.identity.clone(),
|
|
876
|
+
namespace: self.namespace.clone(),
|
|
877
|
+
})
|
|
878
|
+
.await?
|
|
879
|
+
.into_inner())
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
async fn record_activity_heartbeat(
|
|
883
|
+
&self,
|
|
884
|
+
task_token: TaskToken,
|
|
885
|
+
details: Option<Payloads>,
|
|
886
|
+
) -> Result<RecordActivityTaskHeartbeatResponse> {
|
|
887
|
+
Ok(self
|
|
888
|
+
.wf_svc()
|
|
889
|
+
.record_activity_task_heartbeat(RecordActivityTaskHeartbeatRequest {
|
|
890
|
+
task_token: task_token.0,
|
|
891
|
+
details,
|
|
892
|
+
identity: self.inner.options.identity.clone(),
|
|
893
|
+
namespace: self.namespace.clone(),
|
|
894
|
+
})
|
|
895
|
+
.await?
|
|
896
|
+
.into_inner())
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
async fn cancel_activity_task(
|
|
900
|
+
&self,
|
|
901
|
+
task_token: TaskToken,
|
|
902
|
+
details: Option<Payloads>,
|
|
903
|
+
) -> Result<RespondActivityTaskCanceledResponse> {
|
|
904
|
+
Ok(self
|
|
905
|
+
.wf_svc()
|
|
906
|
+
.respond_activity_task_canceled(RespondActivityTaskCanceledRequest {
|
|
907
|
+
task_token: task_token.0,
|
|
908
|
+
details,
|
|
909
|
+
identity: self.inner.options.identity.clone(),
|
|
910
|
+
namespace: self.namespace.clone(),
|
|
911
|
+
})
|
|
912
|
+
.await?
|
|
913
|
+
.into_inner())
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
async fn fail_activity_task(
|
|
917
|
+
&self,
|
|
918
|
+
task_token: TaskToken,
|
|
919
|
+
failure: Option<Failure>,
|
|
920
|
+
) -> Result<RespondActivityTaskFailedResponse> {
|
|
921
|
+
Ok(self
|
|
922
|
+
.wf_svc()
|
|
923
|
+
.respond_activity_task_failed(RespondActivityTaskFailedRequest {
|
|
924
|
+
task_token: task_token.0,
|
|
925
|
+
failure,
|
|
926
|
+
identity: self.inner.options.identity.clone(),
|
|
927
|
+
namespace: self.namespace.clone(),
|
|
928
|
+
// TODO: Implement - https://github.com/temporalio/sdk-core/issues/293
|
|
929
|
+
last_heartbeat_details: None,
|
|
930
|
+
})
|
|
931
|
+
.await?
|
|
932
|
+
.into_inner())
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
async fn fail_workflow_task(
|
|
936
|
+
&self,
|
|
937
|
+
task_token: TaskToken,
|
|
938
|
+
cause: WorkflowTaskFailedCause,
|
|
939
|
+
failure: Option<Failure>,
|
|
940
|
+
) -> Result<RespondWorkflowTaskFailedResponse> {
|
|
941
|
+
let request = RespondWorkflowTaskFailedRequest {
|
|
942
|
+
task_token: task_token.0,
|
|
943
|
+
cause: cause as i32,
|
|
944
|
+
failure,
|
|
945
|
+
identity: self.inner.options.identity.clone(),
|
|
946
|
+
binary_checksum: self.bound_worker_build_id.clone().unwrap_or_default(),
|
|
947
|
+
namespace: self.namespace.clone(),
|
|
948
|
+
};
|
|
949
|
+
Ok(self
|
|
950
|
+
.wf_svc()
|
|
951
|
+
.respond_workflow_task_failed(request)
|
|
952
|
+
.await?
|
|
953
|
+
.into_inner())
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
async fn signal_workflow_execution(
|
|
957
|
+
&self,
|
|
958
|
+
workflow_id: String,
|
|
959
|
+
run_id: String,
|
|
960
|
+
signal_name: String,
|
|
961
|
+
payloads: Option<Payloads>,
|
|
962
|
+
request_id: Option<String>,
|
|
963
|
+
) -> Result<SignalWorkflowExecutionResponse> {
|
|
964
|
+
Ok(self
|
|
965
|
+
.wf_svc()
|
|
966
|
+
.signal_workflow_execution(SignalWorkflowExecutionRequest {
|
|
967
|
+
namespace: self.namespace.clone(),
|
|
968
|
+
workflow_execution: Some(WorkflowExecution {
|
|
969
|
+
workflow_id,
|
|
970
|
+
run_id,
|
|
971
|
+
}),
|
|
972
|
+
signal_name,
|
|
973
|
+
input: payloads,
|
|
974
|
+
identity: self.inner.options.identity.clone(),
|
|
975
|
+
request_id: request_id.unwrap_or_else(|| Uuid::new_v4().to_string()),
|
|
976
|
+
..Default::default()
|
|
977
|
+
})
|
|
978
|
+
.await?
|
|
979
|
+
.into_inner())
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
async fn signal_with_start_workflow_execution(
|
|
983
|
+
&self,
|
|
984
|
+
input: Option<Payloads>,
|
|
985
|
+
task_queue: String,
|
|
986
|
+
workflow_id: String,
|
|
987
|
+
workflow_type: String,
|
|
988
|
+
request_id: Option<String>,
|
|
989
|
+
options: WorkflowOptions,
|
|
990
|
+
signal_name: String,
|
|
991
|
+
signal_input: Option<Payloads>,
|
|
992
|
+
signal_header: Option<Header>,
|
|
993
|
+
) -> Result<SignalWithStartWorkflowExecutionResponse> {
|
|
994
|
+
Ok(self
|
|
995
|
+
.wf_svc()
|
|
996
|
+
.signal_with_start_workflow_execution(SignalWithStartWorkflowExecutionRequest {
|
|
997
|
+
namespace: self.namespace.clone(),
|
|
998
|
+
workflow_id,
|
|
999
|
+
workflow_type: Some(WorkflowType {
|
|
1000
|
+
name: workflow_type,
|
|
1001
|
+
}),
|
|
1002
|
+
task_queue: Some(TaskQueue {
|
|
1003
|
+
name: task_queue,
|
|
1004
|
+
kind: TaskQueueKind::Normal as i32,
|
|
1005
|
+
}),
|
|
1006
|
+
input,
|
|
1007
|
+
signal_name,
|
|
1008
|
+
signal_input,
|
|
1009
|
+
identity: self.inner.options.identity.clone(),
|
|
1010
|
+
request_id: request_id.unwrap_or_else(|| Uuid::new_v4().to_string()),
|
|
1011
|
+
workflow_id_reuse_policy: options.id_reuse_policy as i32,
|
|
1012
|
+
workflow_execution_timeout: options
|
|
1013
|
+
.execution_timeout
|
|
1014
|
+
.and_then(|d| d.try_into().ok()),
|
|
1015
|
+
workflow_run_timeout: options.execution_timeout.and_then(|d| d.try_into().ok()),
|
|
1016
|
+
workflow_task_timeout: options.task_timeout.and_then(|d| d.try_into().ok()),
|
|
1017
|
+
search_attributes: options.search_attributes.and_then(|d| d.try_into().ok()),
|
|
1018
|
+
cron_schedule: options.cron_schedule.unwrap_or_default(),
|
|
1019
|
+
header: signal_header,
|
|
1020
|
+
..Default::default()
|
|
1021
|
+
})
|
|
1022
|
+
.await?
|
|
1023
|
+
.into_inner())
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
async fn query_workflow_execution(
|
|
1027
|
+
&self,
|
|
1028
|
+
workflow_id: String,
|
|
1029
|
+
run_id: String,
|
|
1030
|
+
query: WorkflowQuery,
|
|
1031
|
+
) -> Result<QueryWorkflowResponse> {
|
|
1032
|
+
Ok(self
|
|
1033
|
+
.wf_svc()
|
|
1034
|
+
.query_workflow(QueryWorkflowRequest {
|
|
1035
|
+
namespace: self.namespace.clone(),
|
|
1036
|
+
execution: Some(WorkflowExecution {
|
|
1037
|
+
workflow_id,
|
|
1038
|
+
run_id,
|
|
1039
|
+
}),
|
|
1040
|
+
query: Some(query),
|
|
1041
|
+
query_reject_condition: 1,
|
|
1042
|
+
})
|
|
1043
|
+
.await?
|
|
1044
|
+
.into_inner())
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
async fn describe_workflow_execution(
|
|
1048
|
+
&self,
|
|
1049
|
+
workflow_id: String,
|
|
1050
|
+
run_id: Option<String>,
|
|
1051
|
+
) -> Result<DescribeWorkflowExecutionResponse> {
|
|
1052
|
+
Ok(self
|
|
1053
|
+
.wf_svc()
|
|
1054
|
+
.describe_workflow_execution(DescribeWorkflowExecutionRequest {
|
|
1055
|
+
namespace: self.namespace.clone(),
|
|
1056
|
+
execution: Some(WorkflowExecution {
|
|
1057
|
+
workflow_id,
|
|
1058
|
+
run_id: run_id.unwrap_or_default(),
|
|
1059
|
+
}),
|
|
1060
|
+
})
|
|
1061
|
+
.await?
|
|
1062
|
+
.into_inner())
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
async fn get_workflow_execution_history(
|
|
1066
|
+
&self,
|
|
1067
|
+
workflow_id: String,
|
|
1068
|
+
run_id: Option<String>,
|
|
1069
|
+
page_token: Vec<u8>,
|
|
1070
|
+
) -> Result<GetWorkflowExecutionHistoryResponse> {
|
|
1071
|
+
Ok(self
|
|
1072
|
+
.wf_svc()
|
|
1073
|
+
.get_workflow_execution_history(GetWorkflowExecutionHistoryRequest {
|
|
1074
|
+
namespace: self.namespace.clone(),
|
|
1075
|
+
execution: Some(WorkflowExecution {
|
|
1076
|
+
workflow_id,
|
|
1077
|
+
run_id: run_id.unwrap_or_default(),
|
|
1078
|
+
}),
|
|
1079
|
+
next_page_token: page_token,
|
|
1080
|
+
..Default::default()
|
|
1081
|
+
})
|
|
1082
|
+
.await?
|
|
1083
|
+
.into_inner())
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
async fn respond_legacy_query(
|
|
1087
|
+
&self,
|
|
1088
|
+
task_token: TaskToken,
|
|
1089
|
+
query_result: QueryResult,
|
|
1090
|
+
) -> Result<RespondQueryTaskCompletedResponse> {
|
|
1091
|
+
let (_, completed_type, query_result, error_message) = query_result.into_components();
|
|
1092
|
+
Ok(self
|
|
1093
|
+
.wf_svc()
|
|
1094
|
+
.respond_query_task_completed(RespondQueryTaskCompletedRequest {
|
|
1095
|
+
task_token: task_token.into(),
|
|
1096
|
+
completed_type: completed_type as i32,
|
|
1097
|
+
query_result,
|
|
1098
|
+
error_message,
|
|
1099
|
+
namespace: self.namespace.clone(),
|
|
1100
|
+
})
|
|
1101
|
+
.await?
|
|
1102
|
+
.into_inner())
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
async fn cancel_workflow_execution(
|
|
1106
|
+
&self,
|
|
1107
|
+
workflow_id: String,
|
|
1108
|
+
run_id: Option<String>,
|
|
1109
|
+
reason: String,
|
|
1110
|
+
request_id: Option<String>,
|
|
1111
|
+
) -> Result<RequestCancelWorkflowExecutionResponse> {
|
|
1112
|
+
Ok(self
|
|
1113
|
+
.wf_svc()
|
|
1114
|
+
.request_cancel_workflow_execution(RequestCancelWorkflowExecutionRequest {
|
|
1115
|
+
namespace: self.namespace.clone(),
|
|
1116
|
+
workflow_execution: Some(WorkflowExecution {
|
|
1117
|
+
workflow_id,
|
|
1118
|
+
run_id: run_id.unwrap_or_default(),
|
|
1119
|
+
}),
|
|
1120
|
+
identity: self.inner.options.identity.clone(),
|
|
1121
|
+
request_id: request_id.unwrap_or_else(|| Uuid::new_v4().to_string()),
|
|
1122
|
+
first_execution_run_id: "".to_string(),
|
|
1123
|
+
reason,
|
|
1124
|
+
})
|
|
1125
|
+
.await?
|
|
1126
|
+
.into_inner())
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
async fn terminate_workflow_execution(
|
|
1130
|
+
&self,
|
|
1131
|
+
workflow_id: String,
|
|
1132
|
+
run_id: Option<String>,
|
|
1133
|
+
) -> Result<TerminateWorkflowExecutionResponse> {
|
|
1134
|
+
Ok(self
|
|
1135
|
+
.wf_svc()
|
|
1136
|
+
.terminate_workflow_execution(TerminateWorkflowExecutionRequest {
|
|
1137
|
+
namespace: self.namespace.clone(),
|
|
1138
|
+
workflow_execution: Some(WorkflowExecution {
|
|
1139
|
+
workflow_id,
|
|
1140
|
+
run_id: run_id.unwrap_or_default(),
|
|
1141
|
+
}),
|
|
1142
|
+
reason: "".to_string(),
|
|
1143
|
+
details: None,
|
|
1144
|
+
identity: self.inner.options.identity.clone(),
|
|
1145
|
+
first_execution_run_id: "".to_string(),
|
|
1146
|
+
})
|
|
1147
|
+
.await?
|
|
1148
|
+
.into_inner())
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
async fn list_namespaces(&self) -> Result<ListNamespacesResponse> {
|
|
1152
|
+
Ok(self
|
|
1153
|
+
.wf_svc()
|
|
1154
|
+
.list_namespaces(ListNamespacesRequest::default())
|
|
1155
|
+
.await?
|
|
1156
|
+
.into_inner())
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
async fn describe_namespace(&self, namespace: Namespace) -> Result<DescribeNamespaceResponse> {
|
|
1160
|
+
Ok(self
|
|
1161
|
+
.wf_svc()
|
|
1162
|
+
.describe_namespace(namespace.into_describe_namespace_request())
|
|
1163
|
+
.await?
|
|
1164
|
+
.into_inner())
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
async fn list_open_workflow_executions(
|
|
1168
|
+
&self,
|
|
1169
|
+
maximum_page_size: i32,
|
|
1170
|
+
next_page_token: Vec<u8>,
|
|
1171
|
+
start_time_filter: Option<StartTimeFilter>,
|
|
1172
|
+
filters: Option<ListOpenFilters>,
|
|
1173
|
+
) -> Result<ListOpenWorkflowExecutionsResponse> {
|
|
1174
|
+
Ok(self
|
|
1175
|
+
.wf_svc()
|
|
1176
|
+
.list_open_workflow_executions(ListOpenWorkflowExecutionsRequest {
|
|
1177
|
+
namespace: self.namespace.clone(),
|
|
1178
|
+
maximum_page_size,
|
|
1179
|
+
next_page_token,
|
|
1180
|
+
start_time_filter,
|
|
1181
|
+
filters,
|
|
1182
|
+
})
|
|
1183
|
+
.await?
|
|
1184
|
+
.into_inner())
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
async fn list_closed_workflow_executions(
|
|
1188
|
+
&self,
|
|
1189
|
+
maximum_page_size: i32,
|
|
1190
|
+
next_page_token: Vec<u8>,
|
|
1191
|
+
start_time_filter: Option<StartTimeFilter>,
|
|
1192
|
+
filters: Option<ListClosedFilters>,
|
|
1193
|
+
) -> Result<ListClosedWorkflowExecutionsResponse> {
|
|
1194
|
+
Ok(self
|
|
1195
|
+
.wf_svc()
|
|
1196
|
+
.list_closed_workflow_executions(ListClosedWorkflowExecutionsRequest {
|
|
1197
|
+
namespace: self.namespace.clone(),
|
|
1198
|
+
maximum_page_size,
|
|
1199
|
+
next_page_token,
|
|
1200
|
+
start_time_filter,
|
|
1201
|
+
filters,
|
|
1202
|
+
})
|
|
1203
|
+
.await?
|
|
1204
|
+
.into_inner())
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
async fn list_workflow_executions(
|
|
1208
|
+
&self,
|
|
1209
|
+
page_size: i32,
|
|
1210
|
+
next_page_token: Vec<u8>,
|
|
1211
|
+
query: String,
|
|
1212
|
+
) -> Result<ListWorkflowExecutionsResponse> {
|
|
1213
|
+
Ok(self
|
|
1214
|
+
.wf_svc()
|
|
1215
|
+
.list_workflow_executions(ListWorkflowExecutionsRequest {
|
|
1216
|
+
namespace: self.namespace.clone(),
|
|
1217
|
+
page_size,
|
|
1218
|
+
next_page_token,
|
|
1219
|
+
query,
|
|
1220
|
+
})
|
|
1221
|
+
.await?
|
|
1222
|
+
.into_inner())
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
fn get_options(&self) -> &ClientOptions {
|
|
1226
|
+
&self.inner.options
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
fn namespace(&self) -> &str {
|
|
1230
|
+
&self.namespace
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
mod sealed {
|
|
1235
|
+
use crate::{InterceptedMetricsSvc, RawClientLike, WorkflowClientTrait};
|
|
1236
|
+
|
|
1237
|
+
pub trait WfHandleClient:
|
|
1238
|
+
WorkflowClientTrait + RawClientLike<SvcType = InterceptedMetricsSvc>
|
|
1239
|
+
{
|
|
1240
|
+
}
|
|
1241
|
+
impl<T> WfHandleClient for T where
|
|
1242
|
+
T: WorkflowClientTrait + RawClientLike<SvcType = InterceptedMetricsSvc>
|
|
1243
|
+
{
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
/// Additional methods for workflow clients
|
|
1248
|
+
pub trait WfClientExt: WfHandleClient + Sized + Clone {
|
|
1249
|
+
/// Create an untyped handle for a workflow execution, which can be used to do things like
|
|
1250
|
+
/// wait for that workflow's result. `run_id` may be left blank to target the latest run.
|
|
1251
|
+
fn get_untyped_workflow_handle(
|
|
1252
|
+
&self,
|
|
1253
|
+
workflow_id: impl Into<String>,
|
|
1254
|
+
run_id: impl Into<String>,
|
|
1255
|
+
) -> UntypedWorkflowHandle<Self> {
|
|
1256
|
+
let rid = run_id.into();
|
|
1257
|
+
UntypedWorkflowHandle::new(
|
|
1258
|
+
self.clone(),
|
|
1259
|
+
WorkflowExecutionInfo {
|
|
1260
|
+
namespace: self.namespace().to_string(),
|
|
1261
|
+
workflow_id: workflow_id.into(),
|
|
1262
|
+
run_id: if rid.is_empty() { None } else { Some(rid) },
|
|
1263
|
+
},
|
|
1264
|
+
)
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
impl<T> WfClientExt for T where T: WfHandleClient + Clone + Sized {}
|
|
1268
|
+
|
|
1269
|
+
#[cfg(test)]
|
|
1270
|
+
mod tests {
|
|
1271
|
+
use super::*;
|
|
1272
|
+
|
|
1273
|
+
#[test]
|
|
1274
|
+
fn respects_per_call_headers() {
|
|
1275
|
+
let opts = ClientOptionsBuilder::default()
|
|
1276
|
+
.identity("enchicat".to_string())
|
|
1277
|
+
.target_url(Url::parse("https://smolkitty").unwrap())
|
|
1278
|
+
.client_name("cute-kitty".to_string())
|
|
1279
|
+
.client_version("0.1.0".to_string())
|
|
1280
|
+
.build()
|
|
1281
|
+
.unwrap();
|
|
1282
|
+
|
|
1283
|
+
let mut static_headers = HashMap::new();
|
|
1284
|
+
static_headers.insert("enchi".to_string(), "kitty".to_string());
|
|
1285
|
+
let mut iceptor = ServiceCallInterceptor {
|
|
1286
|
+
opts,
|
|
1287
|
+
headers: Arc::new(RwLock::new(static_headers)),
|
|
1288
|
+
};
|
|
1289
|
+
let mut req = tonic::Request::new(());
|
|
1290
|
+
req.metadata_mut().insert("enchi", "cat".parse().unwrap());
|
|
1291
|
+
let next_req = iceptor.call(req).unwrap();
|
|
1292
|
+
assert_eq!(next_req.metadata().get("enchi").unwrap(), "cat");
|
|
1293
|
+
}
|
|
1294
|
+
}
|