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,792 @@
|
|
1
|
+
#![warn(missing_docs)] // error if there are missing docs
|
2
|
+
|
3
|
+
//! This crate defines an alpha-stage Temporal Rust SDK.
|
4
|
+
//!
|
5
|
+
//! Currently defining activities and running an activity-only worker is the most stable code.
|
6
|
+
//! Workflow definitions exist and running a workflow worker works, but the API is still very
|
7
|
+
//! unstable.
|
8
|
+
//!
|
9
|
+
//! An example of running an activity worker:
|
10
|
+
//! ```no_run
|
11
|
+
//! use std::{str::FromStr, sync::Arc};
|
12
|
+
//! use temporal_sdk::{sdk_client_options, ActContext, Worker};
|
13
|
+
//! use temporal_sdk_core::{init_worker, telemetry_init, TelemetryOptionsBuilder, Url};
|
14
|
+
//! use temporal_sdk_core_api::worker::WorkerConfigBuilder;
|
15
|
+
//!
|
16
|
+
//! #[tokio::main]
|
17
|
+
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
18
|
+
//! let server_options = sdk_client_options(Url::from_str("http://localhost:7233")?).build()?;
|
19
|
+
//!
|
20
|
+
//! let client = server_options.connect("default", None, None).await?;
|
21
|
+
//!
|
22
|
+
//! let telemetry_options = TelemetryOptionsBuilder::default().build()?;
|
23
|
+
//! telemetry_init(&telemetry_options)?;
|
24
|
+
//!
|
25
|
+
//! let worker_config = WorkerConfigBuilder::default()
|
26
|
+
//! .namespace("default")
|
27
|
+
//! .task_queue("task_queue")
|
28
|
+
//! .build()?;
|
29
|
+
//!
|
30
|
+
//! let core_worker = init_worker(worker_config, client);
|
31
|
+
//!
|
32
|
+
//! let mut worker = Worker::new_from_core(Arc::new(core_worker), "task_queue");
|
33
|
+
//! worker.register_activity(
|
34
|
+
//! "echo_activity",
|
35
|
+
//! |_ctx: ActContext, echo_me: String| async move { Ok(echo_me) },
|
36
|
+
//! );
|
37
|
+
//!
|
38
|
+
//! worker.run().await?;
|
39
|
+
//!
|
40
|
+
//! Ok(())
|
41
|
+
//! }
|
42
|
+
//! ```
|
43
|
+
|
44
|
+
#[macro_use]
|
45
|
+
extern crate tracing;
|
46
|
+
|
47
|
+
mod activity_context;
|
48
|
+
mod app_data;
|
49
|
+
mod conversions;
|
50
|
+
pub mod interceptors;
|
51
|
+
mod payload_converter;
|
52
|
+
mod workflow_context;
|
53
|
+
mod workflow_future;
|
54
|
+
|
55
|
+
pub use activity_context::ActContext;
|
56
|
+
pub use temporal_client::Namespace;
|
57
|
+
pub use workflow_context::{
|
58
|
+
ActivityOptions, CancellableFuture, ChildWorkflow, ChildWorkflowOptions, LocalActivityOptions,
|
59
|
+
Signal, SignalData, SignalWorkflowOptions, WfContext,
|
60
|
+
};
|
61
|
+
|
62
|
+
use crate::{
|
63
|
+
interceptors::WorkerInterceptor,
|
64
|
+
workflow_context::{ChildWfCommon, PendingChildWorkflow},
|
65
|
+
};
|
66
|
+
use anyhow::{anyhow, bail, Context};
|
67
|
+
use app_data::AppData;
|
68
|
+
use futures::{future::BoxFuture, FutureExt, StreamExt, TryFutureExt, TryStreamExt};
|
69
|
+
use std::{
|
70
|
+
cell::RefCell,
|
71
|
+
collections::HashMap,
|
72
|
+
fmt::{Debug, Display, Formatter},
|
73
|
+
future::Future,
|
74
|
+
sync::Arc,
|
75
|
+
};
|
76
|
+
use temporal_client::ClientOptionsBuilder;
|
77
|
+
use temporal_sdk_core::Url;
|
78
|
+
use temporal_sdk_core_api::{
|
79
|
+
errors::{PollActivityError, PollWfError},
|
80
|
+
Worker as CoreWorker,
|
81
|
+
};
|
82
|
+
use temporal_sdk_core_protos::{
|
83
|
+
coresdk::{
|
84
|
+
activity_result::{ActivityExecutionResult, ActivityResolution},
|
85
|
+
activity_task::{activity_task, ActivityTask},
|
86
|
+
child_workflow::ChildWorkflowResult,
|
87
|
+
common::NamespacedWorkflowExecution,
|
88
|
+
workflow_activation::{
|
89
|
+
resolve_child_workflow_execution_start::Status as ChildWorkflowStartStatus,
|
90
|
+
workflow_activation_job::Variant, WorkflowActivation, WorkflowActivationJob,
|
91
|
+
},
|
92
|
+
workflow_commands::{workflow_command, ContinueAsNewWorkflowExecution},
|
93
|
+
workflow_completion::WorkflowActivationCompletion,
|
94
|
+
ActivityTaskCompletion, AsJsonPayloadExt, FromJsonPayloadExt,
|
95
|
+
},
|
96
|
+
temporal::api::{common::v1::Payload, failure::v1::Failure},
|
97
|
+
TaskToken,
|
98
|
+
};
|
99
|
+
use tokio::{
|
100
|
+
sync::{
|
101
|
+
mpsc::{unbounded_channel, UnboundedSender},
|
102
|
+
oneshot,
|
103
|
+
},
|
104
|
+
task::JoinError,
|
105
|
+
};
|
106
|
+
use tokio_stream::wrappers::UnboundedReceiverStream;
|
107
|
+
use tokio_util::sync::CancellationToken;
|
108
|
+
|
109
|
+
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
110
|
+
|
111
|
+
/// Returns a [ClientOptionsBuilder] with required fields set to appropriate values
|
112
|
+
/// for the Rust SDK.
|
113
|
+
pub fn sdk_client_options(url: impl Into<Url>) -> ClientOptionsBuilder {
|
114
|
+
let mut builder = ClientOptionsBuilder::default();
|
115
|
+
builder
|
116
|
+
.target_url(url)
|
117
|
+
.client_name("rust-sdk".to_string())
|
118
|
+
.client_version(VERSION.to_string());
|
119
|
+
|
120
|
+
builder
|
121
|
+
}
|
122
|
+
|
123
|
+
/// A worker that can poll for and respond to workflow tasks by using [WorkflowFunction]s,
|
124
|
+
/// and activity tasks by using [ActivityFunction]s
|
125
|
+
pub struct Worker {
|
126
|
+
common: CommonWorker,
|
127
|
+
workflow_half: WorkflowHalf,
|
128
|
+
activity_half: ActivityHalf,
|
129
|
+
app_data: Option<AppData>,
|
130
|
+
}
|
131
|
+
|
132
|
+
struct CommonWorker {
|
133
|
+
worker: Arc<dyn CoreWorker>,
|
134
|
+
task_queue: String,
|
135
|
+
worker_interceptor: Option<Box<dyn WorkerInterceptor>>,
|
136
|
+
}
|
137
|
+
|
138
|
+
struct WorkflowHalf {
|
139
|
+
/// Maps run id to cached workflow state
|
140
|
+
workflows: RefCell<HashMap<String, WorkflowData>>,
|
141
|
+
/// Maps workflow type to the function for executing workflow runs with that ID
|
142
|
+
workflow_fns: RefCell<HashMap<String, WorkflowFunction>>,
|
143
|
+
}
|
144
|
+
struct WorkflowData {
|
145
|
+
/// Channel used to send the workflow activations
|
146
|
+
activation_chan: UnboundedSender<WorkflowActivation>,
|
147
|
+
}
|
148
|
+
|
149
|
+
struct WorkflowFutureHandle<F: Future<Output = Result<WorkflowResult<()>, JoinError>>> {
|
150
|
+
join_handle: F,
|
151
|
+
run_id: String,
|
152
|
+
}
|
153
|
+
|
154
|
+
struct ActivityHalf {
|
155
|
+
/// Maps activity type to the function for executing activities of that type
|
156
|
+
activity_fns: HashMap<String, ActivityFunction>,
|
157
|
+
task_tokens_to_cancels: HashMap<TaskToken, CancellationToken>,
|
158
|
+
}
|
159
|
+
|
160
|
+
impl Worker {
|
161
|
+
/// Create a new Rust SDK worker from a core worker
|
162
|
+
pub fn new_from_core(worker: Arc<dyn CoreWorker>, task_queue: impl Into<String>) -> Self {
|
163
|
+
Self {
|
164
|
+
common: CommonWorker {
|
165
|
+
worker,
|
166
|
+
task_queue: task_queue.into(),
|
167
|
+
worker_interceptor: None,
|
168
|
+
},
|
169
|
+
workflow_half: WorkflowHalf {
|
170
|
+
workflows: Default::default(),
|
171
|
+
workflow_fns: Default::default(),
|
172
|
+
},
|
173
|
+
activity_half: ActivityHalf {
|
174
|
+
activity_fns: Default::default(),
|
175
|
+
task_tokens_to_cancels: Default::default(),
|
176
|
+
},
|
177
|
+
app_data: Some(Default::default()),
|
178
|
+
}
|
179
|
+
}
|
180
|
+
|
181
|
+
/// Returns the task queue name this worker polls on
|
182
|
+
pub fn task_queue(&self) -> &str {
|
183
|
+
&self.common.task_queue
|
184
|
+
}
|
185
|
+
|
186
|
+
/// Return a handle that can be used to initiate shutdown.
|
187
|
+
/// TODO: Doc better after shutdown changes
|
188
|
+
pub fn shutdown_handle(&self) -> impl Fn() {
|
189
|
+
let w = self.common.worker.clone();
|
190
|
+
move || w.initiate_shutdown()
|
191
|
+
}
|
192
|
+
|
193
|
+
/// Register a Workflow function to invoke when the Worker is asked to run a workflow of
|
194
|
+
/// `workflow_type`
|
195
|
+
pub fn register_wf<F: Into<WorkflowFunction>>(
|
196
|
+
&mut self,
|
197
|
+
workflow_type: impl Into<String>,
|
198
|
+
wf_function: F,
|
199
|
+
) {
|
200
|
+
self.workflow_half
|
201
|
+
.workflow_fns
|
202
|
+
.get_mut()
|
203
|
+
.insert(workflow_type.into(), wf_function.into());
|
204
|
+
}
|
205
|
+
|
206
|
+
/// Register an Activity function to invoke when the Worker is asked to run an activity of
|
207
|
+
/// `activity_type`
|
208
|
+
pub fn register_activity<A, R, O>(
|
209
|
+
&mut self,
|
210
|
+
activity_type: impl Into<String>,
|
211
|
+
act_function: impl IntoActivityFunc<A, R, O>,
|
212
|
+
) {
|
213
|
+
self.activity_half.activity_fns.insert(
|
214
|
+
activity_type.into(),
|
215
|
+
ActivityFunction {
|
216
|
+
act_func: act_function.into_activity_fn(),
|
217
|
+
},
|
218
|
+
);
|
219
|
+
}
|
220
|
+
|
221
|
+
/// Insert Custom App Context for Workflows and Activities
|
222
|
+
pub fn insert_app_data<T: Send + Sync + 'static>(&mut self, data: T) {
|
223
|
+
self.app_data.as_mut().map(|a| a.insert(data));
|
224
|
+
}
|
225
|
+
|
226
|
+
/// Runs the worker. Eventually resolves after the worker has been explicitly shut down,
|
227
|
+
/// or may return early with an error in the event of some unresolvable problem.
|
228
|
+
pub async fn run(&mut self) -> Result<(), anyhow::Error> {
|
229
|
+
let shutdown_token = CancellationToken::new();
|
230
|
+
let (common, wf_half, act_half, app_data) = self.split_apart();
|
231
|
+
let safe_app_data = Arc::new(
|
232
|
+
app_data
|
233
|
+
.take()
|
234
|
+
.ok_or_else(|| anyhow!("app_data should exist on run"))?,
|
235
|
+
);
|
236
|
+
let (wf_future_tx, wf_future_rx) = unbounded_channel();
|
237
|
+
let (completions_tx, completions_rx) = unbounded_channel();
|
238
|
+
let wf_future_joiner = async {
|
239
|
+
UnboundedReceiverStream::new(wf_future_rx)
|
240
|
+
.map(Result::<_, anyhow::Error>::Ok)
|
241
|
+
.try_for_each_concurrent(
|
242
|
+
None,
|
243
|
+
|WorkflowFutureHandle {
|
244
|
+
join_handle,
|
245
|
+
run_id,
|
246
|
+
}| {
|
247
|
+
let wf_half = &*wf_half;
|
248
|
+
async move {
|
249
|
+
join_handle.await??;
|
250
|
+
info!(run_id=%run_id, "Removing workflow from cache");
|
251
|
+
wf_half.workflows.borrow_mut().remove(&run_id);
|
252
|
+
Ok(())
|
253
|
+
}
|
254
|
+
},
|
255
|
+
)
|
256
|
+
.await
|
257
|
+
.context("Workflow futures encountered an error")
|
258
|
+
};
|
259
|
+
let wf_completion_processor = async {
|
260
|
+
UnboundedReceiverStream::new(completions_rx)
|
261
|
+
.map(Ok)
|
262
|
+
.try_for_each_concurrent(None, |completion| async {
|
263
|
+
if let Some(ref i) = common.worker_interceptor {
|
264
|
+
i.on_workflow_activation_completion(&completion).await;
|
265
|
+
}
|
266
|
+
common.worker.complete_workflow_activation(completion).await
|
267
|
+
})
|
268
|
+
.map_err(anyhow::Error::from)
|
269
|
+
.await
|
270
|
+
.context("Workflow completions processor encountered an error")
|
271
|
+
};
|
272
|
+
tokio::try_join!(
|
273
|
+
// Workflow polling loop
|
274
|
+
async {
|
275
|
+
loop {
|
276
|
+
let activation = match common.worker.poll_workflow_activation().await {
|
277
|
+
Err(PollWfError::ShutDown) => {
|
278
|
+
break;
|
279
|
+
}
|
280
|
+
o => o?,
|
281
|
+
};
|
282
|
+
if let Some(wf_fut) = wf_half.workflow_activation_handler(
|
283
|
+
common,
|
284
|
+
shutdown_token.clone(),
|
285
|
+
activation,
|
286
|
+
&completions_tx,
|
287
|
+
)? {
|
288
|
+
if wf_future_tx.send(wf_fut).is_err() {
|
289
|
+
panic!(
|
290
|
+
"Receive half of completion processor channel cannot be dropped"
|
291
|
+
);
|
292
|
+
}
|
293
|
+
}
|
294
|
+
}
|
295
|
+
// Tell still-alive workflows to evict themselves
|
296
|
+
shutdown_token.cancel();
|
297
|
+
// It's important to drop these so the future and completion processors will
|
298
|
+
// terminate.
|
299
|
+
drop(wf_future_tx);
|
300
|
+
drop(completions_tx);
|
301
|
+
Result::<_, anyhow::Error>::Ok(())
|
302
|
+
},
|
303
|
+
// Only poll on the activity queue if activity functions have been registered. This
|
304
|
+
// makes tests which use mocks dramatically more manageable.
|
305
|
+
async {
|
306
|
+
if !act_half.activity_fns.is_empty() {
|
307
|
+
let shutdown_token = shutdown_token.clone();
|
308
|
+
loop {
|
309
|
+
tokio::select! {
|
310
|
+
activity = common.worker.poll_activity_task() => {
|
311
|
+
if matches!(activity, Err(PollActivityError::ShutDown)) {
|
312
|
+
break;
|
313
|
+
}
|
314
|
+
act_half.activity_task_handler(
|
315
|
+
common.worker.clone(),
|
316
|
+
safe_app_data.clone(),
|
317
|
+
common.task_queue.clone(),
|
318
|
+
activity?
|
319
|
+
)?;
|
320
|
+
},
|
321
|
+
_ = shutdown_token.cancelled() => { break }
|
322
|
+
}
|
323
|
+
}
|
324
|
+
};
|
325
|
+
Result::<_, anyhow::Error>::Ok(())
|
326
|
+
},
|
327
|
+
wf_future_joiner,
|
328
|
+
wf_completion_processor,
|
329
|
+
)?;
|
330
|
+
|
331
|
+
info!("Polling loops exited");
|
332
|
+
if let Some(i) = self.common.worker_interceptor.as_ref() {
|
333
|
+
i.on_shutdown(self);
|
334
|
+
}
|
335
|
+
self.common.worker.shutdown().await;
|
336
|
+
self.app_data = Some(
|
337
|
+
Arc::try_unwrap(safe_app_data)
|
338
|
+
.map_err(|_| anyhow!("some references of AppData exist on worker shutdown"))?,
|
339
|
+
);
|
340
|
+
Ok(())
|
341
|
+
}
|
342
|
+
|
343
|
+
/// Set a [WorkerInterceptor]
|
344
|
+
pub fn set_worker_interceptor(&mut self, interceptor: Box<dyn WorkerInterceptor>) {
|
345
|
+
self.common.worker_interceptor = Some(interceptor);
|
346
|
+
}
|
347
|
+
|
348
|
+
/// Turns this rust worker into a new worker with all the same workflows and activities
|
349
|
+
/// registered, but with a new underlying core worker. Can be used to swap the worker for
|
350
|
+
/// a replay worker, change task queues, etc.
|
351
|
+
pub fn with_new_core_worker(&mut self, new_core_worker: Arc<dyn CoreWorker>) {
|
352
|
+
self.common.worker = new_core_worker;
|
353
|
+
}
|
354
|
+
|
355
|
+
/// Returns number of currently cached workflows as understood by the SDK. Importantly, this
|
356
|
+
/// is not the same as understood by core, though they *should* always be in sync.
|
357
|
+
pub fn cached_workflows(&self) -> usize {
|
358
|
+
self.workflow_half.workflows.borrow().len()
|
359
|
+
}
|
360
|
+
|
361
|
+
fn split_apart(
|
362
|
+
&mut self,
|
363
|
+
) -> (
|
364
|
+
&mut CommonWorker,
|
365
|
+
&mut WorkflowHalf,
|
366
|
+
&mut ActivityHalf,
|
367
|
+
&mut Option<AppData>,
|
368
|
+
) {
|
369
|
+
(
|
370
|
+
&mut self.common,
|
371
|
+
&mut self.workflow_half,
|
372
|
+
&mut self.activity_half,
|
373
|
+
&mut self.app_data,
|
374
|
+
)
|
375
|
+
}
|
376
|
+
}
|
377
|
+
|
378
|
+
impl WorkflowHalf {
|
379
|
+
fn workflow_activation_handler(
|
380
|
+
&self,
|
381
|
+
common: &CommonWorker,
|
382
|
+
shutdown_token: CancellationToken,
|
383
|
+
activation: WorkflowActivation,
|
384
|
+
completions_tx: &UnboundedSender<WorkflowActivationCompletion>,
|
385
|
+
) -> Result<
|
386
|
+
Option<WorkflowFutureHandle<impl Future<Output = Result<WorkflowResult<()>, JoinError>>>>,
|
387
|
+
anyhow::Error,
|
388
|
+
> {
|
389
|
+
let mut res = None;
|
390
|
+
let run_id = activation.run_id.clone();
|
391
|
+
|
392
|
+
// If the activation is to start a workflow, create a new workflow driver for it,
|
393
|
+
// using the function associated with that workflow id
|
394
|
+
if let Some(WorkflowActivationJob {
|
395
|
+
variant: Some(Variant::StartWorkflow(sw)),
|
396
|
+
}) = activation.jobs.get(0)
|
397
|
+
{
|
398
|
+
let workflow_type = &sw.workflow_type;
|
399
|
+
let wf_fns_borrow = self.workflow_fns.borrow();
|
400
|
+
let wf_function = wf_fns_borrow
|
401
|
+
.get(workflow_type)
|
402
|
+
.ok_or_else(|| anyhow!("Workflow type {workflow_type} not found"))?;
|
403
|
+
|
404
|
+
let (wff, activations) = wf_function.start_workflow(
|
405
|
+
common.worker.get_config().namespace.clone(),
|
406
|
+
common.task_queue.clone(),
|
407
|
+
// NOTE: Don't clone args if this gets ported to be a non-test rust worker
|
408
|
+
sw.arguments.clone(),
|
409
|
+
completions_tx.clone(),
|
410
|
+
);
|
411
|
+
let jh = tokio::spawn(async move {
|
412
|
+
tokio::select! {
|
413
|
+
r = wff => r,
|
414
|
+
// TODO: This probably shouldn't abort early, as it could cause an in-progress
|
415
|
+
// complete to abort. Send synthetic remove activation
|
416
|
+
_ = shutdown_token.cancelled() => {
|
417
|
+
Ok(WfExitValue::Evicted)
|
418
|
+
}
|
419
|
+
}
|
420
|
+
});
|
421
|
+
res = Some(WorkflowFutureHandle {
|
422
|
+
join_handle: jh,
|
423
|
+
run_id: run_id.clone(),
|
424
|
+
});
|
425
|
+
self.workflows.borrow_mut().insert(
|
426
|
+
run_id.clone(),
|
427
|
+
WorkflowData {
|
428
|
+
activation_chan: activations,
|
429
|
+
},
|
430
|
+
);
|
431
|
+
}
|
432
|
+
|
433
|
+
// The activation is expected to apply to some workflow we know about. Use it to
|
434
|
+
// unblock things and advance the workflow.
|
435
|
+
if let Some(dat) = self.workflows.borrow_mut().get_mut(&run_id) {
|
436
|
+
dat.activation_chan
|
437
|
+
.send(activation)
|
438
|
+
.expect("Workflow should exist if we're sending it an activation");
|
439
|
+
} else {
|
440
|
+
bail!(
|
441
|
+
"Got activation {:?} for unknown workflow {}",
|
442
|
+
activation,
|
443
|
+
run_id
|
444
|
+
);
|
445
|
+
};
|
446
|
+
|
447
|
+
Ok(res)
|
448
|
+
}
|
449
|
+
}
|
450
|
+
|
451
|
+
impl ActivityHalf {
|
452
|
+
/// Spawns off a task to handle the provided activity task
|
453
|
+
fn activity_task_handler(
|
454
|
+
&mut self,
|
455
|
+
worker: Arc<dyn CoreWorker>,
|
456
|
+
app_data: Arc<AppData>,
|
457
|
+
task_queue: String,
|
458
|
+
activity: ActivityTask,
|
459
|
+
) -> Result<(), anyhow::Error> {
|
460
|
+
match activity.variant {
|
461
|
+
Some(activity_task::Variant::Start(start)) => {
|
462
|
+
let act_fn = self
|
463
|
+
.activity_fns
|
464
|
+
.get(&start.activity_type)
|
465
|
+
.ok_or_else(|| {
|
466
|
+
anyhow!(
|
467
|
+
"No function registered for activity type {}",
|
468
|
+
start.activity_type
|
469
|
+
)
|
470
|
+
})?
|
471
|
+
.clone();
|
472
|
+
let ct = CancellationToken::new();
|
473
|
+
let task_token = activity.task_token;
|
474
|
+
self.task_tokens_to_cancels
|
475
|
+
.insert(task_token.clone().into(), ct.clone());
|
476
|
+
|
477
|
+
let (ctx, arg) = ActContext::new(
|
478
|
+
worker.clone(),
|
479
|
+
app_data,
|
480
|
+
ct,
|
481
|
+
task_queue,
|
482
|
+
task_token.clone(),
|
483
|
+
start,
|
484
|
+
);
|
485
|
+
tokio::spawn(async move {
|
486
|
+
let output = (act_fn.act_func)(ctx, arg).await;
|
487
|
+
let result = match output {
|
488
|
+
Ok(ActExitValue::Normal(p)) => ActivityExecutionResult::ok(p),
|
489
|
+
Ok(ActExitValue::WillCompleteAsync) => {
|
490
|
+
ActivityExecutionResult::will_complete_async()
|
491
|
+
}
|
492
|
+
Err(err) => match err.downcast::<ActivityCancelledError>() {
|
493
|
+
Ok(ce) => ActivityExecutionResult::cancel_from_details(ce.details),
|
494
|
+
Err(other_err) => ActivityExecutionResult::fail(other_err.into()),
|
495
|
+
},
|
496
|
+
};
|
497
|
+
worker
|
498
|
+
.complete_activity_task(ActivityTaskCompletion {
|
499
|
+
task_token,
|
500
|
+
result: Some(result),
|
501
|
+
})
|
502
|
+
.await?;
|
503
|
+
Ok::<_, anyhow::Error>(())
|
504
|
+
});
|
505
|
+
}
|
506
|
+
Some(activity_task::Variant::Cancel(_)) => {
|
507
|
+
if let Some(ct) = self.task_tokens_to_cancels.get(&activity.task_token.into()) {
|
508
|
+
ct.cancel();
|
509
|
+
}
|
510
|
+
}
|
511
|
+
None => bail!("Undefined activity task variant"),
|
512
|
+
}
|
513
|
+
Ok(())
|
514
|
+
}
|
515
|
+
}
|
516
|
+
|
517
|
+
#[derive(Debug)]
|
518
|
+
enum UnblockEvent {
|
519
|
+
Timer(u32, TimerResult),
|
520
|
+
Activity(u32, Box<ActivityResolution>),
|
521
|
+
WorkflowStart(u32, Box<ChildWorkflowStartStatus>),
|
522
|
+
WorkflowComplete(u32, Box<ChildWorkflowResult>),
|
523
|
+
SignalExternal(u32, Option<Failure>),
|
524
|
+
CancelExternal(u32, Option<Failure>),
|
525
|
+
}
|
526
|
+
|
527
|
+
/// Result of awaiting on a timer
|
528
|
+
#[derive(Debug, Copy, Clone)]
|
529
|
+
pub enum TimerResult {
|
530
|
+
/// The timer was cancelled
|
531
|
+
Cancelled,
|
532
|
+
/// The timer elapsed and fired
|
533
|
+
Fired,
|
534
|
+
}
|
535
|
+
|
536
|
+
/// Successful result of sending a signal to an external workflow
|
537
|
+
pub struct SignalExternalOk;
|
538
|
+
/// Result of awaiting on sending a signal to an external workflow
|
539
|
+
pub type SignalExternalWfResult = Result<SignalExternalOk, Failure>;
|
540
|
+
|
541
|
+
/// Successful result of sending a cancel request to an external workflow
|
542
|
+
pub struct CancelExternalOk;
|
543
|
+
/// Result of awaiting on sending a cancel request to an external workflow
|
544
|
+
pub type CancelExternalWfResult = Result<CancelExternalOk, Failure>;
|
545
|
+
|
546
|
+
trait Unblockable {
|
547
|
+
type OtherDat;
|
548
|
+
|
549
|
+
fn unblock(ue: UnblockEvent, od: Self::OtherDat) -> Self;
|
550
|
+
}
|
551
|
+
|
552
|
+
impl Unblockable for TimerResult {
|
553
|
+
type OtherDat = ();
|
554
|
+
fn unblock(ue: UnblockEvent, _: Self::OtherDat) -> Self {
|
555
|
+
match ue {
|
556
|
+
UnblockEvent::Timer(_, result) => result,
|
557
|
+
_ => panic!("Invalid unblock event for timer"),
|
558
|
+
}
|
559
|
+
}
|
560
|
+
}
|
561
|
+
|
562
|
+
impl Unblockable for ActivityResolution {
|
563
|
+
type OtherDat = ();
|
564
|
+
fn unblock(ue: UnblockEvent, _: Self::OtherDat) -> Self {
|
565
|
+
match ue {
|
566
|
+
UnblockEvent::Activity(_, result) => *result,
|
567
|
+
_ => panic!("Invalid unblock event for activity"),
|
568
|
+
}
|
569
|
+
}
|
570
|
+
}
|
571
|
+
|
572
|
+
impl Unblockable for PendingChildWorkflow {
|
573
|
+
// Other data here is workflow id
|
574
|
+
type OtherDat = ChildWfCommon;
|
575
|
+
fn unblock(ue: UnblockEvent, od: Self::OtherDat) -> Self {
|
576
|
+
match ue {
|
577
|
+
UnblockEvent::WorkflowStart(_, result) => Self {
|
578
|
+
status: *result,
|
579
|
+
common: od,
|
580
|
+
},
|
581
|
+
_ => panic!("Invalid unblock event for child workflow start"),
|
582
|
+
}
|
583
|
+
}
|
584
|
+
}
|
585
|
+
|
586
|
+
impl Unblockable for ChildWorkflowResult {
|
587
|
+
type OtherDat = ();
|
588
|
+
fn unblock(ue: UnblockEvent, _: Self::OtherDat) -> Self {
|
589
|
+
match ue {
|
590
|
+
UnblockEvent::WorkflowComplete(_, result) => *result,
|
591
|
+
_ => panic!("Invalid unblock event for child workflow complete"),
|
592
|
+
}
|
593
|
+
}
|
594
|
+
}
|
595
|
+
|
596
|
+
impl Unblockable for SignalExternalWfResult {
|
597
|
+
type OtherDat = ();
|
598
|
+
fn unblock(ue: UnblockEvent, _: Self::OtherDat) -> Self {
|
599
|
+
match ue {
|
600
|
+
UnblockEvent::SignalExternal(_, maybefail) => {
|
601
|
+
maybefail.map_or(Ok(SignalExternalOk), Err)
|
602
|
+
}
|
603
|
+
_ => panic!("Invalid unblock event for signal external workflow result"),
|
604
|
+
}
|
605
|
+
}
|
606
|
+
}
|
607
|
+
|
608
|
+
impl Unblockable for CancelExternalWfResult {
|
609
|
+
type OtherDat = ();
|
610
|
+
fn unblock(ue: UnblockEvent, _: Self::OtherDat) -> Self {
|
611
|
+
match ue {
|
612
|
+
UnblockEvent::CancelExternal(_, maybefail) => {
|
613
|
+
maybefail.map_or(Ok(CancelExternalOk), Err)
|
614
|
+
}
|
615
|
+
_ => panic!("Invalid unblock event for signal external workflow result"),
|
616
|
+
}
|
617
|
+
}
|
618
|
+
}
|
619
|
+
|
620
|
+
/// Identifier for cancellable operations
|
621
|
+
#[derive(Debug, Clone)]
|
622
|
+
pub enum CancellableID {
|
623
|
+
/// Timer sequence number
|
624
|
+
Timer(u32),
|
625
|
+
/// Activity sequence number
|
626
|
+
Activity(u32),
|
627
|
+
/// Activity sequence number
|
628
|
+
LocalActivity(u32),
|
629
|
+
/// Start child sequence number
|
630
|
+
ChildWorkflow(u32),
|
631
|
+
/// Signal workflow
|
632
|
+
SignalExternalWorkflow(u32),
|
633
|
+
/// An external workflow identifier as may have been created by a started child workflow
|
634
|
+
ExternalWorkflow {
|
635
|
+
/// Sequence number which will be used for the cancel command
|
636
|
+
seqnum: u32,
|
637
|
+
/// Identifying information about the workflow to be cancelled
|
638
|
+
execution: NamespacedWorkflowExecution,
|
639
|
+
/// Set to true if this workflow is a child of the issuing workflow
|
640
|
+
only_child: bool,
|
641
|
+
},
|
642
|
+
}
|
643
|
+
|
644
|
+
#[derive(derive_more::From)]
|
645
|
+
#[allow(clippy::large_enum_variant)]
|
646
|
+
enum RustWfCmd {
|
647
|
+
#[from(ignore)]
|
648
|
+
Cancel(CancellableID),
|
649
|
+
ForceWFTFailure(anyhow::Error),
|
650
|
+
NewCmd(CommandCreateRequest),
|
651
|
+
NewNonblockingCmd(workflow_command::Variant),
|
652
|
+
SubscribeChildWorkflowCompletion(CommandSubscribeChildWorkflowCompletion),
|
653
|
+
SubscribeSignal(String, UnboundedSender<SignalData>),
|
654
|
+
}
|
655
|
+
|
656
|
+
struct CommandCreateRequest {
|
657
|
+
cmd: workflow_command::Variant,
|
658
|
+
unblocker: oneshot::Sender<UnblockEvent>,
|
659
|
+
}
|
660
|
+
|
661
|
+
struct CommandSubscribeChildWorkflowCompletion {
|
662
|
+
seq: u32,
|
663
|
+
unblocker: oneshot::Sender<UnblockEvent>,
|
664
|
+
}
|
665
|
+
|
666
|
+
type WfFunc = dyn Fn(WfContext) -> BoxFuture<'static, WorkflowResult<()>> + Send + Sync + 'static;
|
667
|
+
|
668
|
+
/// The user's async function / workflow code
|
669
|
+
pub struct WorkflowFunction {
|
670
|
+
wf_func: Box<WfFunc>,
|
671
|
+
}
|
672
|
+
|
673
|
+
impl<F, Fut> From<F> for WorkflowFunction
|
674
|
+
where
|
675
|
+
F: Fn(WfContext) -> Fut + Send + Sync + 'static,
|
676
|
+
Fut: Future<Output = WorkflowResult<()>> + Send + 'static,
|
677
|
+
{
|
678
|
+
fn from(wf_func: F) -> Self {
|
679
|
+
Self::new(wf_func)
|
680
|
+
}
|
681
|
+
}
|
682
|
+
|
683
|
+
impl WorkflowFunction {
|
684
|
+
/// Build a workflow function from a closure or function pointer which accepts a [WfContext]
|
685
|
+
pub fn new<F, Fut>(wf_func: F) -> Self
|
686
|
+
where
|
687
|
+
F: Fn(WfContext) -> Fut + Send + Sync + 'static,
|
688
|
+
Fut: Future<Output = WorkflowResult<()>> + Send + 'static,
|
689
|
+
{
|
690
|
+
Self {
|
691
|
+
wf_func: Box::new(move |ctx: WfContext| wf_func(ctx).boxed()),
|
692
|
+
}
|
693
|
+
}
|
694
|
+
}
|
695
|
+
|
696
|
+
/// The result of running a workflow
|
697
|
+
pub type WorkflowResult<T> = Result<WfExitValue<T>, anyhow::Error>;
|
698
|
+
|
699
|
+
/// Workflow functions may return these values when exiting
|
700
|
+
#[derive(Debug, derive_more::From)]
|
701
|
+
pub enum WfExitValue<T: Debug> {
|
702
|
+
/// Continue the workflow as a new execution
|
703
|
+
#[from(ignore)]
|
704
|
+
ContinueAsNew(Box<ContinueAsNewWorkflowExecution>),
|
705
|
+
/// Confirm the workflow was cancelled (can be automatic in a more advanced iteration)
|
706
|
+
#[from(ignore)]
|
707
|
+
Cancelled,
|
708
|
+
/// The run was evicted
|
709
|
+
#[from(ignore)]
|
710
|
+
Evicted,
|
711
|
+
/// Finish with a result
|
712
|
+
Normal(T),
|
713
|
+
}
|
714
|
+
|
715
|
+
impl<T: Debug> WfExitValue<T> {
|
716
|
+
/// Construct a [WfExitValue::ContinueAsNew] variant (handles boxing)
|
717
|
+
pub fn continue_as_new(can: ContinueAsNewWorkflowExecution) -> Self {
|
718
|
+
Self::ContinueAsNew(Box::new(can))
|
719
|
+
}
|
720
|
+
}
|
721
|
+
|
722
|
+
/// Activity functions may return these values when exiting
|
723
|
+
#[derive(derive_more::From)]
|
724
|
+
pub enum ActExitValue<T: Debug> {
|
725
|
+
/// Completion requires an asynchronous callback
|
726
|
+
#[from(ignore)]
|
727
|
+
WillCompleteAsync,
|
728
|
+
/// Finish with a result
|
729
|
+
Normal(T),
|
730
|
+
}
|
731
|
+
|
732
|
+
type BoxActFn = Arc<
|
733
|
+
dyn Fn(ActContext, Payload) -> BoxFuture<'static, Result<ActExitValue<Payload>, anyhow::Error>>
|
734
|
+
+ Send
|
735
|
+
+ Sync,
|
736
|
+
>;
|
737
|
+
|
738
|
+
/// Container for user-defined activity functions
|
739
|
+
#[derive(Clone)]
|
740
|
+
pub struct ActivityFunction {
|
741
|
+
act_func: BoxActFn,
|
742
|
+
}
|
743
|
+
|
744
|
+
/// Return this error to indicate your activity is cancelling
|
745
|
+
#[derive(Debug, Default)]
|
746
|
+
pub struct ActivityCancelledError {
|
747
|
+
details: Option<Payload>,
|
748
|
+
}
|
749
|
+
impl std::error::Error for ActivityCancelledError {}
|
750
|
+
impl Display for ActivityCancelledError {
|
751
|
+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
752
|
+
write!(f, "Activity cancelled")
|
753
|
+
}
|
754
|
+
}
|
755
|
+
|
756
|
+
/// Closures / functions which can be turned into activity functions implement this trait
|
757
|
+
pub trait IntoActivityFunc<Args, Res, Out> {
|
758
|
+
/// Consume the closure or fn pointer and turned it into a boxed activity function
|
759
|
+
fn into_activity_fn(self) -> BoxActFn;
|
760
|
+
}
|
761
|
+
|
762
|
+
impl<A, Rf, R, O, F> IntoActivityFunc<A, Rf, O> for F
|
763
|
+
where
|
764
|
+
F: (Fn(ActContext, A) -> Rf) + Sync + Send + 'static,
|
765
|
+
A: FromJsonPayloadExt + Send,
|
766
|
+
Rf: Future<Output = Result<R, anyhow::Error>> + Send + 'static,
|
767
|
+
R: Into<ActExitValue<O>>,
|
768
|
+
O: AsJsonPayloadExt + Debug,
|
769
|
+
{
|
770
|
+
fn into_activity_fn(self) -> BoxActFn {
|
771
|
+
let wrapper = move |ctx: ActContext, input: Payload| {
|
772
|
+
// Some minor gymnastics are required to avoid needing to clone the function
|
773
|
+
match A::from_json_payload(&input) {
|
774
|
+
Ok(deser) => (self)(ctx, deser)
|
775
|
+
.map(|r| {
|
776
|
+
r.and_then(|r| {
|
777
|
+
let exit_val: ActExitValue<O> = r.into();
|
778
|
+
Ok(match exit_val {
|
779
|
+
ActExitValue::WillCompleteAsync => ActExitValue::WillCompleteAsync,
|
780
|
+
ActExitValue::Normal(x) => {
|
781
|
+
ActExitValue::Normal(x.as_json_payload()?)
|
782
|
+
}
|
783
|
+
})
|
784
|
+
})
|
785
|
+
})
|
786
|
+
.boxed(),
|
787
|
+
Err(e) => async move { Err(e.into()) }.boxed(),
|
788
|
+
}
|
789
|
+
};
|
790
|
+
Arc::new(wrapper)
|
791
|
+
}
|
792
|
+
}
|