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,464 @@
|
|
1
|
+
mod activity_heartbeat_manager;
|
2
|
+
mod local_activities;
|
3
|
+
|
4
|
+
pub(crate) use local_activities::{
|
5
|
+
DispatchOrTimeoutLA, ExecutingLAId, LACompleteAction, LocalActRequest,
|
6
|
+
LocalActivityExecutionResult, LocalActivityManager, LocalActivityResolution,
|
7
|
+
LocalInFlightActInfo, NewLocalAct,
|
8
|
+
};
|
9
|
+
|
10
|
+
use crate::{
|
11
|
+
abstractions::{MeteredSemaphore, OwnedMeteredSemPermit},
|
12
|
+
pollers::BoxedActPoller,
|
13
|
+
telemetry::metrics::{activity_type, activity_worker_type, workflow_type, MetricsContext},
|
14
|
+
worker::{
|
15
|
+
activities::activity_heartbeat_manager::ActivityHeartbeatError, client::WorkerClient,
|
16
|
+
},
|
17
|
+
PollActivityError, TaskToken,
|
18
|
+
};
|
19
|
+
use activity_heartbeat_manager::ActivityHeartbeatManager;
|
20
|
+
use dashmap::DashMap;
|
21
|
+
use governor::{
|
22
|
+
clock::DefaultClock,
|
23
|
+
middleware::NoOpMiddleware,
|
24
|
+
state::{InMemoryState, NotKeyed},
|
25
|
+
Quota, RateLimiter,
|
26
|
+
};
|
27
|
+
use std::{
|
28
|
+
convert::TryInto,
|
29
|
+
sync::Arc,
|
30
|
+
time::{Duration, Instant},
|
31
|
+
};
|
32
|
+
use temporal_sdk_core_protos::{
|
33
|
+
coresdk::{
|
34
|
+
activity_result::{self as ar, activity_execution_result as aer},
|
35
|
+
activity_task::{ActivityCancelReason, ActivityTask},
|
36
|
+
ActivityHeartbeat,
|
37
|
+
},
|
38
|
+
temporal::api::{
|
39
|
+
failure::v1::{failure::FailureInfo, CanceledFailureInfo, Failure},
|
40
|
+
workflowservice::v1::PollActivityTaskQueueResponse,
|
41
|
+
},
|
42
|
+
};
|
43
|
+
use tokio::sync::Notify;
|
44
|
+
|
45
|
+
#[derive(Debug, derive_more::Constructor)]
|
46
|
+
struct PendingActivityCancel {
|
47
|
+
task_token: TaskToken,
|
48
|
+
reason: ActivityCancelReason,
|
49
|
+
}
|
50
|
+
|
51
|
+
/// Contains minimal set of details that core needs to store while an activity is running.
|
52
|
+
#[derive(Debug)]
|
53
|
+
struct InFlightActInfo {
|
54
|
+
pub activity_type: String,
|
55
|
+
pub workflow_type: String,
|
56
|
+
start_time: Instant,
|
57
|
+
}
|
58
|
+
|
59
|
+
/// Augments [InFlightActInfo] with details specific to remote activities
|
60
|
+
struct RemoteInFlightActInfo {
|
61
|
+
pub base: InFlightActInfo,
|
62
|
+
/// Used to calculate aggregation delay between activity heartbeats.
|
63
|
+
pub heartbeat_timeout: Option<prost_types::Duration>,
|
64
|
+
/// Set to true if we have already issued a cancellation activation to lang for this activity
|
65
|
+
pub issued_cancel_to_lang: bool,
|
66
|
+
/// Set to true if we have already learned from the server this activity doesn't exist. EX:
|
67
|
+
/// we have learned from heartbeating and issued a cancel task, in which case we may simply
|
68
|
+
/// discard the reply.
|
69
|
+
pub known_not_found: bool,
|
70
|
+
/// The permit from the max concurrent semaphore
|
71
|
+
_permit: OwnedMeteredSemPermit,
|
72
|
+
}
|
73
|
+
impl RemoteInFlightActInfo {
|
74
|
+
fn new(
|
75
|
+
activity_type: String,
|
76
|
+
workflow_type: String,
|
77
|
+
heartbeat_timeout: Option<prost_types::Duration>,
|
78
|
+
permit: OwnedMeteredSemPermit,
|
79
|
+
) -> Self {
|
80
|
+
Self {
|
81
|
+
base: InFlightActInfo {
|
82
|
+
activity_type,
|
83
|
+
workflow_type,
|
84
|
+
start_time: Instant::now(),
|
85
|
+
},
|
86
|
+
heartbeat_timeout,
|
87
|
+
issued_cancel_to_lang: false,
|
88
|
+
known_not_found: false,
|
89
|
+
_permit: permit,
|
90
|
+
}
|
91
|
+
}
|
92
|
+
}
|
93
|
+
|
94
|
+
struct NonPollActBuffer {
|
95
|
+
tx: async_channel::Sender<PermittedTqResp>,
|
96
|
+
rx: async_channel::Receiver<PermittedTqResp>,
|
97
|
+
}
|
98
|
+
impl NonPollActBuffer {
|
99
|
+
pub fn new() -> Self {
|
100
|
+
let (tx, rx) = async_channel::unbounded();
|
101
|
+
Self { tx, rx }
|
102
|
+
}
|
103
|
+
|
104
|
+
pub async fn next(&self) -> PermittedTqResp {
|
105
|
+
self.rx.recv().await.expect("Send half cannot be dropped")
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
pub(crate) struct WorkerActivityTasks {
|
110
|
+
/// Centralizes management of heartbeat issuing / throttling
|
111
|
+
heartbeat_manager: ActivityHeartbeatManager,
|
112
|
+
/// Activities that have been issued to lang but not yet completed
|
113
|
+
outstanding_activity_tasks: DashMap<TaskToken, RemoteInFlightActInfo>,
|
114
|
+
/// Buffers activity task polling in the event we need to return a cancellation while a poll is
|
115
|
+
/// ongoing.
|
116
|
+
poller: BoxedActPoller,
|
117
|
+
/// Holds activity tasks we have received by non-polling means. EX: In direct response to
|
118
|
+
/// workflow task completion.
|
119
|
+
non_poll_tasks: NonPollActBuffer,
|
120
|
+
/// Ensures we stay at or below this worker's maximum concurrent activity limit
|
121
|
+
activities_semaphore: Arc<MeteredSemaphore>,
|
122
|
+
/// Enables per-worker rate-limiting of activity tasks
|
123
|
+
ratelimiter: Option<RateLimiter<NotKeyed, InMemoryState, DefaultClock, NoOpMiddleware>>,
|
124
|
+
/// Wakes every time an activity is removed from the outstanding map
|
125
|
+
complete_notify: Notify,
|
126
|
+
|
127
|
+
metrics: MetricsContext,
|
128
|
+
|
129
|
+
max_heartbeat_throttle_interval: Duration,
|
130
|
+
default_heartbeat_throttle_interval: Duration,
|
131
|
+
}
|
132
|
+
|
133
|
+
impl WorkerActivityTasks {
|
134
|
+
pub(crate) fn new(
|
135
|
+
max_activity_tasks: usize,
|
136
|
+
max_worker_act_per_sec: Option<f64>,
|
137
|
+
poller: BoxedActPoller,
|
138
|
+
client: Arc<dyn WorkerClient>,
|
139
|
+
metrics: MetricsContext,
|
140
|
+
max_heartbeat_throttle_interval: Duration,
|
141
|
+
default_heartbeat_throttle_interval: Duration,
|
142
|
+
) -> Self {
|
143
|
+
Self {
|
144
|
+
heartbeat_manager: ActivityHeartbeatManager::new(client),
|
145
|
+
outstanding_activity_tasks: Default::default(),
|
146
|
+
poller,
|
147
|
+
non_poll_tasks: NonPollActBuffer::new(),
|
148
|
+
activities_semaphore: Arc::new(MeteredSemaphore::new(
|
149
|
+
max_activity_tasks,
|
150
|
+
metrics.with_new_attrs([activity_worker_type()]),
|
151
|
+
MetricsContext::available_task_slots,
|
152
|
+
)),
|
153
|
+
ratelimiter: max_worker_act_per_sec.and_then(|ps| {
|
154
|
+
Quota::with_period(Duration::from_secs_f64(ps.recip())).map(RateLimiter::direct)
|
155
|
+
}),
|
156
|
+
complete_notify: Notify::new(),
|
157
|
+
metrics,
|
158
|
+
max_heartbeat_throttle_interval,
|
159
|
+
default_heartbeat_throttle_interval,
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
pub(crate) fn notify_shutdown(&self) {
|
164
|
+
self.poller.notify_shutdown();
|
165
|
+
}
|
166
|
+
|
167
|
+
/// Wait for all outstanding activity tasks to finish
|
168
|
+
pub(crate) async fn wait_all_finished(&self) {
|
169
|
+
while !self.outstanding_activity_tasks.is_empty() {
|
170
|
+
self.complete_notify.notified().await
|
171
|
+
}
|
172
|
+
}
|
173
|
+
|
174
|
+
pub(crate) async fn shutdown(self) {
|
175
|
+
self.poller.shutdown_box().await;
|
176
|
+
self.heartbeat_manager.shutdown().await;
|
177
|
+
}
|
178
|
+
|
179
|
+
/// Wait until not at the outstanding activity limit, and then poll for an activity task.
|
180
|
+
///
|
181
|
+
/// Returns `Ok(None)` if no activity is ready and the overall polling loop should be retried.
|
182
|
+
pub(crate) async fn poll(&self) -> Result<Option<ActivityTask>, PollActivityError> {
|
183
|
+
let poll_with_semaphore = async {
|
184
|
+
// Acquire and subsequently forget a permit for an outstanding activity. When they are
|
185
|
+
// completed, we must add a new permit to the semaphore, since holding the permit the
|
186
|
+
// entire time lang does work would be a challenge.
|
187
|
+
let perm = self
|
188
|
+
.activities_semaphore
|
189
|
+
.acquire_owned()
|
190
|
+
.await
|
191
|
+
.expect("outstanding activity semaphore not closed");
|
192
|
+
if let Some(ref rl) = self.ratelimiter {
|
193
|
+
rl.until_ready().await;
|
194
|
+
}
|
195
|
+
(self.poller.poll().await, perm)
|
196
|
+
};
|
197
|
+
|
198
|
+
tokio::select! {
|
199
|
+
biased;
|
200
|
+
|
201
|
+
cancel_task = self.next_pending_cancel_task() => {
|
202
|
+
cancel_task
|
203
|
+
}
|
204
|
+
task = self.non_poll_tasks.next() => {
|
205
|
+
Ok(Some(self.about_to_issue_task(task)))
|
206
|
+
}
|
207
|
+
(work, permit) = poll_with_semaphore => {
|
208
|
+
match work {
|
209
|
+
Some(Ok(work)) => {
|
210
|
+
if work == PollActivityTaskQueueResponse::default() {
|
211
|
+
// Timeout
|
212
|
+
self.metrics.act_poll_timeout();
|
213
|
+
return Ok(None)
|
214
|
+
}
|
215
|
+
let work = self.about_to_issue_task(PermittedTqResp {
|
216
|
+
resp: work, permit
|
217
|
+
});
|
218
|
+
Ok(Some(work))
|
219
|
+
}
|
220
|
+
None => {
|
221
|
+
Err(PollActivityError::ShutDown)
|
222
|
+
}
|
223
|
+
Some(Err(e)) => Err(e.into())
|
224
|
+
}
|
225
|
+
}
|
226
|
+
}
|
227
|
+
}
|
228
|
+
|
229
|
+
pub(crate) async fn complete(
|
230
|
+
&self,
|
231
|
+
task_token: TaskToken,
|
232
|
+
status: aer::Status,
|
233
|
+
client: &dyn WorkerClient,
|
234
|
+
) {
|
235
|
+
if let Some((_, act_info)) = self.outstanding_activity_tasks.remove(&task_token) {
|
236
|
+
let act_metrics = self.metrics.with_new_attrs([
|
237
|
+
activity_type(act_info.base.activity_type.clone()),
|
238
|
+
workflow_type(act_info.base.workflow_type.clone()),
|
239
|
+
]);
|
240
|
+
act_metrics.act_execution_latency(act_info.base.start_time.elapsed());
|
241
|
+
let known_not_found = act_info.known_not_found;
|
242
|
+
drop(act_info); // TODO: Get rid of dashmap. If we hold ref across await, bad stuff.
|
243
|
+
self.heartbeat_manager.evict(task_token.clone()).await;
|
244
|
+
self.complete_notify.notify_waiters();
|
245
|
+
|
246
|
+
// No need to report activities which we already know the server doesn't care about
|
247
|
+
if !known_not_found {
|
248
|
+
let maybe_net_err = match status {
|
249
|
+
aer::Status::WillCompleteAsync(_) => None,
|
250
|
+
aer::Status::Completed(ar::Success { result }) => client
|
251
|
+
.complete_activity_task(task_token.clone(), result.map(Into::into))
|
252
|
+
.await
|
253
|
+
.err(),
|
254
|
+
aer::Status::Failed(ar::Failure { failure }) => {
|
255
|
+
act_metrics.act_execution_failed();
|
256
|
+
client
|
257
|
+
.fail_activity_task(task_token.clone(), failure.map(Into::into))
|
258
|
+
.await
|
259
|
+
.err()
|
260
|
+
}
|
261
|
+
aer::Status::Cancelled(ar::Cancellation { failure }) => {
|
262
|
+
let details = if let Some(Failure {
|
263
|
+
failure_info:
|
264
|
+
Some(FailureInfo::CanceledFailureInfo(CanceledFailureInfo { details })),
|
265
|
+
..
|
266
|
+
}) = failure
|
267
|
+
{
|
268
|
+
details
|
269
|
+
} else {
|
270
|
+
warn!(task_token = ? task_token,
|
271
|
+
"Expected activity cancelled status with CanceledFailureInfo");
|
272
|
+
None
|
273
|
+
};
|
274
|
+
client
|
275
|
+
.cancel_activity_task(task_token.clone(), details.map(Into::into))
|
276
|
+
.await
|
277
|
+
.err()
|
278
|
+
}
|
279
|
+
};
|
280
|
+
|
281
|
+
if let Some(e) = maybe_net_err {
|
282
|
+
if e.code() == tonic::Code::NotFound {
|
283
|
+
warn!(task_token = ?task_token, details = ?e, "Activity not found on \
|
284
|
+
completion. This may happen if the activity has already been cancelled but \
|
285
|
+
completed anyway.");
|
286
|
+
} else {
|
287
|
+
warn!(error=?e, "Network error while completing activity");
|
288
|
+
};
|
289
|
+
};
|
290
|
+
};
|
291
|
+
} else {
|
292
|
+
warn!(
|
293
|
+
"Attempted to complete activity task {} but we were not tracking it",
|
294
|
+
&task_token
|
295
|
+
);
|
296
|
+
}
|
297
|
+
}
|
298
|
+
|
299
|
+
/// Attempt to record an activity heartbeat
|
300
|
+
pub(crate) fn record_heartbeat(
|
301
|
+
&self,
|
302
|
+
details: ActivityHeartbeat,
|
303
|
+
) -> Result<(), ActivityHeartbeatError> {
|
304
|
+
// TODO: Propagate these back as cancels. Silent fails is too nonobvious
|
305
|
+
let heartbeat_timeout: Duration = self
|
306
|
+
.outstanding_activity_tasks
|
307
|
+
.get(&TaskToken(details.task_token.clone()))
|
308
|
+
.ok_or(ActivityHeartbeatError::UnknownActivity)?
|
309
|
+
.heartbeat_timeout
|
310
|
+
.clone()
|
311
|
+
// We treat None as 0 (even though heartbeat_timeout is never set to None by the server)
|
312
|
+
.unwrap_or_default()
|
313
|
+
.try_into()
|
314
|
+
// This technically should never happen since prost duration should be directly mappable
|
315
|
+
// to std::time::Duration.
|
316
|
+
.or(Err(ActivityHeartbeatError::InvalidHeartbeatTimeout))?;
|
317
|
+
|
318
|
+
// There is a bug in the server that translates non-set heartbeat timeouts into 0 duration.
|
319
|
+
// That's why we treat 0 the same way as None, otherwise we wouldn't know which aggregation
|
320
|
+
// delay to use, and using 0 is not a good idea as SDK would hammer the server too hard.
|
321
|
+
let throttle_interval = if heartbeat_timeout.as_millis() == 0 {
|
322
|
+
self.default_heartbeat_throttle_interval
|
323
|
+
} else {
|
324
|
+
heartbeat_timeout.mul_f64(0.8)
|
325
|
+
};
|
326
|
+
let throttle_interval =
|
327
|
+
std::cmp::min(throttle_interval, self.max_heartbeat_throttle_interval);
|
328
|
+
self.heartbeat_manager.record(details, throttle_interval)
|
329
|
+
}
|
330
|
+
|
331
|
+
/// Returns a handle that the workflows management side can use to interact with this manager
|
332
|
+
pub(crate) fn get_handle_for_workflows(&self) -> ActivitiesFromWFTsHandle {
|
333
|
+
ActivitiesFromWFTsHandle {
|
334
|
+
sem: self.activities_semaphore.clone(),
|
335
|
+
tx: self.non_poll_tasks.tx.clone(),
|
336
|
+
}
|
337
|
+
}
|
338
|
+
|
339
|
+
async fn next_pending_cancel_task(&self) -> Result<Option<ActivityTask>, PollActivityError> {
|
340
|
+
let next_pc = self.heartbeat_manager.next_pending_cancel().await;
|
341
|
+
// Issue cancellations for anything we noticed was cancelled during heartbeating
|
342
|
+
if let Some(PendingActivityCancel { task_token, reason }) = next_pc {
|
343
|
+
// It's possible that activity has been completed and we no longer have an
|
344
|
+
// outstanding activity task. This is fine because it means that we no
|
345
|
+
// longer need to cancel this activity, so we'll just ignore such orphaned
|
346
|
+
// cancellations.
|
347
|
+
if let Some(mut details) = self.outstanding_activity_tasks.get_mut(&task_token) {
|
348
|
+
if details.issued_cancel_to_lang {
|
349
|
+
// Don't double-issue cancellations
|
350
|
+
return Ok(None);
|
351
|
+
}
|
352
|
+
|
353
|
+
details.issued_cancel_to_lang = true;
|
354
|
+
if reason == ActivityCancelReason::NotFound {
|
355
|
+
details.known_not_found = true;
|
356
|
+
}
|
357
|
+
Ok(Some(ActivityTask::cancel_from_ids(task_token.0, reason)))
|
358
|
+
} else {
|
359
|
+
debug!(task_token = ?task_token, "Unknown activity task when issuing cancel");
|
360
|
+
// If we can't find the activity here, it's already been completed,
|
361
|
+
// in which case issuing a cancel again is pointless.
|
362
|
+
Ok(None)
|
363
|
+
}
|
364
|
+
} else {
|
365
|
+
// The only situation where the next cancel would return none is if the manager
|
366
|
+
// was dropped, which can only happen on shutdown.
|
367
|
+
Err(PollActivityError::ShutDown)
|
368
|
+
}
|
369
|
+
}
|
370
|
+
|
371
|
+
/// Called when there is a new act task about to be bubbled up out of the manager
|
372
|
+
fn about_to_issue_task(&self, task: PermittedTqResp) -> ActivityTask {
|
373
|
+
if let Some(dur) = task.resp.sched_to_start() {
|
374
|
+
self.metrics.act_sched_to_start_latency(dur);
|
375
|
+
};
|
376
|
+
|
377
|
+
self.outstanding_activity_tasks.insert(
|
378
|
+
task.resp.task_token.clone().into(),
|
379
|
+
RemoteInFlightActInfo::new(
|
380
|
+
task.resp.activity_type.clone().unwrap_or_default().name,
|
381
|
+
task.resp.workflow_type.clone().unwrap_or_default().name,
|
382
|
+
task.resp.heartbeat_timeout.clone(),
|
383
|
+
task.permit,
|
384
|
+
),
|
385
|
+
);
|
386
|
+
|
387
|
+
ActivityTask::start_from_poll_resp(task.resp)
|
388
|
+
}
|
389
|
+
|
390
|
+
#[cfg(test)]
|
391
|
+
pub(crate) fn remaining_activity_capacity(&self) -> usize {
|
392
|
+
self.activities_semaphore.available_permits()
|
393
|
+
}
|
394
|
+
}
|
395
|
+
|
396
|
+
/// Provides facilities for the workflow side of things to interact with the activity manager.
|
397
|
+
/// Allows for the handling of activities returned by WFT completions.
|
398
|
+
pub(crate) struct ActivitiesFromWFTsHandle {
|
399
|
+
sem: Arc<MeteredSemaphore>,
|
400
|
+
tx: async_channel::Sender<PermittedTqResp>,
|
401
|
+
}
|
402
|
+
|
403
|
+
impl ActivitiesFromWFTsHandle {
|
404
|
+
/// Returns a handle that can be used to reserve an activity slot. EX: When requesting eager
|
405
|
+
/// dispatch of an activity to this worker upon workflow task completion
|
406
|
+
pub(crate) fn reserve_slot(&self) -> Option<OwnedMeteredSemPermit> {
|
407
|
+
self.sem.try_acquire_owned().ok()
|
408
|
+
}
|
409
|
+
|
410
|
+
/// Queue new activity tasks for dispatch received from non-polling sources (ex: eager returns
|
411
|
+
/// from WFT completion)
|
412
|
+
pub(crate) fn add_tasks(&self, tasks: impl IntoIterator<Item = PermittedTqResp>) {
|
413
|
+
for t in tasks.into_iter() {
|
414
|
+
self.tx.try_send(t).expect("Receive half cannot be dropped");
|
415
|
+
}
|
416
|
+
}
|
417
|
+
}
|
418
|
+
|
419
|
+
pub(crate) struct PermittedTqResp {
|
420
|
+
pub permit: OwnedMeteredSemPermit,
|
421
|
+
pub resp: PollActivityTaskQueueResponse,
|
422
|
+
}
|
423
|
+
|
424
|
+
#[cfg(test)]
|
425
|
+
mod tests {
|
426
|
+
use super::*;
|
427
|
+
use crate::{
|
428
|
+
test_help::mock_poller_from_resps, worker::client::mocks::mock_manual_workflow_client,
|
429
|
+
};
|
430
|
+
|
431
|
+
#[tokio::test]
|
432
|
+
async fn per_worker_ratelimit() {
|
433
|
+
let poller = mock_poller_from_resps([
|
434
|
+
PollActivityTaskQueueResponse {
|
435
|
+
task_token: vec![1],
|
436
|
+
activity_id: "act1".to_string(),
|
437
|
+
..Default::default()
|
438
|
+
}
|
439
|
+
.into(),
|
440
|
+
PollActivityTaskQueueResponse {
|
441
|
+
task_token: vec![2],
|
442
|
+
activity_id: "act2".to_string(),
|
443
|
+
..Default::default()
|
444
|
+
}
|
445
|
+
.into(),
|
446
|
+
]);
|
447
|
+
let atm = WorkerActivityTasks::new(
|
448
|
+
10,
|
449
|
+
Some(2.0),
|
450
|
+
poller,
|
451
|
+
Arc::new(mock_manual_workflow_client()),
|
452
|
+
MetricsContext::default(),
|
453
|
+
Duration::from_secs(1),
|
454
|
+
Duration::from_secs(1),
|
455
|
+
);
|
456
|
+
let start = Instant::now();
|
457
|
+
atm.poll().await.unwrap().unwrap();
|
458
|
+
atm.poll().await.unwrap().unwrap();
|
459
|
+
// At least half a second will have elapsed since we only allow 2 tasks per second.
|
460
|
+
// With no ratelimit, even on a slow CI server with lots of load, this would typically take
|
461
|
+
// low single digit ms or less.
|
462
|
+
assert!(start.elapsed() > Duration::from_secs_f64(0.5));
|
463
|
+
}
|
464
|
+
}
|
@@ -0,0 +1,87 @@
|
|
1
|
+
use super::*;
|
2
|
+
use futures::Future;
|
3
|
+
|
4
|
+
#[cfg(test)]
|
5
|
+
/// Create a mock client primed with basic necessary expectations
|
6
|
+
pub(crate) fn mock_workflow_client() -> MockWorkerClient {
|
7
|
+
MockWorkerClient::new()
|
8
|
+
}
|
9
|
+
|
10
|
+
/// Create a mock manual client primed with basic necessary expectations
|
11
|
+
pub(crate) fn mock_manual_workflow_client() -> MockManualWorkerClient {
|
12
|
+
MockManualWorkerClient::new()
|
13
|
+
}
|
14
|
+
|
15
|
+
// Need a version of the mock that can return futures so we can return potentially pending
|
16
|
+
// results. This is really annoying b/c of the async trait stuff. Need
|
17
|
+
// https://github.com/asomers/mockall/issues/189 to be fixed for it to go away.
|
18
|
+
mockall::mock! {
|
19
|
+
pub ManualWorkerClient {}
|
20
|
+
#[allow(unused)]
|
21
|
+
impl WorkerClient for ManualWorkerClient {
|
22
|
+
fn poll_workflow_task<'a, 'b>(&'a self, task_queue: String, is_sticky: bool)
|
23
|
+
-> impl Future<Output = Result<PollWorkflowTaskQueueResponse>> + Send + 'b
|
24
|
+
where 'a: 'b, Self: 'b;
|
25
|
+
|
26
|
+
fn poll_activity_task<'a, 'b>(&self, task_queue: String, max_tasks_per_sec: Option<f64>)
|
27
|
+
-> impl Future<Output = Result<PollActivityTaskQueueResponse>> + Send + 'b
|
28
|
+
where 'a: 'b, Self: 'b;
|
29
|
+
|
30
|
+
fn complete_workflow_task<'a, 'b>(
|
31
|
+
&self,
|
32
|
+
request: WorkflowTaskCompletion,
|
33
|
+
) -> impl Future<Output = Result<RespondWorkflowTaskCompletedResponse>> + Send + 'b
|
34
|
+
where 'a: 'b, Self: 'b;
|
35
|
+
|
36
|
+
fn complete_activity_task<'a, 'b>(
|
37
|
+
&self,
|
38
|
+
task_token: TaskToken,
|
39
|
+
result: Option<Payloads>,
|
40
|
+
) -> impl Future<Output = Result<RespondActivityTaskCompletedResponse>> + Send + 'b
|
41
|
+
where 'a: 'b, Self: 'b;
|
42
|
+
|
43
|
+
fn cancel_activity_task<'a, 'b>(
|
44
|
+
&self,
|
45
|
+
task_token: TaskToken,
|
46
|
+
details: Option<Payloads>,
|
47
|
+
) -> impl Future<Output = Result<RespondActivityTaskCanceledResponse>> + Send + 'b
|
48
|
+
where 'a: 'b, Self: 'b;
|
49
|
+
|
50
|
+
fn fail_activity_task<'a, 'b>(
|
51
|
+
&self,
|
52
|
+
task_token: TaskToken,
|
53
|
+
failure: Option<Failure>,
|
54
|
+
) -> impl Future<Output = Result<RespondActivityTaskFailedResponse>> + Send + 'b
|
55
|
+
where 'a: 'b, Self: 'b;
|
56
|
+
|
57
|
+
fn fail_workflow_task<'a, 'b>(
|
58
|
+
&self,
|
59
|
+
task_token: TaskToken,
|
60
|
+
cause: WorkflowTaskFailedCause,
|
61
|
+
failure: Option<Failure>,
|
62
|
+
) -> impl Future<Output = Result<RespondWorkflowTaskFailedResponse>> + Send + 'b
|
63
|
+
where 'a: 'b, Self: 'b;
|
64
|
+
|
65
|
+
fn record_activity_heartbeat<'a, 'b>(
|
66
|
+
&self,
|
67
|
+
task_token: TaskToken,
|
68
|
+
details: Option<Payloads>,
|
69
|
+
) -> impl Future<Output = Result<RecordActivityTaskHeartbeatResponse>> + Send + 'b
|
70
|
+
where 'a: 'b, Self: 'b;
|
71
|
+
|
72
|
+
fn get_workflow_execution_history<'a, 'b>(
|
73
|
+
&self,
|
74
|
+
workflow_id: String,
|
75
|
+
run_id: Option<String>,
|
76
|
+
page_token: Vec<u8>
|
77
|
+
) -> impl Future<Output = Result<GetWorkflowExecutionHistoryResponse>> + Send + 'b
|
78
|
+
where 'a: 'b, Self: 'b;
|
79
|
+
|
80
|
+
fn respond_legacy_query<'a, 'b>(
|
81
|
+
&self,
|
82
|
+
task_token: TaskToken,
|
83
|
+
query_result: QueryResult,
|
84
|
+
) -> impl Future<Output = Result<RespondQueryTaskCompletedResponse>> + Send + 'b
|
85
|
+
where 'a: 'b, Self: 'b;
|
86
|
+
}
|
87
|
+
}
|