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,439 @@
|
|
1
|
+
#![allow(clippy::large_enum_variant)]
|
2
|
+
|
3
|
+
use super::{
|
4
|
+
workflow_machines::{MachineResponse, WFMachinesError},
|
5
|
+
Cancellable, EventInfo, MachineKind, NewMachineWithCommand, OnEventWrapper, WFMachinesAdapter,
|
6
|
+
};
|
7
|
+
use rustfsm::{fsm, MachineError, StateMachine, TransitionResult};
|
8
|
+
use std::convert::TryFrom;
|
9
|
+
use temporal_sdk_core_protos::{
|
10
|
+
coresdk::{
|
11
|
+
workflow_activation::FireTimer,
|
12
|
+
workflow_commands::{CancelTimer, StartTimer},
|
13
|
+
HistoryEventId,
|
14
|
+
},
|
15
|
+
temporal::api::{
|
16
|
+
command::v1::Command,
|
17
|
+
enums::v1::{CommandType, EventType},
|
18
|
+
history::v1::{history_event, HistoryEvent, TimerFiredEventAttributes},
|
19
|
+
},
|
20
|
+
};
|
21
|
+
|
22
|
+
fsm! {
|
23
|
+
pub(super) name TimerMachine;
|
24
|
+
command TimerMachineCommand;
|
25
|
+
error WFMachinesError;
|
26
|
+
shared_state SharedState;
|
27
|
+
|
28
|
+
Created --(Schedule, on_schedule) --> StartCommandCreated;
|
29
|
+
|
30
|
+
StartCommandCreated --(CommandStartTimer) --> StartCommandCreated;
|
31
|
+
StartCommandCreated --(TimerStarted(HistoryEventId), on_timer_started) --> StartCommandRecorded;
|
32
|
+
StartCommandCreated --(Cancel, shared on_cancel) --> Canceled;
|
33
|
+
|
34
|
+
StartCommandRecorded --(TimerFired(TimerFiredEventAttributes), shared on_timer_fired) --> Fired;
|
35
|
+
StartCommandRecorded --(Cancel, shared on_cancel) --> CancelTimerCommandCreated;
|
36
|
+
|
37
|
+
CancelTimerCommandCreated --(Cancel) --> CancelTimerCommandCreated;
|
38
|
+
CancelTimerCommandCreated
|
39
|
+
--(CommandCancelTimer, on_command_cancel_timer) --> CancelTimerCommandSent;
|
40
|
+
|
41
|
+
CancelTimerCommandSent --(TimerCanceled) --> Canceled;
|
42
|
+
|
43
|
+
// Ignore any spurious cancellations after resolution
|
44
|
+
Canceled --(Cancel) --> Canceled;
|
45
|
+
Fired --(Cancel) --> Fired;
|
46
|
+
}
|
47
|
+
|
48
|
+
#[derive(Debug, derive_more::Display)]
|
49
|
+
pub(super) enum TimerMachineCommand {
|
50
|
+
Complete,
|
51
|
+
IssueCancelCmd(Command),
|
52
|
+
// We don't issue activations for timer cancellations. Lang SDK is expected to cancel
|
53
|
+
// it's own timers when user calls cancel, and they cannot be cancelled by any other
|
54
|
+
// means.
|
55
|
+
}
|
56
|
+
|
57
|
+
#[derive(Default, Clone)]
|
58
|
+
pub(super) struct SharedState {
|
59
|
+
attrs: StartTimer,
|
60
|
+
cancelled_before_sent: bool,
|
61
|
+
}
|
62
|
+
|
63
|
+
/// Creates a new, scheduled, timer as a [CancellableCommand]
|
64
|
+
pub(super) fn new_timer(attribs: StartTimer) -> NewMachineWithCommand {
|
65
|
+
let (timer, add_cmd) = TimerMachine::new_scheduled(attribs);
|
66
|
+
NewMachineWithCommand {
|
67
|
+
command: add_cmd,
|
68
|
+
machine: timer.into(),
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
impl TimerMachine {
|
73
|
+
/// Create a new timer and immediately schedule it
|
74
|
+
fn new_scheduled(attribs: StartTimer) -> (Self, Command) {
|
75
|
+
let mut s = Self::new(attribs);
|
76
|
+
OnEventWrapper::on_event_mut(&mut s, TimerMachineEvents::Schedule)
|
77
|
+
.expect("Scheduling timers doesn't fail");
|
78
|
+
let cmd = Command {
|
79
|
+
command_type: CommandType::StartTimer as i32,
|
80
|
+
attributes: Some(s.shared_state().attrs.clone().into()),
|
81
|
+
};
|
82
|
+
(s, cmd)
|
83
|
+
}
|
84
|
+
|
85
|
+
fn new(attribs: StartTimer) -> Self {
|
86
|
+
Self {
|
87
|
+
state: Created {}.into(),
|
88
|
+
shared_state: SharedState {
|
89
|
+
attrs: attribs,
|
90
|
+
cancelled_before_sent: false,
|
91
|
+
},
|
92
|
+
}
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
impl TryFrom<HistoryEvent> for TimerMachineEvents {
|
97
|
+
type Error = WFMachinesError;
|
98
|
+
|
99
|
+
fn try_from(e: HistoryEvent) -> Result<Self, Self::Error> {
|
100
|
+
Ok(match e.event_type() {
|
101
|
+
EventType::TimerStarted => Self::TimerStarted(e.event_id),
|
102
|
+
EventType::TimerCanceled => Self::TimerCanceled,
|
103
|
+
EventType::TimerFired => {
|
104
|
+
if let Some(history_event::Attributes::TimerFiredEventAttributes(attrs)) =
|
105
|
+
e.attributes
|
106
|
+
{
|
107
|
+
Self::TimerFired(attrs)
|
108
|
+
} else {
|
109
|
+
return Err(WFMachinesError::Fatal(format!(
|
110
|
+
"Timer fired attribs were unset: {}",
|
111
|
+
e
|
112
|
+
)));
|
113
|
+
}
|
114
|
+
}
|
115
|
+
_ => {
|
116
|
+
return Err(WFMachinesError::Nondeterminism(format!(
|
117
|
+
"Timer machine does not handle this event: {}",
|
118
|
+
e
|
119
|
+
)))
|
120
|
+
}
|
121
|
+
})
|
122
|
+
}
|
123
|
+
}
|
124
|
+
|
125
|
+
impl TryFrom<CommandType> for TimerMachineEvents {
|
126
|
+
type Error = ();
|
127
|
+
|
128
|
+
fn try_from(c: CommandType) -> Result<Self, Self::Error> {
|
129
|
+
Ok(match c {
|
130
|
+
CommandType::StartTimer => Self::CommandStartTimer,
|
131
|
+
CommandType::CancelTimer => Self::CommandCancelTimer,
|
132
|
+
_ => return Err(()),
|
133
|
+
})
|
134
|
+
}
|
135
|
+
}
|
136
|
+
|
137
|
+
#[derive(Default, Clone)]
|
138
|
+
pub(super) struct Created {}
|
139
|
+
|
140
|
+
impl Created {
|
141
|
+
pub(super) fn on_schedule(self) -> TimerMachineTransition<StartCommandCreated> {
|
142
|
+
TransitionResult::default()
|
143
|
+
}
|
144
|
+
}
|
145
|
+
|
146
|
+
#[derive(Default, Clone)]
|
147
|
+
pub(super) struct CancelTimerCommandCreated {}
|
148
|
+
|
149
|
+
impl CancelTimerCommandCreated {
|
150
|
+
pub(super) fn on_command_cancel_timer(self) -> TimerMachineTransition<CancelTimerCommandSent> {
|
151
|
+
TransitionResult::ok(vec![], CancelTimerCommandSent::default())
|
152
|
+
}
|
153
|
+
}
|
154
|
+
|
155
|
+
#[derive(Default, Clone)]
|
156
|
+
pub(super) struct CancelTimerCommandSent {}
|
157
|
+
|
158
|
+
#[derive(Default, Clone)]
|
159
|
+
pub(super) struct Canceled {}
|
160
|
+
|
161
|
+
impl From<CancelTimerCommandSent> for Canceled {
|
162
|
+
fn from(_: CancelTimerCommandSent) -> Self {
|
163
|
+
Self::default()
|
164
|
+
}
|
165
|
+
}
|
166
|
+
|
167
|
+
#[derive(Default, Clone)]
|
168
|
+
pub(super) struct Fired {}
|
169
|
+
|
170
|
+
#[derive(Default, Clone)]
|
171
|
+
pub(super) struct StartCommandCreated {}
|
172
|
+
|
173
|
+
impl StartCommandCreated {
|
174
|
+
pub(super) fn on_timer_started(
|
175
|
+
self,
|
176
|
+
_id: HistoryEventId,
|
177
|
+
) -> TimerMachineTransition<StartCommandRecorded> {
|
178
|
+
TransitionResult::default()
|
179
|
+
}
|
180
|
+
|
181
|
+
pub(super) fn on_cancel(self, dat: SharedState) -> TimerMachineTransition<Canceled> {
|
182
|
+
TransitionResult::ok_shared(
|
183
|
+
vec![],
|
184
|
+
Canceled::default(),
|
185
|
+
SharedState {
|
186
|
+
cancelled_before_sent: true,
|
187
|
+
..dat
|
188
|
+
},
|
189
|
+
)
|
190
|
+
}
|
191
|
+
}
|
192
|
+
|
193
|
+
#[derive(Default, Clone)]
|
194
|
+
pub(super) struct StartCommandRecorded {}
|
195
|
+
|
196
|
+
impl StartCommandRecorded {
|
197
|
+
pub(super) fn on_timer_fired(
|
198
|
+
self,
|
199
|
+
dat: SharedState,
|
200
|
+
attrs: TimerFiredEventAttributes,
|
201
|
+
) -> TimerMachineTransition<Fired> {
|
202
|
+
if dat.attrs.seq.to_string() == attrs.timer_id {
|
203
|
+
TransitionResult::ok(vec![TimerMachineCommand::Complete], Fired::default())
|
204
|
+
} else {
|
205
|
+
TransitionResult::Err(WFMachinesError::Fatal(format!(
|
206
|
+
"Timer fired event did not have expected timer id {}, it was {}!",
|
207
|
+
dat.attrs.seq, attrs.timer_id
|
208
|
+
)))
|
209
|
+
}
|
210
|
+
}
|
211
|
+
|
212
|
+
pub(super) fn on_cancel(
|
213
|
+
self,
|
214
|
+
dat: SharedState,
|
215
|
+
) -> TimerMachineTransition<CancelTimerCommandCreated> {
|
216
|
+
let cmd = Command {
|
217
|
+
command_type: CommandType::CancelTimer as i32,
|
218
|
+
attributes: Some(CancelTimer { seq: dat.attrs.seq }.into()),
|
219
|
+
};
|
220
|
+
TransitionResult::ok(
|
221
|
+
vec![TimerMachineCommand::IssueCancelCmd(cmd)],
|
222
|
+
CancelTimerCommandCreated::default(),
|
223
|
+
)
|
224
|
+
}
|
225
|
+
}
|
226
|
+
|
227
|
+
impl WFMachinesAdapter for TimerMachine {
|
228
|
+
fn adapt_response(
|
229
|
+
&self,
|
230
|
+
my_command: TimerMachineCommand,
|
231
|
+
_event_info: Option<EventInfo>,
|
232
|
+
) -> Result<Vec<MachineResponse>, WFMachinesError> {
|
233
|
+
Ok(match my_command {
|
234
|
+
// Fire the completion
|
235
|
+
TimerMachineCommand::Complete => vec![FireTimer {
|
236
|
+
seq: self.shared_state.attrs.seq,
|
237
|
+
}
|
238
|
+
.into()],
|
239
|
+
TimerMachineCommand::IssueCancelCmd(c) => vec![MachineResponse::IssueNewCommand(c)],
|
240
|
+
})
|
241
|
+
}
|
242
|
+
|
243
|
+
fn matches_event(&self, event: &HistoryEvent) -> bool {
|
244
|
+
matches!(
|
245
|
+
event.event_type(),
|
246
|
+
EventType::TimerStarted | EventType::TimerCanceled | EventType::TimerFired
|
247
|
+
)
|
248
|
+
}
|
249
|
+
|
250
|
+
fn kind(&self) -> MachineKind {
|
251
|
+
MachineKind::Timer
|
252
|
+
}
|
253
|
+
}
|
254
|
+
|
255
|
+
impl Cancellable for TimerMachine {
|
256
|
+
fn cancel(&mut self) -> Result<Vec<MachineResponse>, MachineError<Self::Error>> {
|
257
|
+
Ok(
|
258
|
+
match OnEventWrapper::on_event_mut(self, TimerMachineEvents::Cancel)?.pop() {
|
259
|
+
Some(TimerMachineCommand::IssueCancelCmd(cmd)) => {
|
260
|
+
vec![MachineResponse::IssueNewCommand(cmd)]
|
261
|
+
}
|
262
|
+
None => vec![],
|
263
|
+
x => panic!("Invalid cancel event response {:?}", x),
|
264
|
+
},
|
265
|
+
)
|
266
|
+
}
|
267
|
+
|
268
|
+
fn was_cancelled_before_sent_to_server(&self) -> bool {
|
269
|
+
self.shared_state().cancelled_before_sent
|
270
|
+
}
|
271
|
+
}
|
272
|
+
|
273
|
+
#[cfg(test)]
|
274
|
+
mod test {
|
275
|
+
use super::*;
|
276
|
+
use crate::{
|
277
|
+
replay::TestHistoryBuilder, test_help::canned_histories, worker::workflow::ManagedWFFunc,
|
278
|
+
};
|
279
|
+
use rstest::{fixture, rstest};
|
280
|
+
use std::{mem::discriminant, time::Duration};
|
281
|
+
use temporal_sdk::{CancellableFuture, WfContext, WorkflowFunction};
|
282
|
+
|
283
|
+
#[fixture]
|
284
|
+
fn happy_wfm() -> ManagedWFFunc {
|
285
|
+
/*
|
286
|
+
We have two versions of this test, one which processes the history in two calls, and one
|
287
|
+
which replays all of it in one go. Both versions must produce the same two activations.
|
288
|
+
However, The former will iterate the machines three times and the latter will iterate
|
289
|
+
them twice.
|
290
|
+
|
291
|
+
There are two workflow tasks, so it seems we should iterate two times, but the reason
|
292
|
+
for the extra iteration in the incremental version is that we need to "wait" for the
|
293
|
+
timer to fire. In the all-in-one-go test, the timer is created and resolved in the same
|
294
|
+
task, hence no extra loop.
|
295
|
+
*/
|
296
|
+
let func = WorkflowFunction::new(|command_sink: WfContext| async move {
|
297
|
+
command_sink.timer(Duration::from_secs(5)).await;
|
298
|
+
Ok(().into())
|
299
|
+
});
|
300
|
+
|
301
|
+
let t = canned_histories::single_timer("1");
|
302
|
+
assert_eq!(2, t.get_full_history_info().unwrap().wf_task_count());
|
303
|
+
ManagedWFFunc::new(t, func, vec![])
|
304
|
+
}
|
305
|
+
|
306
|
+
#[rstest]
|
307
|
+
#[tokio::test]
|
308
|
+
async fn test_fire_happy_path_inc(mut happy_wfm: ManagedWFFunc) {
|
309
|
+
happy_wfm.get_next_activation().await.unwrap();
|
310
|
+
let commands = happy_wfm.get_server_commands().commands;
|
311
|
+
assert_eq!(commands.len(), 1);
|
312
|
+
assert_eq!(commands[0].command_type, CommandType::StartTimer as i32);
|
313
|
+
|
314
|
+
happy_wfm.get_next_activation().await.unwrap();
|
315
|
+
let commands = happy_wfm.get_server_commands().commands;
|
316
|
+
assert_eq!(commands.len(), 1);
|
317
|
+
assert_eq!(commands.len(), 1);
|
318
|
+
assert_eq!(
|
319
|
+
commands[0].command_type,
|
320
|
+
CommandType::CompleteWorkflowExecution as i32
|
321
|
+
);
|
322
|
+
happy_wfm.shutdown().await.unwrap();
|
323
|
+
}
|
324
|
+
|
325
|
+
#[rstest]
|
326
|
+
#[tokio::test]
|
327
|
+
async fn test_fire_happy_path_full(mut happy_wfm: ManagedWFFunc) {
|
328
|
+
happy_wfm.process_all_activations().await.unwrap();
|
329
|
+
let commands = happy_wfm.get_server_commands().commands;
|
330
|
+
assert_eq!(commands.len(), 1);
|
331
|
+
assert_eq!(
|
332
|
+
commands[0].command_type,
|
333
|
+
CommandType::CompleteWorkflowExecution as i32
|
334
|
+
);
|
335
|
+
happy_wfm.shutdown().await.unwrap();
|
336
|
+
}
|
337
|
+
|
338
|
+
#[tokio::test]
|
339
|
+
async fn mismatched_timer_ids_errors() {
|
340
|
+
let func = WorkflowFunction::new(|command_sink: WfContext| async move {
|
341
|
+
command_sink.timer(Duration::from_secs(5)).await;
|
342
|
+
Ok(().into())
|
343
|
+
});
|
344
|
+
|
345
|
+
let t = canned_histories::single_timer("badid");
|
346
|
+
let mut wfm = ManagedWFFunc::new(t, func, vec![]);
|
347
|
+
let act = wfm.process_all_activations().await;
|
348
|
+
assert!(act
|
349
|
+
.unwrap_err()
|
350
|
+
.to_string()
|
351
|
+
.contains("Timer fired event did not have expected timer id 1"));
|
352
|
+
wfm.shutdown().await.unwrap();
|
353
|
+
}
|
354
|
+
|
355
|
+
#[fixture]
|
356
|
+
fn cancellation_setup() -> ManagedWFFunc {
|
357
|
+
let func = WorkflowFunction::new(|ctx: WfContext| async move {
|
358
|
+
let cancel_timer_fut = ctx.timer(Duration::from_secs(500));
|
359
|
+
ctx.timer(Duration::from_secs(5)).await;
|
360
|
+
// Cancel the first timer after having waited on the second
|
361
|
+
cancel_timer_fut.cancel(&ctx);
|
362
|
+
cancel_timer_fut.await;
|
363
|
+
Ok(().into())
|
364
|
+
});
|
365
|
+
|
366
|
+
let t = canned_histories::cancel_timer("2", "1");
|
367
|
+
ManagedWFFunc::new(t, func, vec![])
|
368
|
+
}
|
369
|
+
|
370
|
+
#[rstest]
|
371
|
+
#[tokio::test]
|
372
|
+
async fn incremental_cancellation(#[from(cancellation_setup)] mut wfm: ManagedWFFunc) {
|
373
|
+
wfm.get_next_activation().await.unwrap();
|
374
|
+
let commands = wfm.get_server_commands().commands;
|
375
|
+
assert_eq!(commands.len(), 2);
|
376
|
+
assert_eq!(commands[0].command_type, CommandType::StartTimer as i32);
|
377
|
+
assert_eq!(commands[1].command_type, CommandType::StartTimer as i32);
|
378
|
+
|
379
|
+
wfm.get_next_activation().await.unwrap();
|
380
|
+
let commands = wfm.get_server_commands().commands;
|
381
|
+
assert_eq!(commands.len(), 2);
|
382
|
+
assert_eq!(commands[0].command_type, CommandType::CancelTimer as i32);
|
383
|
+
assert_eq!(
|
384
|
+
commands[1].command_type,
|
385
|
+
CommandType::CompleteWorkflowExecution as i32
|
386
|
+
);
|
387
|
+
|
388
|
+
assert!(wfm.get_next_activation().await.unwrap().jobs.is_empty());
|
389
|
+
let commands = wfm.get_server_commands().commands;
|
390
|
+
// There should be no commands - the wf completed at the same time the timer was cancelled
|
391
|
+
assert_eq!(commands.len(), 0);
|
392
|
+
wfm.shutdown().await.unwrap();
|
393
|
+
}
|
394
|
+
|
395
|
+
#[rstest]
|
396
|
+
#[tokio::test]
|
397
|
+
async fn full_cancellation(#[from(cancellation_setup)] mut wfm: ManagedWFFunc) {
|
398
|
+
wfm.process_all_activations().await.unwrap();
|
399
|
+
let commands = wfm.get_server_commands().commands;
|
400
|
+
// There should be no commands - the wf completed at the same time the timer was cancelled
|
401
|
+
assert_eq!(commands.len(), 0);
|
402
|
+
wfm.shutdown().await.unwrap();
|
403
|
+
}
|
404
|
+
|
405
|
+
#[tokio::test]
|
406
|
+
async fn cancel_before_sent_to_server() {
|
407
|
+
let func = WorkflowFunction::new(|ctx: WfContext| async move {
|
408
|
+
let cancel_timer_fut = ctx.timer(Duration::from_secs(500));
|
409
|
+
// Immediately cancel the timer
|
410
|
+
cancel_timer_fut.cancel(&ctx);
|
411
|
+
cancel_timer_fut.await;
|
412
|
+
Ok(().into())
|
413
|
+
});
|
414
|
+
|
415
|
+
let mut t = TestHistoryBuilder::default();
|
416
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
417
|
+
t.add_full_wf_task();
|
418
|
+
t.add_workflow_execution_completed();
|
419
|
+
let mut wfm = ManagedWFFunc::new(t, func, vec![]);
|
420
|
+
|
421
|
+
wfm.process_all_activations().await.unwrap();
|
422
|
+
let commands = wfm.get_server_commands().commands;
|
423
|
+
assert_eq!(commands.len(), 0);
|
424
|
+
wfm.shutdown().await.unwrap();
|
425
|
+
}
|
426
|
+
|
427
|
+
#[test]
|
428
|
+
fn cancels_ignored_terminal() {
|
429
|
+
for state in [TimerMachineState::Canceled(Canceled {}), Fired {}.into()] {
|
430
|
+
let mut s = TimerMachine {
|
431
|
+
state: state.clone(),
|
432
|
+
shared_state: Default::default(),
|
433
|
+
};
|
434
|
+
let cmds = s.cancel().unwrap();
|
435
|
+
assert_eq!(cmds.len(), 0);
|
436
|
+
assert_eq!(discriminant(&state), discriminant(&s.state));
|
437
|
+
}
|
438
|
+
}
|
439
|
+
}
|
@@ -0,0 +1,169 @@
|
|
1
|
+
//! Look, I'm not happy about the code in here, and you shouldn't be either. This is all an awful,
|
2
|
+
//! dirty hack to work around the fact that there's no such thing as "run this after all unit tests"
|
3
|
+
//! in stable Rust. Don't do the things in here. They're bad. This is test only code, and should
|
4
|
+
//! never ever be removed from behind `#[cfg(test)]` compilation.
|
5
|
+
|
6
|
+
use dashmap::{mapref::entry::Entry, DashMap, DashSet};
|
7
|
+
use std::{
|
8
|
+
path::PathBuf,
|
9
|
+
sync::{
|
10
|
+
mpsc::{sync_channel, SyncSender},
|
11
|
+
Mutex,
|
12
|
+
},
|
13
|
+
thread::JoinHandle,
|
14
|
+
time::Duration,
|
15
|
+
};
|
16
|
+
|
17
|
+
// During test we want to know about which transitions we've covered in state machines
|
18
|
+
lazy_static::lazy_static! {
|
19
|
+
static ref COVERED_TRANSITIONS: DashMap<String, DashSet<CoveredTransition>>
|
20
|
+
= DashMap::new();
|
21
|
+
static ref COVERAGE_SENDER: SyncSender<(String, CoveredTransition)> =
|
22
|
+
spawn_save_coverage_at_end();
|
23
|
+
static ref THREAD_HANDLE: Mutex<Option<JoinHandle<()>>> = Mutex::new(None);
|
24
|
+
}
|
25
|
+
|
26
|
+
#[derive(Eq, PartialEq, Hash, Debug)]
|
27
|
+
struct CoveredTransition {
|
28
|
+
from_state: String,
|
29
|
+
to_state: String,
|
30
|
+
event: String,
|
31
|
+
}
|
32
|
+
|
33
|
+
pub fn add_coverage(machine_name: String, from_state: String, to_state: String, event: String) {
|
34
|
+
let ct = CoveredTransition {
|
35
|
+
from_state,
|
36
|
+
to_state,
|
37
|
+
event,
|
38
|
+
};
|
39
|
+
let _ = COVERAGE_SENDER.send((machine_name, ct));
|
40
|
+
}
|
41
|
+
|
42
|
+
fn spawn_save_coverage_at_end() -> SyncSender<(String, CoveredTransition)> {
|
43
|
+
let (tx, rx) = sync_channel(1000);
|
44
|
+
let handle = std::thread::spawn(move || {
|
45
|
+
// Assume that, if the entire program hasn't run a state machine transition in the
|
46
|
+
// last second that we are probably done running all the tests. This is to avoid
|
47
|
+
// needing to instrument every single test.
|
48
|
+
while let Ok((machine_name, ct)) = rx.recv_timeout(Duration::from_secs(1)) {
|
49
|
+
match COVERED_TRANSITIONS.entry(machine_name) {
|
50
|
+
Entry::Occupied(o) => {
|
51
|
+
o.get().insert(ct);
|
52
|
+
}
|
53
|
+
Entry::Vacant(v) => {
|
54
|
+
v.insert({
|
55
|
+
let ds = DashSet::new();
|
56
|
+
ds.insert(ct);
|
57
|
+
ds
|
58
|
+
});
|
59
|
+
}
|
60
|
+
}
|
61
|
+
}
|
62
|
+
});
|
63
|
+
*THREAD_HANDLE.lock().unwrap() = Some(handle);
|
64
|
+
tx
|
65
|
+
}
|
66
|
+
|
67
|
+
#[cfg(test)]
|
68
|
+
mod machine_coverage_report {
|
69
|
+
use super::*;
|
70
|
+
use crate::worker::workflow::machines::{
|
71
|
+
activity_state_machine::ActivityMachine,
|
72
|
+
cancel_external_state_machine::CancelExternalMachine,
|
73
|
+
cancel_workflow_state_machine::CancelWorkflowMachine,
|
74
|
+
child_workflow_state_machine::ChildWorkflowMachine,
|
75
|
+
complete_workflow_state_machine::CompleteWorkflowMachine,
|
76
|
+
continue_as_new_workflow_state_machine::ContinueAsNewWorkflowMachine,
|
77
|
+
fail_workflow_state_machine::FailWorkflowMachine,
|
78
|
+
local_activity_state_machine::LocalActivityMachine, patch_state_machine::PatchMachine,
|
79
|
+
signal_external_state_machine::SignalExternalMachine, timer_state_machine::TimerMachine,
|
80
|
+
upsert_search_attributes_state_machine::UpsertSearchAttributesMachine,
|
81
|
+
workflow_task_state_machine::WorkflowTaskMachine,
|
82
|
+
};
|
83
|
+
use rustfsm::StateMachine;
|
84
|
+
use std::{fs::File, io::Write};
|
85
|
+
|
86
|
+
// This "test" needs to exist so that we have a way to join the spawned thread. Otherwise
|
87
|
+
// it'll just get abandoned.
|
88
|
+
#[test]
|
89
|
+
// Use `cargo test -- --include-ignored` to run this. We don't want to bother with it by default
|
90
|
+
// because it takes a minimum of a second.
|
91
|
+
#[ignore]
|
92
|
+
fn reporter() {
|
93
|
+
// Make sure thread handle exists
|
94
|
+
let _ = &*COVERAGE_SENDER;
|
95
|
+
// Join it
|
96
|
+
THREAD_HANDLE
|
97
|
+
.lock()
|
98
|
+
.unwrap()
|
99
|
+
.take()
|
100
|
+
.unwrap()
|
101
|
+
.join()
|
102
|
+
.unwrap();
|
103
|
+
|
104
|
+
// Gather visualizations for all machines
|
105
|
+
let mut activity = ActivityMachine::visualizer().to_owned();
|
106
|
+
let mut timer = TimerMachine::visualizer().to_owned();
|
107
|
+
let mut child_wf = ChildWorkflowMachine::visualizer().to_owned();
|
108
|
+
let mut complete_wf = CompleteWorkflowMachine::visualizer().to_owned();
|
109
|
+
let mut wf_task = WorkflowTaskMachine::visualizer().to_owned();
|
110
|
+
let mut fail_wf = FailWorkflowMachine::visualizer().to_owned();
|
111
|
+
let mut cont_as_new = ContinueAsNewWorkflowMachine::visualizer().to_owned();
|
112
|
+
let mut cancel_wf = CancelWorkflowMachine::visualizer().to_owned();
|
113
|
+
let mut version = PatchMachine::visualizer().to_owned();
|
114
|
+
let mut signal_ext = SignalExternalMachine::visualizer().to_owned();
|
115
|
+
let mut cancel_ext = CancelExternalMachine::visualizer().to_owned();
|
116
|
+
let mut la_mach = LocalActivityMachine::visualizer().to_owned();
|
117
|
+
let mut upsert_search_attr = UpsertSearchAttributesMachine::visualizer().to_owned();
|
118
|
+
|
119
|
+
// This isn't at all efficient but doesn't need to be.
|
120
|
+
// Replace transitions in the vizzes with green color if they are covered.
|
121
|
+
for item in COVERED_TRANSITIONS.iter() {
|
122
|
+
let (machine, coverage) = item.pair();
|
123
|
+
match machine.as_ref() {
|
124
|
+
m @ "ActivityMachine" => cover_transitions(m, &mut activity, coverage),
|
125
|
+
m @ "TimerMachine" => cover_transitions(m, &mut timer, coverage),
|
126
|
+
m @ "ChildWorkflowMachine" => cover_transitions(m, &mut child_wf, coverage),
|
127
|
+
m @ "CompleteWorkflowMachine" => cover_transitions(m, &mut complete_wf, coverage),
|
128
|
+
m @ "WorkflowTaskMachine" => cover_transitions(m, &mut wf_task, coverage),
|
129
|
+
m @ "FailWorkflowMachine" => cover_transitions(m, &mut fail_wf, coverage),
|
130
|
+
m @ "ContinueAsNewWorkflowMachine" => {
|
131
|
+
cover_transitions(m, &mut cont_as_new, coverage);
|
132
|
+
}
|
133
|
+
m @ "CancelWorkflowMachine" => cover_transitions(m, &mut cancel_wf, coverage),
|
134
|
+
m @ "PatchMachine" => cover_transitions(m, &mut version, coverage),
|
135
|
+
m @ "SignalExternalMachine" => cover_transitions(m, &mut signal_ext, coverage),
|
136
|
+
m @ "CancelExternalMachine" => cover_transitions(m, &mut cancel_ext, coverage),
|
137
|
+
m @ "LocalActivityMachine" => cover_transitions(m, &mut la_mach, coverage),
|
138
|
+
m @ "UpsertSearchAttributesMachine" => {
|
139
|
+
cover_transitions(m, &mut upsert_search_attr, coverage)
|
140
|
+
}
|
141
|
+
m => panic!("Unknown machine {}", m),
|
142
|
+
}
|
143
|
+
}
|
144
|
+
}
|
145
|
+
|
146
|
+
fn cover_transitions(machine: &str, viz: &mut String, cov: &DashSet<CoveredTransition>) {
|
147
|
+
for trans in cov.iter() {
|
148
|
+
let find_line = format!(
|
149
|
+
"{} --> {}: {}",
|
150
|
+
trans.from_state, trans.to_state, trans.event
|
151
|
+
);
|
152
|
+
if let Some(start) = viz.find(&find_line) {
|
153
|
+
let new_line = format!(
|
154
|
+
"{} -[#blue]-> {}: {}",
|
155
|
+
trans.from_state, trans.to_state, trans.event
|
156
|
+
);
|
157
|
+
viz.replace_range(start..start + find_line.len(), &new_line);
|
158
|
+
}
|
159
|
+
}
|
160
|
+
|
161
|
+
// Dump the updated viz to a file
|
162
|
+
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
163
|
+
d.push("machine_coverage");
|
164
|
+
std::fs::create_dir_all(&d).unwrap();
|
165
|
+
d.push(format!("{}_Coverage.puml", machine));
|
166
|
+
let mut file = File::create(d).unwrap();
|
167
|
+
file.write_all(viz.as_bytes()).unwrap();
|
168
|
+
}
|
169
|
+
}
|