temporalio 0.0.0 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +301 -0
- data/bridge/Cargo.lock +2888 -0
- data/bridge/Cargo.toml +27 -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 +104 -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/client/Cargo.toml +40 -0
- data/bridge/sdk-core/client/LICENSE.txt +23 -0
- data/bridge/sdk-core/client/src/lib.rs +1286 -0
- data/bridge/sdk-core/client/src/metrics.rs +165 -0
- data/bridge/sdk-core/client/src/raw.rs +932 -0
- data/bridge/sdk-core/client/src/retry.rs +751 -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 +76 -0
- data/bridge/sdk-core/core/src/abstractions.rs +166 -0
- data/bridge/sdk-core/core/src/core_tests/activity_tasks.rs +1014 -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 +925 -0
- data/bridge/sdk-core/core/src/core_tests/mod.rs +100 -0
- data/bridge/sdk-core/core/src/core_tests/queries.rs +894 -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 +2090 -0
- data/bridge/sdk-core/core/src/ephemeral_server/mod.rs +515 -0
- data/bridge/sdk-core/core/src/lib.rs +282 -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 +215 -0
- data/bridge/sdk-core/core/src/retry_logic.rs +202 -0
- data/bridge/sdk-core/core/src/telemetry/log_export.rs +190 -0
- data/bridge/sdk-core/core/src/telemetry/metrics.rs +428 -0
- data/bridge/sdk-core/core/src/telemetry/mod.rs +407 -0
- data/bridge/sdk-core/core/src/telemetry/prometheus_server.rs +78 -0
- data/bridge/sdk-core/core/src/test_help/mod.rs +889 -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 +1048 -0
- data/bridge/sdk-core/core/src/worker/activities.rs +481 -0
- data/bridge/sdk-core/core/src/worker/client/mocks.rs +87 -0
- data/bridge/sdk-core/core/src/worker/client.rs +373 -0
- data/bridge/sdk-core/core/src/worker/mod.rs +570 -0
- data/bridge/sdk-core/core/src/worker/workflow/bridge.rs +37 -0
- data/bridge/sdk-core/core/src/worker/workflow/driven_workflow.rs +101 -0
- data/bridge/sdk-core/core/src/worker/workflow/history_update.rs +532 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +907 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +294 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +167 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +858 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +136 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +157 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +129 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +1450 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/mod.rs +316 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +178 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +708 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +439 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +435 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +175 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +242 -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 +1200 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +272 -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 +655 -0
- data/bridge/sdk-core/core/src/worker/workflow/mod.rs +1200 -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 +985 -0
- data/bridge/sdk-core/core-api/Cargo.toml +32 -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 +109 -0
- data/bridge/sdk-core/core-api/src/telemetry.rs +147 -0
- data/bridge/sdk-core/core-api/src/worker.rs +148 -0
- data/bridge/sdk-core/etc/deps.svg +162 -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/etc/regen-depgraph.sh +5 -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/evict_while_la_running_no_interference-23_history.bin +0 -0
- data/bridge/sdk-core/histories/evict_while_la_running_no_interference-85_history.bin +0 -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 +9 -0
- data/bridge/sdk-core/protos/api_upstream/build/go.mod +7 -0
- data/bridge/sdk-core/protos/api_upstream/build/go.sum +5 -0
- data/bridge/sdk-core/protos/api_upstream/build/tools.go +29 -0
- data/bridge/sdk-core/protos/api_upstream/dependencies/gogoproto/gogo.proto +141 -0
- data/bridge/sdk-core/protos/api_upstream/go.mod +6 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +89 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +260 -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 +47 -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 +56 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +170 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +118 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/interaction_type.proto +39 -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 +40 -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 +758 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +87 -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 +121 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +80 -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 +379 -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/version/v1/message.proto +59 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +146 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +1168 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +415 -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/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 +263 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +304 -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/interceptors.rs +50 -0
- data/bridge/sdk-core/sdk/src/lib.rs +794 -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 +694 -0
- data/bridge/sdk-core/sdk/src/workflow_future.rs +499 -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 +107 -0
- data/bridge/sdk-core/sdk-core-protos/src/constants.rs +7 -0
- data/bridge/sdk-core/sdk-core-protos/src/history_builder.rs +544 -0
- data/bridge/sdk-core/sdk-core-protos/src/history_info.rs +230 -0
- data/bridge/sdk-core/sdk-core-protos/src/lib.rs +1970 -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 +36 -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 +650 -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 +221 -0
- data/bridge/sdk-core/tests/integ_tests/metrics_tests.rs +37 -0
- data/bridge/sdk-core/tests/integ_tests/polling_tests.rs +133 -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 +788 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +53 -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 +223 -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 +597 -0
- data/bridge/sdk-core/tests/load_tests.rs +191 -0
- data/bridge/sdk-core/tests/main.rs +113 -0
- data/bridge/sdk-core/tests/runner.rs +93 -0
- data/bridge/src/connection.rs +186 -0
- data/bridge/src/lib.rs +239 -0
- data/bridge/src/runtime.rs +54 -0
- data/bridge/src/worker.rs +124 -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 +50 -0
- data/lib/gen/temporal/api/command/v1/message_pb.rb +174 -0
- data/lib/gen/temporal/api/common/v1/message_pb.rb +69 -0
- data/lib/gen/temporal/api/enums/v1/batch_operation_pb.rb +33 -0
- data/lib/gen/temporal/api/enums/v1/command_type_pb.rb +39 -0
- data/lib/gen/temporal/api/enums/v1/common_pb.rb +42 -0
- data/lib/gen/temporal/api/enums/v1/event_type_pb.rb +68 -0
- data/lib/gen/temporal/api/enums/v1/failed_cause_pb.rb +77 -0
- data/lib/gen/temporal/api/enums/v1/interaction_type_pb.rb +25 -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 +23 -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 +490 -0
- data/lib/gen/temporal/api/interaction/v1/message_pb.rb +49 -0
- data/lib/gen/temporal/api/namespace/v1/message_pb.rb +63 -0
- data/lib/gen/temporal/api/operatorservice/v1/request_response_pb.rb +85 -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 +149 -0
- data/lib/gen/temporal/api/taskqueue/v1/message_pb.rb +73 -0
- data/lib/gen/temporal/api/version/v1/message_pb.rb +41 -0
- data/lib/gen/temporal/api/workflow/v1/message_pb.rb +111 -0
- data/lib/gen/temporal/api/workflowservice/v1/request_response_pb.rb +788 -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 +165 -0
- data/lib/gen/temporal/sdk/core/workflow_commands/workflow_commands_pb.rb +196 -0
- data/lib/gen/temporal/sdk/core/workflow_completion/workflow_completion_pb.rb +34 -0
- data/lib/temporalio/activity/context.rb +97 -0
- data/lib/temporalio/activity/info.rb +67 -0
- data/lib/temporalio/activity.rb +85 -0
- data/lib/temporalio/bridge/error.rb +8 -0
- data/lib/temporalio/bridge.rb +14 -0
- data/lib/temporalio/client/implementation.rb +340 -0
- data/lib/temporalio/client/workflow_handle.rb +243 -0
- data/lib/temporalio/client.rb +131 -0
- data/lib/temporalio/connection.rb +751 -0
- data/lib/temporalio/data_converter.rb +191 -0
- data/lib/temporalio/error/failure.rb +194 -0
- data/lib/temporalio/error/workflow_failure.rb +19 -0
- data/lib/temporalio/errors.rb +40 -0
- data/lib/temporalio/failure_converter/base.rb +26 -0
- data/lib/temporalio/failure_converter/basic.rb +319 -0
- data/lib/temporalio/failure_converter.rb +7 -0
- data/lib/temporalio/interceptor/chain.rb +28 -0
- data/lib/temporalio/interceptor/client.rb +123 -0
- data/lib/temporalio/payload_codec/base.rb +32 -0
- data/lib/temporalio/payload_converter/base.rb +24 -0
- data/lib/temporalio/payload_converter/bytes.rb +27 -0
- data/lib/temporalio/payload_converter/composite.rb +49 -0
- data/lib/temporalio/payload_converter/encoding_base.rb +35 -0
- data/lib/temporalio/payload_converter/json.rb +26 -0
- data/lib/temporalio/payload_converter/nil.rb +26 -0
- data/lib/temporalio/payload_converter.rb +14 -0
- data/lib/temporalio/retry_policy.rb +82 -0
- data/lib/temporalio/retry_state.rb +35 -0
- data/lib/temporalio/runtime.rb +25 -0
- data/lib/temporalio/timeout_type.rb +29 -0
- data/lib/temporalio/version.rb +3 -0
- data/lib/temporalio/worker/activity_runner.rb +92 -0
- data/lib/temporalio/worker/activity_worker.rb +138 -0
- data/lib/temporalio/worker/reactor.rb +46 -0
- data/lib/temporalio/worker/runner.rb +63 -0
- data/lib/temporalio/worker/sync_worker.rb +88 -0
- data/lib/temporalio/worker/thread_pool_executor.rb +51 -0
- data/lib/temporalio/worker.rb +198 -0
- data/lib/temporalio/workflow/execution_info.rb +54 -0
- data/lib/temporalio/workflow/execution_status.rb +36 -0
- data/lib/temporalio/workflow/id_reuse_policy.rb +36 -0
- data/lib/temporalio/workflow/query_reject_condition.rb +33 -0
- data/lib/temporalio.rb +12 -1
- data/lib/thermite_patch.rb +23 -0
- data/temporalio.gemspec +45 -0
- metadata +566 -9
- data/lib/temporal/version.rb +0 -3
- data/lib/temporal.rb +0 -4
- data/temporal.gemspec +0 -20
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
use crate::{
|
|
2
|
+
worker::{LocalActivityExecutionResult, LEGACY_QUERY_ID},
|
|
3
|
+
CompleteActivityError, TaskToken,
|
|
4
|
+
};
|
|
5
|
+
use anyhow::anyhow;
|
|
6
|
+
use std::{
|
|
7
|
+
collections::HashMap,
|
|
8
|
+
convert::TryFrom,
|
|
9
|
+
fmt::{Debug, Display, Formatter},
|
|
10
|
+
time::{Duration, SystemTime},
|
|
11
|
+
};
|
|
12
|
+
use temporal_sdk_core_protos::{
|
|
13
|
+
constants::{LOCAL_ACTIVITY_MARKER_NAME, PATCH_MARKER_NAME},
|
|
14
|
+
coresdk::{
|
|
15
|
+
activity_result::{activity_execution_result, activity_execution_result::Status},
|
|
16
|
+
common::{
|
|
17
|
+
decode_change_marker_details, extract_local_activity_marker_data,
|
|
18
|
+
extract_local_activity_marker_details,
|
|
19
|
+
},
|
|
20
|
+
external_data::LocalActivityMarkerData,
|
|
21
|
+
workflow_activation::{
|
|
22
|
+
query_to_job, workflow_activation_job, QueryWorkflow, WorkflowActivation,
|
|
23
|
+
WorkflowActivationJob,
|
|
24
|
+
},
|
|
25
|
+
workflow_commands::{
|
|
26
|
+
query_result, ActivityCancellationType, QueryResult, ScheduleLocalActivity,
|
|
27
|
+
},
|
|
28
|
+
workflow_completion,
|
|
29
|
+
},
|
|
30
|
+
temporal::api::{
|
|
31
|
+
common::v1::{Payload, RetryPolicy, WorkflowExecution},
|
|
32
|
+
enums::v1::EventType,
|
|
33
|
+
failure::v1::Failure,
|
|
34
|
+
history::v1::{history_event, History, HistoryEvent, MarkerRecordedEventAttributes},
|
|
35
|
+
query::v1::WorkflowQuery,
|
|
36
|
+
workflowservice::v1::PollWorkflowTaskQueueResponse,
|
|
37
|
+
},
|
|
38
|
+
utilities::TryIntoOrNone,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/// A validated version of a [PollWorkflowTaskQueueResponse]
|
|
42
|
+
#[derive(Clone, PartialEq)]
|
|
43
|
+
#[allow(clippy::manual_non_exhaustive)] // Clippy doesn't understand it's only for *in* this crate
|
|
44
|
+
pub struct ValidPollWFTQResponse {
|
|
45
|
+
pub task_token: TaskToken,
|
|
46
|
+
pub task_queue: String,
|
|
47
|
+
pub workflow_execution: WorkflowExecution,
|
|
48
|
+
pub workflow_type: String,
|
|
49
|
+
pub history: History,
|
|
50
|
+
pub next_page_token: Vec<u8>,
|
|
51
|
+
pub attempt: u32,
|
|
52
|
+
pub previous_started_event_id: i64,
|
|
53
|
+
pub started_event_id: i64,
|
|
54
|
+
/// If this is present, `history` will be empty. This is not a very "tight" design, but it's
|
|
55
|
+
/// enforced at construction time. From the `query` field.
|
|
56
|
+
pub legacy_query: Option<WorkflowQuery>,
|
|
57
|
+
/// Query requests from the `queries` field
|
|
58
|
+
pub query_requests: Vec<QueryWorkflow>,
|
|
59
|
+
|
|
60
|
+
/// Zero-size field to prevent explicit construction
|
|
61
|
+
_cant_construct_me: (),
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
impl Debug for ValidPollWFTQResponse {
|
|
65
|
+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
66
|
+
write!(
|
|
67
|
+
f,
|
|
68
|
+
"ValidWFT {{ task_token: {}, task_queue: {}, workflow_execution: {:?}, \
|
|
69
|
+
workflow_type: {}, attempt: {}, previous_started_event_id: {}, started_event_id {}, \
|
|
70
|
+
history_length: {}, first_evt_in_hist_id: {:?}, legacy_query: {:?}, queries: {:?} }}",
|
|
71
|
+
self.task_token,
|
|
72
|
+
self.task_queue,
|
|
73
|
+
self.workflow_execution,
|
|
74
|
+
self.workflow_type,
|
|
75
|
+
self.attempt,
|
|
76
|
+
self.previous_started_event_id,
|
|
77
|
+
self.started_event_id,
|
|
78
|
+
self.history.events.len(),
|
|
79
|
+
self.history.events.get(0).map(|e| e.event_id),
|
|
80
|
+
self.legacy_query,
|
|
81
|
+
self.query_requests
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
impl TryFrom<PollWorkflowTaskQueueResponse> for ValidPollWFTQResponse {
|
|
87
|
+
/// We return the poll response itself if it was invalid
|
|
88
|
+
type Error = PollWorkflowTaskQueueResponse;
|
|
89
|
+
|
|
90
|
+
fn try_from(value: PollWorkflowTaskQueueResponse) -> Result<Self, Self::Error> {
|
|
91
|
+
match value {
|
|
92
|
+
PollWorkflowTaskQueueResponse {
|
|
93
|
+
task_token,
|
|
94
|
+
workflow_execution_task_queue: Some(tq),
|
|
95
|
+
workflow_execution: Some(workflow_execution),
|
|
96
|
+
workflow_type: Some(workflow_type),
|
|
97
|
+
history: Some(history),
|
|
98
|
+
next_page_token,
|
|
99
|
+
attempt,
|
|
100
|
+
previous_started_event_id,
|
|
101
|
+
started_event_id,
|
|
102
|
+
query,
|
|
103
|
+
queries,
|
|
104
|
+
..
|
|
105
|
+
} => {
|
|
106
|
+
let query_requests = queries
|
|
107
|
+
.into_iter()
|
|
108
|
+
.map(|(id, q)| query_to_job(id, q))
|
|
109
|
+
.collect();
|
|
110
|
+
|
|
111
|
+
Ok(Self {
|
|
112
|
+
task_token: TaskToken(task_token),
|
|
113
|
+
task_queue: tq.name,
|
|
114
|
+
workflow_execution,
|
|
115
|
+
workflow_type: workflow_type.name,
|
|
116
|
+
history,
|
|
117
|
+
next_page_token,
|
|
118
|
+
attempt: attempt as u32,
|
|
119
|
+
previous_started_event_id,
|
|
120
|
+
started_event_id,
|
|
121
|
+
legacy_query: query,
|
|
122
|
+
query_requests,
|
|
123
|
+
_cant_construct_me: (),
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
_ => Err(value),
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
pub(crate) trait WorkflowActivationExt {
|
|
132
|
+
/// Returns true if this activation has one and only one job to perform a legacy query
|
|
133
|
+
fn is_legacy_query(&self) -> bool;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
impl WorkflowActivationExt for WorkflowActivation {
|
|
137
|
+
fn is_legacy_query(&self) -> bool {
|
|
138
|
+
matches!(&self.jobs.as_slice(), &[WorkflowActivationJob {
|
|
139
|
+
variant: Some(workflow_activation_job::Variant::QueryWorkflow(qr))
|
|
140
|
+
}] if qr.query_id == LEGACY_QUERY_ID)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/// Create a legacy query failure result
|
|
145
|
+
pub(crate) fn legacy_query_failure(fail: workflow_completion::Failure) -> QueryResult {
|
|
146
|
+
QueryResult {
|
|
147
|
+
query_id: LEGACY_QUERY_ID.to_string(),
|
|
148
|
+
variant: Some(query_result::Variant::Failed(
|
|
149
|
+
fail.failure.unwrap_or_default(),
|
|
150
|
+
)),
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
pub(crate) trait HistoryEventExt {
|
|
155
|
+
/// If this history event represents a `patched` marker, return the info about
|
|
156
|
+
/// it. Returns `None` if it is any other kind of event or marker.
|
|
157
|
+
fn get_patch_marker_details(&self) -> Option<(String, bool)>;
|
|
158
|
+
/// If this history event represents a local activity marker, return true.
|
|
159
|
+
fn is_local_activity_marker(&self) -> bool;
|
|
160
|
+
/// If this history event represents a local activity marker, return the marker id info.
|
|
161
|
+
/// Returns `None` if it is any other kind of event or marker or the data is invalid.
|
|
162
|
+
fn extract_local_activity_marker_data(&self) -> Option<LocalActivityMarkerData>;
|
|
163
|
+
/// If this history event represents a local activity marker, return all the contained data.
|
|
164
|
+
/// Returns `None` if it is any other kind of event or marker or the data is invalid.
|
|
165
|
+
fn into_local_activity_marker_details(self) -> Option<CompleteLocalActivityData>;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
impl HistoryEventExt for HistoryEvent {
|
|
169
|
+
fn get_patch_marker_details(&self) -> Option<(String, bool)> {
|
|
170
|
+
if self.event_type() == EventType::MarkerRecorded {
|
|
171
|
+
match &self.attributes {
|
|
172
|
+
Some(history_event::Attributes::MarkerRecordedEventAttributes(
|
|
173
|
+
MarkerRecordedEventAttributes {
|
|
174
|
+
marker_name,
|
|
175
|
+
details,
|
|
176
|
+
..
|
|
177
|
+
},
|
|
178
|
+
)) if marker_name == PATCH_MARKER_NAME => decode_change_marker_details(details),
|
|
179
|
+
_ => None,
|
|
180
|
+
}
|
|
181
|
+
} else {
|
|
182
|
+
None
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
fn is_local_activity_marker(&self) -> bool {
|
|
187
|
+
if self.event_type() == EventType::MarkerRecorded {
|
|
188
|
+
return matches!(&self.attributes,
|
|
189
|
+
Some(history_event::Attributes::MarkerRecordedEventAttributes(
|
|
190
|
+
MarkerRecordedEventAttributes { marker_name, .. },
|
|
191
|
+
)) if marker_name == LOCAL_ACTIVITY_MARKER_NAME
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
false
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
fn extract_local_activity_marker_data(&self) -> Option<LocalActivityMarkerData> {
|
|
198
|
+
if self.event_type() == EventType::MarkerRecorded {
|
|
199
|
+
match &self.attributes {
|
|
200
|
+
Some(history_event::Attributes::MarkerRecordedEventAttributes(
|
|
201
|
+
MarkerRecordedEventAttributes {
|
|
202
|
+
marker_name,
|
|
203
|
+
details,
|
|
204
|
+
..
|
|
205
|
+
},
|
|
206
|
+
)) if marker_name == LOCAL_ACTIVITY_MARKER_NAME => {
|
|
207
|
+
extract_local_activity_marker_data(details)
|
|
208
|
+
}
|
|
209
|
+
_ => None,
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
None
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
fn into_local_activity_marker_details(self) -> Option<CompleteLocalActivityData> {
|
|
217
|
+
if self.event_type() == EventType::MarkerRecorded {
|
|
218
|
+
match self.attributes {
|
|
219
|
+
Some(history_event::Attributes::MarkerRecordedEventAttributes(
|
|
220
|
+
MarkerRecordedEventAttributes {
|
|
221
|
+
marker_name,
|
|
222
|
+
mut details,
|
|
223
|
+
failure,
|
|
224
|
+
..
|
|
225
|
+
},
|
|
226
|
+
)) if marker_name == LOCAL_ACTIVITY_MARKER_NAME => {
|
|
227
|
+
let (data, ok_res) = extract_local_activity_marker_details(&mut details);
|
|
228
|
+
let data = data?;
|
|
229
|
+
let result = match (ok_res, failure) {
|
|
230
|
+
(Some(r), None) => Ok(r),
|
|
231
|
+
(None | Some(_), Some(f)) => Err(f),
|
|
232
|
+
(None, None) => Ok(Default::default()),
|
|
233
|
+
};
|
|
234
|
+
Some(CompleteLocalActivityData {
|
|
235
|
+
marker_dat: data,
|
|
236
|
+
result,
|
|
237
|
+
})
|
|
238
|
+
}
|
|
239
|
+
_ => None,
|
|
240
|
+
}
|
|
241
|
+
} else {
|
|
242
|
+
None
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
pub(crate) struct CompleteLocalActivityData {
|
|
248
|
+
pub marker_dat: LocalActivityMarkerData,
|
|
249
|
+
pub result: Result<Payload, Failure>,
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
pub(crate) fn validate_activity_completion(
|
|
253
|
+
status: &activity_execution_result::Status,
|
|
254
|
+
) -> Result<(), CompleteActivityError> {
|
|
255
|
+
match status {
|
|
256
|
+
Status::Completed(c) if c.result.is_none() => {
|
|
257
|
+
Err(CompleteActivityError::MalformedActivityCompletion {
|
|
258
|
+
reason: "Activity completions must contain a `result` payload \
|
|
259
|
+
(which may be empty)"
|
|
260
|
+
.to_string(),
|
|
261
|
+
completion: None,
|
|
262
|
+
})
|
|
263
|
+
}
|
|
264
|
+
_ => Ok(()),
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
impl TryFrom<activity_execution_result::Status> for LocalActivityExecutionResult {
|
|
269
|
+
type Error = CompleteActivityError;
|
|
270
|
+
|
|
271
|
+
fn try_from(s: activity_execution_result::Status) -> Result<Self, Self::Error> {
|
|
272
|
+
match s {
|
|
273
|
+
Status::Completed(c) => Ok(LocalActivityExecutionResult::Completed(c)),
|
|
274
|
+
Status::Failed(f)
|
|
275
|
+
if f.failure
|
|
276
|
+
.as_ref()
|
|
277
|
+
.map(|fail| fail.is_timeout().is_some())
|
|
278
|
+
.unwrap_or_default() =>
|
|
279
|
+
{
|
|
280
|
+
Ok(LocalActivityExecutionResult::TimedOut(f))
|
|
281
|
+
}
|
|
282
|
+
Status::Failed(f) => Ok(LocalActivityExecutionResult::Failed(f)),
|
|
283
|
+
Status::Cancelled(cancel) => Ok(LocalActivityExecutionResult::Cancelled(cancel)),
|
|
284
|
+
Status::WillCompleteAsync(_) => {
|
|
285
|
+
Err(CompleteActivityError::MalformedActivityCompletion {
|
|
286
|
+
reason: "Local activities cannot be completed async".to_string(),
|
|
287
|
+
completion: None,
|
|
288
|
+
})
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/// Validated version of [ScheduleLocalActivity]. See it for field docs.
|
|
295
|
+
/// One or both of `schedule_to_close_timeout` and `start_to_close_timeout` are guaranteed to exist.
|
|
296
|
+
#[derive(Debug, Clone)]
|
|
297
|
+
#[cfg_attr(test, derive(Default))]
|
|
298
|
+
pub struct ValidScheduleLA {
|
|
299
|
+
pub seq: u32,
|
|
300
|
+
pub activity_id: String,
|
|
301
|
+
pub activity_type: String,
|
|
302
|
+
pub attempt: u32,
|
|
303
|
+
pub original_schedule_time: Option<SystemTime>,
|
|
304
|
+
pub headers: HashMap<String, Payload>,
|
|
305
|
+
pub arguments: Vec<Payload>,
|
|
306
|
+
pub schedule_to_start_timeout: Option<Duration>,
|
|
307
|
+
pub close_timeouts: LACloseTimeouts,
|
|
308
|
+
pub retry_policy: RetryPolicy,
|
|
309
|
+
pub local_retry_threshold: Duration,
|
|
310
|
+
pub cancellation_type: ActivityCancellationType,
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
#[derive(Debug, Clone, Copy)]
|
|
314
|
+
pub enum LACloseTimeouts {
|
|
315
|
+
ScheduleOnly(Duration),
|
|
316
|
+
StartOnly(Duration),
|
|
317
|
+
Both { sched: Duration, start: Duration },
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
impl LACloseTimeouts {
|
|
321
|
+
/// Splits into (schedule_to_close, start_to_close) options, one or both of which is guaranteed
|
|
322
|
+
/// to be populated
|
|
323
|
+
pub fn into_sched_and_start(self) -> (Option<Duration>, Option<Duration>) {
|
|
324
|
+
match self {
|
|
325
|
+
LACloseTimeouts::ScheduleOnly(x) => (Some(x), None),
|
|
326
|
+
LACloseTimeouts::StartOnly(x) => (None, Some(x)),
|
|
327
|
+
LACloseTimeouts::Both { sched, start } => (Some(sched), Some(start)),
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
#[cfg(test)]
|
|
333
|
+
impl Default for LACloseTimeouts {
|
|
334
|
+
fn default() -> Self {
|
|
335
|
+
LACloseTimeouts::ScheduleOnly(Duration::from_secs(100))
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
impl ValidScheduleLA {
|
|
340
|
+
pub fn from_schedule_la(
|
|
341
|
+
v: ScheduleLocalActivity,
|
|
342
|
+
wf_exe_timeout: Option<Duration>,
|
|
343
|
+
) -> Result<Self, anyhow::Error> {
|
|
344
|
+
let original_schedule_time = v
|
|
345
|
+
.original_schedule_time
|
|
346
|
+
.map(|x| {
|
|
347
|
+
x.try_into()
|
|
348
|
+
.map_err(|_| anyhow!("Could not convert original_schedule_time"))
|
|
349
|
+
})
|
|
350
|
+
.transpose()?;
|
|
351
|
+
let sched_to_close = v
|
|
352
|
+
.schedule_to_close_timeout
|
|
353
|
+
.map(|x| {
|
|
354
|
+
x.try_into()
|
|
355
|
+
.map_err(|_| anyhow!("Could not convert schedule_to_close_timeout"))
|
|
356
|
+
})
|
|
357
|
+
.transpose()?
|
|
358
|
+
// Default to execution timeout if unset
|
|
359
|
+
.or(wf_exe_timeout);
|
|
360
|
+
let mut schedule_to_start_timeout = v
|
|
361
|
+
.schedule_to_start_timeout
|
|
362
|
+
.map(|x| {
|
|
363
|
+
x.try_into()
|
|
364
|
+
.map_err(|_| anyhow!("Could not convert schedule_to_start_timeout"))
|
|
365
|
+
})
|
|
366
|
+
.transpose()?;
|
|
367
|
+
// Clamp schedule-to-start if larger than schedule-to-close
|
|
368
|
+
if let Some((sched_to_start, sched_to_close)) =
|
|
369
|
+
schedule_to_start_timeout.as_mut().zip(sched_to_close)
|
|
370
|
+
{
|
|
371
|
+
if *sched_to_start > sched_to_close {
|
|
372
|
+
*sched_to_start = sched_to_close;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
let close_timeouts = match (
|
|
376
|
+
sched_to_close,
|
|
377
|
+
v.start_to_close_timeout
|
|
378
|
+
.map(|x| {
|
|
379
|
+
x.try_into()
|
|
380
|
+
.map_err(|_| anyhow!("Could not convert start_to_close_timeout"))
|
|
381
|
+
})
|
|
382
|
+
.transpose()?,
|
|
383
|
+
) {
|
|
384
|
+
(Some(sch), None) => LACloseTimeouts::ScheduleOnly(sch),
|
|
385
|
+
(None, Some(start)) => LACloseTimeouts::StartOnly(start),
|
|
386
|
+
(Some(sched), Some(mut start)) => {
|
|
387
|
+
// Clamp start-to-close if larger than schedule-to-close
|
|
388
|
+
if start > sched {
|
|
389
|
+
start = sched;
|
|
390
|
+
}
|
|
391
|
+
LACloseTimeouts::Both { sched, start }
|
|
392
|
+
}
|
|
393
|
+
(None, None) => {
|
|
394
|
+
return Err(anyhow!(
|
|
395
|
+
"One of schedule_to_close or start_to_close timeouts must be set"
|
|
396
|
+
))
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
let retry_policy = v.retry_policy.unwrap_or_default();
|
|
400
|
+
let local_retry_threshold = v
|
|
401
|
+
.local_retry_threshold
|
|
402
|
+
.clone()
|
|
403
|
+
.try_into_or_none()
|
|
404
|
+
.unwrap_or_else(|| Duration::from_secs(60));
|
|
405
|
+
let cancellation_type = ActivityCancellationType::from_i32(v.cancellation_type)
|
|
406
|
+
.unwrap_or(ActivityCancellationType::WaitCancellationCompleted);
|
|
407
|
+
Ok(ValidScheduleLA {
|
|
408
|
+
seq: v.seq,
|
|
409
|
+
activity_id: v.activity_id,
|
|
410
|
+
activity_type: v.activity_type,
|
|
411
|
+
attempt: v.attempt,
|
|
412
|
+
original_schedule_time,
|
|
413
|
+
headers: v.headers,
|
|
414
|
+
arguments: v.arguments,
|
|
415
|
+
schedule_to_start_timeout,
|
|
416
|
+
close_timeouts,
|
|
417
|
+
retry_policy,
|
|
418
|
+
local_retry_threshold,
|
|
419
|
+
cancellation_type,
|
|
420
|
+
})
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
impl Display for ValidScheduleLA {
|
|
425
|
+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
426
|
+
write!(f, "ValidScheduleLA({}, {})", self.seq, self.activity_type)
|
|
427
|
+
}
|
|
428
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
//! This module implements support for creating special core instances and workers which can be used
|
|
2
|
+
//! to replay canned histories. It should be used by Lang SDKs to provide replay capabilities to
|
|
3
|
+
//! users during testing.
|
|
4
|
+
|
|
5
|
+
use crate::{
|
|
6
|
+
worker::client::{mocks::mock_manual_workflow_client, WorkerClient},
|
|
7
|
+
Worker,
|
|
8
|
+
};
|
|
9
|
+
use futures::{FutureExt, Stream, StreamExt};
|
|
10
|
+
use once_cell::sync::OnceCell;
|
|
11
|
+
use parking_lot::Mutex;
|
|
12
|
+
use std::{
|
|
13
|
+
collections::HashMap,
|
|
14
|
+
pin::Pin,
|
|
15
|
+
sync::Arc,
|
|
16
|
+
task::{Context, Poll},
|
|
17
|
+
};
|
|
18
|
+
use temporal_sdk_core_protos::{
|
|
19
|
+
coresdk::workflow_activation::remove_from_cache::EvictionReason,
|
|
20
|
+
temporal::api::{
|
|
21
|
+
common::v1::WorkflowExecution,
|
|
22
|
+
history::v1::History,
|
|
23
|
+
workflowservice::v1::{
|
|
24
|
+
RespondWorkflowTaskCompletedResponse, RespondWorkflowTaskFailedResponse,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
pub use temporal_sdk_core_protos::{
|
|
29
|
+
default_wes_attribs, HistoryInfo, TestHistoryBuilder, DEFAULT_WORKFLOW_TYPE,
|
|
30
|
+
};
|
|
31
|
+
use tokio::sync::{mpsc, mpsc::UnboundedSender, Mutex as TokioMutex};
|
|
32
|
+
use tokio_stream::wrappers::UnboundedReceiverStream;
|
|
33
|
+
use tokio_util::sync::CancellationToken;
|
|
34
|
+
|
|
35
|
+
/// A history which will be used during replay verification. Since histories do not include the
|
|
36
|
+
/// workflow id, it must be manually attached.
|
|
37
|
+
#[derive(Debug, Clone, derive_more::Constructor)]
|
|
38
|
+
pub struct HistoryForReplay {
|
|
39
|
+
hist: History,
|
|
40
|
+
workflow_id: String,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/// Allows lang to feed histories into the replayer one at a time. Simply drop the feeder to signal
|
|
44
|
+
/// to the worker that you're done and it should initiate shutdown.
|
|
45
|
+
pub struct HistoryFeeder {
|
|
46
|
+
tx: mpsc::Sender<HistoryForReplay>,
|
|
47
|
+
}
|
|
48
|
+
/// The stream half of a [HistoryFeeder]
|
|
49
|
+
pub struct HistoryFeederStream {
|
|
50
|
+
rcvr: mpsc::Receiver<HistoryForReplay>,
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
impl HistoryFeeder {
|
|
54
|
+
/// Make a new history feeder, which will store at most `buffer_size` histories before `feed`
|
|
55
|
+
/// blocks.
|
|
56
|
+
///
|
|
57
|
+
/// Returns a feeder which will be used to feed in histories, and a stream you can pass to
|
|
58
|
+
/// one of the replay worker init functions.
|
|
59
|
+
pub fn new(buffer_size: usize) -> (Self, HistoryFeederStream) {
|
|
60
|
+
let (tx, rcvr) = mpsc::channel(buffer_size);
|
|
61
|
+
(Self { tx }, HistoryFeederStream { rcvr })
|
|
62
|
+
}
|
|
63
|
+
/// Feed a new history into the replayer, blocking if there is not room to accept another
|
|
64
|
+
/// history.
|
|
65
|
+
pub async fn feed(&self, history: HistoryForReplay) -> anyhow::Result<()> {
|
|
66
|
+
self.tx.send(history).await?;
|
|
67
|
+
Ok(())
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
impl Stream for HistoryFeederStream {
|
|
72
|
+
type Item = HistoryForReplay;
|
|
73
|
+
|
|
74
|
+
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
|
75
|
+
self.rcvr.poll_recv(cx)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/// Create a mock client which can be used by a replay worker to serve up canned histories. It will
|
|
80
|
+
/// return the entire history in one workflow task. If a workflow task failure is sent to the mock,
|
|
81
|
+
/// it will send the complete response again.
|
|
82
|
+
///
|
|
83
|
+
/// Once it runs out of histories to return, it will serve up default responses after a 10s delay
|
|
84
|
+
pub(crate) fn mock_client_from_histories(historator: Historator) -> impl WorkerClient {
|
|
85
|
+
let mut mg = mock_manual_workflow_client();
|
|
86
|
+
|
|
87
|
+
let hist_allow_tx = historator.replay_done_tx.clone();
|
|
88
|
+
let historator = Arc::new(TokioMutex::new(historator));
|
|
89
|
+
|
|
90
|
+
mg.expect_poll_workflow_task().returning(move |_, _| {
|
|
91
|
+
let historator = historator.clone();
|
|
92
|
+
async move {
|
|
93
|
+
let mut hlock = historator.lock().await;
|
|
94
|
+
// Always wait for permission before dispatching the next task
|
|
95
|
+
let _ = hlock.allow_stream.next().await;
|
|
96
|
+
|
|
97
|
+
if let Some(history) = hlock.next().await {
|
|
98
|
+
let hist_info = HistoryInfo::new_from_history(&history.hist, None).unwrap();
|
|
99
|
+
let mut resp = hist_info.as_poll_wft_response();
|
|
100
|
+
resp.workflow_execution = Some(WorkflowExecution {
|
|
101
|
+
workflow_id: history.workflow_id,
|
|
102
|
+
run_id: hist_info.orig_run_id().to_string(),
|
|
103
|
+
});
|
|
104
|
+
Ok(resp)
|
|
105
|
+
} else {
|
|
106
|
+
if let Some(wc) = hlock.worker_closer.get() {
|
|
107
|
+
wc.cancel();
|
|
108
|
+
}
|
|
109
|
+
Ok(Default::default())
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
.boxed()
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
mg.expect_complete_workflow_task().returning(move |_| {
|
|
116
|
+
async move { Ok(RespondWorkflowTaskCompletedResponse::default()) }.boxed()
|
|
117
|
+
});
|
|
118
|
+
mg.expect_fail_workflow_task().returning(move |_, _, _| {
|
|
119
|
+
hist_allow_tx.send("Failed".to_string()).unwrap();
|
|
120
|
+
async move { Ok(RespondWorkflowTaskFailedResponse::default()) }.boxed()
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
mg
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
pub(crate) struct Historator {
|
|
127
|
+
iter: Pin<Box<dyn Stream<Item = HistoryForReplay> + Send>>,
|
|
128
|
+
allow_stream: UnboundedReceiverStream<String>,
|
|
129
|
+
worker_closer: Arc<OnceCell<CancellationToken>>,
|
|
130
|
+
dat: Arc<Mutex<HistoratorDat>>,
|
|
131
|
+
replay_done_tx: UnboundedSender<String>,
|
|
132
|
+
}
|
|
133
|
+
impl Historator {
|
|
134
|
+
pub(crate) fn new(histories: impl Stream<Item = HistoryForReplay> + Send + 'static) -> Self {
|
|
135
|
+
let dat = Arc::new(Mutex::new(HistoratorDat::default()));
|
|
136
|
+
let (replay_done_tx, replay_done_rx) = mpsc::unbounded_channel();
|
|
137
|
+
// Need to allow the first history item
|
|
138
|
+
replay_done_tx.send("fake".to_string()).unwrap();
|
|
139
|
+
Self {
|
|
140
|
+
iter: Box::pin(histories.fuse()),
|
|
141
|
+
allow_stream: UnboundedReceiverStream::new(replay_done_rx),
|
|
142
|
+
worker_closer: Arc::new(OnceCell::new()),
|
|
143
|
+
dat,
|
|
144
|
+
replay_done_tx,
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/// Returns a callback that can be used as the post-activation hook for a worker to indicate
|
|
149
|
+
/// we're ready to replay the next history, or whatever else.
|
|
150
|
+
pub(crate) fn get_post_activate_hook(&self) -> impl Fn(&Worker, &str, usize) + Send + Sync {
|
|
151
|
+
let dat = self.dat.clone();
|
|
152
|
+
let done_tx = self.replay_done_tx.clone();
|
|
153
|
+
move |worker, activated_run_id, last_processed_event| {
|
|
154
|
+
// We can't hold the lock while evaluating the hook, or we'd deadlock.
|
|
155
|
+
let last_event_in_hist = dat
|
|
156
|
+
.lock()
|
|
157
|
+
.run_id_to_last_event_num
|
|
158
|
+
.get(activated_run_id)
|
|
159
|
+
.cloned();
|
|
160
|
+
if let Some(le) = last_event_in_hist {
|
|
161
|
+
if last_processed_event >= le {
|
|
162
|
+
worker.request_wf_eviction(
|
|
163
|
+
activated_run_id,
|
|
164
|
+
"Always evict workflows after replay",
|
|
165
|
+
EvictionReason::LangRequested,
|
|
166
|
+
);
|
|
167
|
+
done_tx.send(activated_run_id.to_string()).unwrap();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
pub(crate) fn get_shutdown_setter(&self) -> impl FnOnce(CancellationToken) + 'static {
|
|
174
|
+
let wc = self.worker_closer.clone();
|
|
175
|
+
move |ct| {
|
|
176
|
+
wc.set(ct).expect("Shutdown token must only be set once");
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
impl Stream for Historator {
|
|
182
|
+
type Item = HistoryForReplay;
|
|
183
|
+
|
|
184
|
+
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
|
185
|
+
match self.iter.poll_next_unpin(cx) {
|
|
186
|
+
Poll::Ready(Some(history)) => {
|
|
187
|
+
let run_id = history
|
|
188
|
+
.hist
|
|
189
|
+
.extract_run_id_from_start()
|
|
190
|
+
.expect(
|
|
191
|
+
"Histories provided for replay must contain run ids in their workflow \
|
|
192
|
+
execution started events",
|
|
193
|
+
)
|
|
194
|
+
.to_string();
|
|
195
|
+
let last_event = history.hist.last_event_id();
|
|
196
|
+
self.dat
|
|
197
|
+
.lock()
|
|
198
|
+
.run_id_to_last_event_num
|
|
199
|
+
.insert(run_id, last_event as usize);
|
|
200
|
+
Poll::Ready(Some(history))
|
|
201
|
+
}
|
|
202
|
+
Poll::Ready(None) => {
|
|
203
|
+
self.dat.lock().all_dispatched = true;
|
|
204
|
+
Poll::Ready(None)
|
|
205
|
+
}
|
|
206
|
+
o => o,
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
#[derive(Default)]
|
|
212
|
+
struct HistoratorDat {
|
|
213
|
+
run_id_to_last_event_num: HashMap<String, usize>,
|
|
214
|
+
all_dispatched: bool,
|
|
215
|
+
}
|