temporalio 0.0.1 → 0.1.0
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 +180 -7
- data/bridge/Cargo.lock +208 -76
- data/bridge/Cargo.toml +5 -2
- data/bridge/sdk-core/Cargo.toml +1 -1
- data/bridge/sdk-core/README.md +20 -10
- data/bridge/sdk-core/client/Cargo.toml +1 -1
- data/bridge/sdk-core/client/src/lib.rs +227 -59
- data/bridge/sdk-core/client/src/metrics.rs +17 -8
- data/bridge/sdk-core/client/src/raw.rs +13 -12
- data/bridge/sdk-core/client/src/retry.rs +132 -43
- data/bridge/sdk-core/core/Cargo.toml +28 -15
- data/bridge/sdk-core/core/benches/workflow_replay.rs +13 -10
- data/bridge/sdk-core/core/src/abstractions.rs +225 -36
- data/bridge/sdk-core/core/src/core_tests/activity_tasks.rs +217 -79
- data/bridge/sdk-core/core/src/core_tests/determinism.rs +165 -2
- data/bridge/sdk-core/core/src/core_tests/local_activities.rs +565 -34
- data/bridge/sdk-core/core/src/core_tests/queries.rs +247 -90
- data/bridge/sdk-core/core/src/core_tests/workers.rs +3 -5
- data/bridge/sdk-core/core/src/core_tests/workflow_cancels.rs +1 -1
- data/bridge/sdk-core/core/src/core_tests/workflow_tasks.rs +430 -67
- data/bridge/sdk-core/core/src/ephemeral_server/mod.rs +106 -12
- data/bridge/sdk-core/core/src/internal_flags.rs +136 -0
- data/bridge/sdk-core/core/src/lib.rs +148 -34
- data/bridge/sdk-core/core/src/protosext/mod.rs +1 -1
- data/bridge/sdk-core/core/src/replay/mod.rs +185 -41
- data/bridge/sdk-core/core/src/telemetry/log_export.rs +190 -0
- data/bridge/sdk-core/core/src/telemetry/metrics.rs +219 -140
- data/bridge/sdk-core/core/src/telemetry/mod.rs +326 -315
- data/bridge/sdk-core/core/src/telemetry/prometheus_server.rs +20 -14
- data/bridge/sdk-core/core/src/test_help/mod.rs +85 -21
- data/bridge/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +112 -156
- data/bridge/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
- data/bridge/sdk-core/core/src/worker/activities/local_activities.rs +364 -128
- data/bridge/sdk-core/core/src/worker/activities.rs +263 -170
- data/bridge/sdk-core/core/src/worker/client/mocks.rs +23 -3
- data/bridge/sdk-core/core/src/worker/client.rs +48 -6
- data/bridge/sdk-core/core/src/worker/mod.rs +186 -75
- data/bridge/sdk-core/core/src/worker/workflow/bridge.rs +1 -3
- data/bridge/sdk-core/core/src/worker/workflow/driven_workflow.rs +13 -24
- data/bridge/sdk-core/core/src/worker/workflow/history_update.rs +879 -226
- data/bridge/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +101 -48
- data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +8 -12
- data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +6 -9
- data/bridge/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +90 -32
- data/bridge/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +6 -9
- data/bridge/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +7 -10
- data/bridge/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +6 -9
- data/bridge/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +160 -83
- data/bridge/sdk-core/core/src/worker/workflow/machines/mod.rs +36 -54
- data/bridge/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +179 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +104 -157
- data/bridge/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +8 -12
- data/bridge/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +9 -13
- data/bridge/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +10 -4
- data/bridge/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +14 -11
- data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +6 -17
- data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +395 -299
- data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +12 -20
- data/bridge/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +33 -18
- data/bridge/sdk-core/core/src/worker/workflow/managed_run.rs +1032 -374
- data/bridge/sdk-core/core/src/worker/workflow/mod.rs +525 -392
- data/bridge/sdk-core/core/src/worker/workflow/run_cache.rs +40 -57
- data/bridge/sdk-core/core/src/worker/workflow/wft_extraction.rs +125 -0
- data/bridge/sdk-core/core/src/worker/workflow/wft_poller.rs +3 -6
- data/bridge/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +117 -0
- data/bridge/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +24 -0
- data/bridge/sdk-core/core/src/worker/workflow/workflow_stream.rs +456 -681
- data/bridge/sdk-core/core-api/Cargo.toml +6 -4
- data/bridge/sdk-core/core-api/src/errors.rs +1 -34
- data/bridge/sdk-core/core-api/src/lib.rs +7 -45
- data/bridge/sdk-core/core-api/src/telemetry.rs +141 -0
- data/bridge/sdk-core/core-api/src/worker.rs +27 -1
- data/bridge/sdk-core/etc/deps.svg +115 -140
- data/bridge/sdk-core/etc/regen-depgraph.sh +5 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +18 -15
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +1 -1
- data/bridge/sdk-core/fsm/rustfsm_trait/src/lib.rs +8 -3
- data/bridge/sdk-core/histories/evict_while_la_running_no_interference-16_history.bin +0 -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/protos/api_upstream/buf.yaml +0 -3
- 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/{temporal/api/enums/v1/cluster.proto → build/tools.go} +7 -18
- data/bridge/sdk-core/protos/api_upstream/go.mod +6 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +12 -9
- data/bridge/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +15 -26
- data/bridge/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +13 -2
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +3 -2
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +4 -9
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +3 -2
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +10 -8
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +28 -2
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +2 -2
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +2 -2
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +2 -2
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +2 -2
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +2 -2
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +24 -19
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +2 -2
- data/bridge/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +2 -2
- data/bridge/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +2 -2
- data/bridge/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +2 -2
- data/bridge/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +62 -26
- data/bridge/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +4 -2
- data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +24 -61
- data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +2 -21
- data/bridge/sdk-core/protos/api_upstream/temporal/api/protocol/v1/message.proto +57 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +2 -2
- data/bridge/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +2 -2
- data/bridge/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +110 -31
- data/bridge/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +4 -4
- data/bridge/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +71 -6
- data/bridge/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +2 -2
- data/bridge/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +3 -2
- data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +111 -36
- data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +19 -5
- data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +1 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +1 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +1 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +1 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +9 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +9 -1
- data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +6 -0
- data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +2 -2
- data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +2 -2
- data/bridge/sdk-core/sdk/Cargo.toml +4 -3
- data/bridge/sdk-core/sdk/src/interceptors.rs +36 -3
- data/bridge/sdk-core/sdk/src/lib.rs +94 -25
- data/bridge/sdk-core/sdk/src/workflow_context.rs +13 -2
- data/bridge/sdk-core/sdk/src/workflow_future.rs +10 -13
- data/bridge/sdk-core/sdk-core-protos/Cargo.toml +5 -2
- data/bridge/sdk-core/sdk-core-protos/build.rs +36 -2
- data/bridge/sdk-core/sdk-core-protos/src/history_builder.rs +164 -104
- data/bridge/sdk-core/sdk-core-protos/src/history_info.rs +27 -23
- data/bridge/sdk-core/sdk-core-protos/src/lib.rs +252 -74
- data/bridge/sdk-core/sdk-core-protos/src/task_token.rs +12 -2
- data/bridge/sdk-core/test-utils/Cargo.toml +4 -1
- data/bridge/sdk-core/test-utils/src/canned_histories.rs +106 -296
- data/bridge/sdk-core/test-utils/src/histfetch.rs +1 -1
- data/bridge/sdk-core/test-utils/src/lib.rs +161 -50
- data/bridge/sdk-core/test-utils/src/wf_input_saver.rs +50 -0
- data/bridge/sdk-core/test-utils/src/workflows.rs +29 -0
- data/bridge/sdk-core/tests/fuzzy_workflow.rs +130 -0
- data/bridge/sdk-core/tests/{load_tests.rs → heavy_tests.rs} +125 -51
- data/bridge/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
- data/bridge/sdk-core/tests/integ_tests/heartbeat_tests.rs +10 -5
- data/bridge/sdk-core/tests/integ_tests/metrics_tests.rs +239 -0
- data/bridge/sdk-core/tests/integ_tests/polling_tests.rs +4 -60
- data/bridge/sdk-core/tests/integ_tests/queries_tests.rs +5 -128
- data/bridge/sdk-core/tests/integ_tests/visibility_tests.rs +83 -25
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/activities.rs +93 -69
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +6 -13
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +1 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +6 -2
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -10
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +151 -116
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +54 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/patches.rs +7 -28
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/replay.rs +115 -24
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/signals.rs +18 -14
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +6 -20
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/timers.rs +10 -21
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +6 -4
- data/bridge/sdk-core/tests/integ_tests/workflow_tests.rs +27 -18
- data/bridge/sdk-core/tests/main.rs +8 -16
- data/bridge/sdk-core/tests/runner.rs +75 -36
- data/bridge/sdk-core/tests/wf_input_replay.rs +32 -0
- data/bridge/src/connection.rs +117 -82
- data/bridge/src/lib.rs +356 -42
- data/bridge/src/runtime.rs +10 -3
- data/bridge/src/test_server.rs +153 -0
- data/bridge/src/worker.rs +133 -9
- data/lib/gen/temporal/api/batch/v1/message_pb.rb +8 -6
- data/lib/gen/temporal/api/command/v1/message_pb.rb +10 -16
- data/lib/gen/temporal/api/common/v1/message_pb.rb +5 -1
- data/lib/gen/temporal/api/enums/v1/batch_operation_pb.rb +2 -1
- data/lib/gen/temporal/api/enums/v1/command_type_pb.rb +3 -3
- data/lib/gen/temporal/api/enums/v1/common_pb.rb +2 -1
- data/lib/gen/temporal/api/enums/v1/event_type_pb.rb +5 -4
- data/lib/gen/temporal/api/enums/v1/failed_cause_pb.rb +9 -1
- data/lib/gen/temporal/api/enums/v1/namespace_pb.rb +1 -1
- data/lib/gen/temporal/api/enums/v1/query_pb.rb +1 -1
- data/lib/gen/temporal/api/enums/v1/reset_pb.rb +1 -1
- data/lib/gen/temporal/api/enums/v1/schedule_pb.rb +1 -1
- data/lib/gen/temporal/api/enums/v1/task_queue_pb.rb +1 -1
- data/lib/gen/temporal/api/enums/v1/update_pb.rb +7 -10
- data/lib/gen/temporal/api/enums/v1/workflow_pb.rb +1 -1
- data/lib/gen/temporal/api/errordetails/v1/message_pb.rb +1 -1
- data/lib/gen/temporal/api/failure/v1/message_pb.rb +1 -1
- data/lib/gen/temporal/api/filter/v1/message_pb.rb +1 -1
- data/lib/gen/temporal/api/history/v1/message_pb.rb +34 -25
- data/lib/gen/temporal/api/namespace/v1/message_pb.rb +2 -1
- data/lib/gen/temporal/api/operatorservice/v1/request_response_pb.rb +14 -51
- data/lib/gen/temporal/api/operatorservice/v1/service_pb.rb +1 -1
- data/lib/gen/temporal/api/protocol/v1/message_pb.rb +30 -0
- data/lib/gen/temporal/api/query/v1/message_pb.rb +1 -1
- data/lib/gen/temporal/api/replication/v1/message_pb.rb +1 -1
- data/lib/gen/temporal/api/schedule/v1/message_pb.rb +22 -1
- data/lib/gen/temporal/api/sdk/v1/task_complete_metadata_pb.rb +23 -0
- data/lib/gen/temporal/api/taskqueue/v1/message_pb.rb +2 -2
- data/lib/gen/temporal/api/testservice/v1/request_response_pb.rb +49 -0
- data/lib/gen/temporal/api/testservice/v1/service_pb.rb +21 -0
- data/lib/gen/temporal/api/update/v1/message_pb.rb +49 -3
- data/lib/gen/temporal/api/version/v1/message_pb.rb +1 -1
- data/lib/gen/temporal/api/workflow/v1/message_pb.rb +2 -1
- data/lib/gen/temporal/api/workflowservice/v1/request_response_pb.rb +47 -20
- data/lib/gen/temporal/api/workflowservice/v1/service_pb.rb +1 -1
- data/lib/gen/temporal/sdk/core/activity_result/activity_result_pb.rb +13 -9
- data/lib/gen/temporal/sdk/core/activity_task/activity_task_pb.rb +10 -6
- data/lib/gen/temporal/sdk/core/child_workflow/child_workflow_pb.rb +13 -9
- data/lib/gen/temporal/sdk/core/common/common_pb.rb +7 -3
- data/lib/gen/temporal/sdk/core/core_interface_pb.rb +9 -3
- data/lib/gen/temporal/sdk/core/external_data/external_data_pb.rb +7 -3
- data/lib/gen/temporal/sdk/core/workflow_activation/workflow_activation_pb.rb +28 -21
- data/lib/gen/temporal/sdk/core/workflow_commands/workflow_commands_pb.rb +32 -24
- data/lib/gen/temporal/sdk/core/workflow_completion/workflow_completion_pb.rb +12 -5
- data/lib/temporalio/activity/context.rb +102 -0
- data/lib/temporalio/activity/info.rb +67 -0
- data/lib/temporalio/activity.rb +85 -0
- data/lib/temporalio/bridge/connect_options.rb +15 -0
- data/lib/temporalio/bridge/error.rb +8 -0
- data/lib/temporalio/bridge/retry_config.rb +24 -0
- data/lib/temporalio/bridge/tls_options.rb +19 -0
- data/lib/temporalio/bridge.rb +14 -0
- data/lib/{temporal → temporalio}/client/implementation.rb +57 -56
- data/lib/{temporal → temporalio}/client/workflow_handle.rb +35 -35
- data/lib/{temporal → temporalio}/client.rb +19 -32
- data/lib/temporalio/connection/retry_config.rb +44 -0
- data/lib/temporalio/connection/service.rb +20 -0
- data/lib/temporalio/connection/test_service.rb +92 -0
- data/lib/temporalio/connection/tls_options.rb +51 -0
- data/lib/temporalio/connection/workflow_service.rb +731 -0
- data/lib/temporalio/connection.rb +86 -0
- data/lib/{temporal → temporalio}/data_converter.rb +76 -35
- data/lib/{temporal → temporalio}/error/failure.rb +6 -6
- data/lib/{temporal → temporalio}/error/workflow_failure.rb +4 -2
- data/lib/{temporal → temporalio}/errors.rb +19 -1
- data/lib/{temporal → temporalio}/failure_converter/base.rb +5 -5
- data/lib/{temporal → temporalio}/failure_converter/basic.rb +58 -52
- data/lib/temporalio/failure_converter.rb +7 -0
- data/lib/temporalio/interceptor/activity_inbound.rb +22 -0
- data/lib/temporalio/interceptor/activity_outbound.rb +24 -0
- data/lib/{temporal → temporalio}/interceptor/chain.rb +7 -6
- data/lib/{temporal → temporalio}/interceptor/client.rb +27 -2
- data/lib/temporalio/interceptor.rb +22 -0
- data/lib/{temporal → temporalio}/payload_codec/base.rb +5 -5
- data/lib/{temporal → temporalio}/payload_converter/base.rb +3 -3
- data/lib/{temporal → temporalio}/payload_converter/bytes.rb +4 -3
- data/lib/{temporal → temporalio}/payload_converter/composite.rb +7 -5
- data/lib/{temporal → temporalio}/payload_converter/encoding_base.rb +4 -4
- data/lib/{temporal → temporalio}/payload_converter/json.rb +4 -3
- data/lib/{temporal → temporalio}/payload_converter/nil.rb +4 -3
- data/lib/temporalio/payload_converter.rb +14 -0
- data/lib/{temporal → temporalio}/retry_policy.rb +17 -7
- data/lib/{temporal → temporalio}/retry_state.rb +1 -1
- data/lib/temporalio/runtime.rb +25 -0
- data/lib/temporalio/testing/time_skipping_handle.rb +32 -0
- data/lib/temporalio/testing/time_skipping_interceptor.rb +23 -0
- data/lib/temporalio/testing/workflow_environment.rb +112 -0
- data/lib/temporalio/testing.rb +175 -0
- data/lib/{temporal → temporalio}/timeout_type.rb +2 -2
- data/lib/temporalio/version.rb +3 -0
- data/lib/temporalio/worker/activity_runner.rb +114 -0
- data/lib/temporalio/worker/activity_worker.rb +164 -0
- data/lib/temporalio/worker/reactor.rb +46 -0
- data/lib/temporalio/worker/runner.rb +63 -0
- data/lib/temporalio/worker/sync_worker.rb +124 -0
- data/lib/temporalio/worker/thread_pool_executor.rb +51 -0
- data/lib/temporalio/worker.rb +204 -0
- data/lib/temporalio/workflow/async.rb +46 -0
- data/lib/{temporal → temporalio}/workflow/execution_info.rb +4 -4
- data/lib/{temporal → temporalio}/workflow/execution_status.rb +1 -1
- data/lib/temporalio/workflow/future.rb +138 -0
- data/lib/{temporal → temporalio}/workflow/id_reuse_policy.rb +6 -6
- data/lib/temporalio/workflow/info.rb +76 -0
- data/lib/{temporal → temporalio}/workflow/query_reject_condition.rb +5 -5
- data/lib/temporalio.rb +12 -3
- data/temporalio.gemspec +11 -6
- metadata +137 -64
- data/bridge/sdk-core/Cargo.lock +0 -2606
- data/bridge/sdk-core/bridge-ffi/Cargo.toml +0 -24
- data/bridge/sdk-core/bridge-ffi/LICENSE.txt +0 -23
- data/bridge/sdk-core/bridge-ffi/build.rs +0 -25
- data/bridge/sdk-core/bridge-ffi/include/sdk-core-bridge.h +0 -249
- data/bridge/sdk-core/bridge-ffi/src/lib.rs +0 -825
- data/bridge/sdk-core/bridge-ffi/src/wrappers.rs +0 -211
- data/bridge/sdk-core/core/src/log_export.rs +0 -62
- data/bridge/sdk-core/core/src/worker/workflow/machines/mutable_side_effect_state_machine.rs +0 -127
- data/bridge/sdk-core/core/src/worker/workflow/machines/side_effect_state_machine.rs +0 -71
- data/bridge/sdk-core/protos/api_upstream/temporal/api/cluster/v1/message.proto +0 -83
- data/bridge/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +0 -210
- data/bridge/sdk-core/sdk/src/conversions.rs +0 -8
- data/lib/bridge.so +0 -0
- data/lib/gen/temporal/api/cluster/v1/message_pb.rb +0 -67
- data/lib/gen/temporal/api/enums/v1/cluster_pb.rb +0 -26
- data/lib/gen/temporal/sdk/core/bridge/bridge_pb.rb +0 -222
- data/lib/temporal/bridge.rb +0 -14
- data/lib/temporal/connection.rb +0 -736
- data/lib/temporal/failure_converter.rb +0 -8
- data/lib/temporal/payload_converter.rb +0 -14
- data/lib/temporal/runtime.rb +0 -22
- data/lib/temporal/version.rb +0 -3
- data/lib/temporal.rb +0 -8
|
@@ -1,26 +1,32 @@
|
|
|
1
1
|
mod local_acts;
|
|
2
2
|
|
|
3
|
-
pub(crate) use temporal_sdk_core_api::errors::WFMachinesError;
|
|
4
|
-
|
|
5
3
|
use super::{
|
|
6
|
-
|
|
4
|
+
cancel_external_state_machine::new_external_cancel,
|
|
7
5
|
cancel_workflow_state_machine::cancel_workflow,
|
|
8
|
-
child_workflow_state_machine::new_child_workflow,
|
|
9
6
|
complete_workflow_state_machine::complete_workflow,
|
|
10
7
|
continue_as_new_workflow_state_machine::continue_as_new,
|
|
11
8
|
fail_workflow_state_machine::fail_workflow, local_activity_state_machine::new_local_activity,
|
|
12
9
|
patch_state_machine::has_change, signal_external_state_machine::new_external_signal,
|
|
13
10
|
timer_state_machine::new_timer, upsert_search_attributes_state_machine::upsert_search_attrs,
|
|
14
11
|
workflow_machines::local_acts::LocalActivityData,
|
|
15
|
-
workflow_task_state_machine::WorkflowTaskMachine,
|
|
12
|
+
workflow_task_state_machine::WorkflowTaskMachine, Machines, NewMachineWithCommand,
|
|
16
13
|
TemporalStateMachine,
|
|
17
14
|
};
|
|
18
15
|
use crate::{
|
|
16
|
+
internal_flags::InternalFlags,
|
|
19
17
|
protosext::{HistoryEventExt, ValidScheduleLA},
|
|
20
18
|
telemetry::{metrics::MetricsContext, VecDisplayer},
|
|
21
19
|
worker::{
|
|
22
20
|
workflow::{
|
|
23
|
-
|
|
21
|
+
history_update::NextWFT,
|
|
22
|
+
machines::{
|
|
23
|
+
activity_state_machine::ActivityMachine,
|
|
24
|
+
child_workflow_state_machine::ChildWorkflowMachine,
|
|
25
|
+
modify_workflow_properties_state_machine::modify_workflow_properties,
|
|
26
|
+
HistEventData,
|
|
27
|
+
},
|
|
28
|
+
CommandID, DrivenWorkflow, HistoryUpdate, InternalFlagsRef, LocalResolution,
|
|
29
|
+
OutgoingJob, RunBasics, WFCommand, WFMachinesError, WorkflowFetcher,
|
|
24
30
|
WorkflowStartedInfo,
|
|
25
31
|
},
|
|
26
32
|
ExecutingLAId, LocalActRequest, LocalActivityExecutionResult, LocalActivityResolution,
|
|
@@ -30,14 +36,17 @@ use siphasher::sip::SipHasher13;
|
|
|
30
36
|
use slotmap::{SlotMap, SparseSecondaryMap};
|
|
31
37
|
use std::{
|
|
32
38
|
borrow::{Borrow, BorrowMut},
|
|
39
|
+
cell::RefCell,
|
|
33
40
|
collections::{HashMap, VecDeque},
|
|
34
41
|
convert::TryInto,
|
|
35
42
|
hash::{Hash, Hasher},
|
|
43
|
+
rc::Rc,
|
|
36
44
|
time::{Duration, Instant, SystemTime},
|
|
37
45
|
};
|
|
38
46
|
use temporal_sdk_core_protos::{
|
|
39
47
|
coresdk::{
|
|
40
48
|
common::NamespacedWorkflowExecution,
|
|
49
|
+
workflow_activation,
|
|
41
50
|
workflow_activation::{
|
|
42
51
|
workflow_activation_job, NotifyHasPatch, UpdateRandomSeed, WorkflowActivation,
|
|
43
52
|
},
|
|
@@ -49,6 +58,7 @@ use temporal_sdk_core_protos::{
|
|
|
49
58
|
command::v1::{command::Attributes as ProtoCmdAttrs, Command as ProtoCommand},
|
|
50
59
|
enums::v1::EventType,
|
|
51
60
|
history::v1::{history_event, HistoryEvent},
|
|
61
|
+
sdk::v1::WorkflowTaskCompletedMetadata,
|
|
52
62
|
},
|
|
53
63
|
};
|
|
54
64
|
|
|
@@ -93,6 +103,9 @@ pub(crate) struct WorkflowMachines {
|
|
|
93
103
|
/// The current workflow time if it has been established. This may differ from the WFT start
|
|
94
104
|
/// time since local activities may advance the clock
|
|
95
105
|
current_wf_time: Option<SystemTime>,
|
|
106
|
+
/// The internal flags which have been seen so far during this run's execution and thus are
|
|
107
|
+
/// usable during replay.
|
|
108
|
+
observed_internal_flags: InternalFlagsRef,
|
|
96
109
|
|
|
97
110
|
all_machines: SlotMap<MachineKey, Machines>,
|
|
98
111
|
/// If a machine key is in this map, that machine was created internally by core, not as a
|
|
@@ -131,7 +144,7 @@ pub(crate) struct WorkflowMachines {
|
|
|
131
144
|
}
|
|
132
145
|
|
|
133
146
|
#[derive(Debug, derive_more::Display)]
|
|
134
|
-
#[display(fmt = "Cmd&Machine({})"
|
|
147
|
+
#[display(fmt = "Cmd&Machine({command})")]
|
|
135
148
|
struct CommandAndMachine {
|
|
136
149
|
command: MachineAssociatedCommand,
|
|
137
150
|
machine: MachineKey,
|
|
@@ -140,7 +153,7 @@ struct CommandAndMachine {
|
|
|
140
153
|
#[derive(Debug, derive_more::Display)]
|
|
141
154
|
enum MachineAssociatedCommand {
|
|
142
155
|
Real(Box<ProtoCommand>),
|
|
143
|
-
#[display(fmt = "FakeLocalActivityMarker({})"
|
|
156
|
+
#[display(fmt = "FakeLocalActivityMarker({_0})")]
|
|
144
157
|
FakeLocalActivityMarker(u32),
|
|
145
158
|
}
|
|
146
159
|
|
|
@@ -153,9 +166,9 @@ struct ChangeInfo {
|
|
|
153
166
|
#[derive(Debug, derive_more::Display)]
|
|
154
167
|
#[must_use]
|
|
155
168
|
#[allow(clippy::large_enum_variant)]
|
|
156
|
-
pub enum MachineResponse {
|
|
157
|
-
#[display(fmt = "PushWFJob({})"
|
|
158
|
-
PushWFJob(
|
|
169
|
+
pub(super) enum MachineResponse {
|
|
170
|
+
#[display(fmt = "PushWFJob({_0})")]
|
|
171
|
+
PushWFJob(OutgoingJob),
|
|
159
172
|
|
|
160
173
|
/// Pushes a new command into the list that will be sent to server once we respond with the
|
|
161
174
|
/// workflow task completion
|
|
@@ -163,31 +176,31 @@ pub enum MachineResponse {
|
|
|
163
176
|
/// The machine requests the creation of another *different* machine. This acts as if lang
|
|
164
177
|
/// had replied to the activation with a command, but we use a special set of IDs to avoid
|
|
165
178
|
/// collisions.
|
|
166
|
-
#[display(fmt = "NewCoreOriginatedCommand({:?})"
|
|
179
|
+
#[display(fmt = "NewCoreOriginatedCommand({_0:?})")]
|
|
167
180
|
NewCoreOriginatedCommand(ProtoCmdAttrs),
|
|
168
|
-
#[display(fmt = "IssueFakeLocalActivityMarker({})"
|
|
181
|
+
#[display(fmt = "IssueFakeLocalActivityMarker({_0})")]
|
|
169
182
|
IssueFakeLocalActivityMarker(u32),
|
|
170
183
|
#[display(fmt = "TriggerWFTaskStarted")]
|
|
171
184
|
TriggerWFTaskStarted {
|
|
172
185
|
task_started_event_id: i64,
|
|
173
186
|
time: SystemTime,
|
|
174
187
|
},
|
|
175
|
-
#[display(fmt = "UpdateRunIdOnWorkflowReset({})"
|
|
188
|
+
#[display(fmt = "UpdateRunIdOnWorkflowReset({run_id})")]
|
|
176
189
|
UpdateRunIdOnWorkflowReset { run_id: String },
|
|
177
190
|
|
|
178
191
|
/// Queue a local activity to be processed by the worker
|
|
179
192
|
#[display(fmt = "QueueLocalActivity")]
|
|
180
193
|
QueueLocalActivity(ValidScheduleLA),
|
|
181
194
|
/// Request cancellation of an executing local activity
|
|
182
|
-
#[display(fmt = "RequestCancelLocalActivity({})"
|
|
195
|
+
#[display(fmt = "RequestCancelLocalActivity({_0})")]
|
|
183
196
|
RequestCancelLocalActivity(u32),
|
|
184
197
|
/// Indicates we are abandoning the indicated LA, so we can remove it from "outstanding" LAs
|
|
185
198
|
/// and we will not try to WFT heartbeat because of it.
|
|
186
|
-
#[display(fmt = "AbandonLocalActivity({:?})"
|
|
199
|
+
#[display(fmt = "AbandonLocalActivity({_0:?})")]
|
|
187
200
|
AbandonLocalActivity(u32),
|
|
188
201
|
|
|
189
202
|
/// Set the workflow time to the provided time
|
|
190
|
-
#[display(fmt = "UpdateWFTime({:?})"
|
|
203
|
+
#[display(fmt = "UpdateWFTime({_0:?})")]
|
|
191
204
|
UpdateWFTime(Option<SystemTime>),
|
|
192
205
|
}
|
|
193
206
|
|
|
@@ -196,30 +209,27 @@ where
|
|
|
196
209
|
T: Into<workflow_activation_job::Variant>,
|
|
197
210
|
{
|
|
198
211
|
fn from(v: T) -> Self {
|
|
199
|
-
Self::PushWFJob(v.into())
|
|
212
|
+
Self::PushWFJob(v.into().into())
|
|
200
213
|
}
|
|
201
214
|
}
|
|
202
215
|
|
|
203
216
|
impl WorkflowMachines {
|
|
204
|
-
pub(crate) fn new(
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
metrics: MetricsContext,
|
|
212
|
-
) -> Self {
|
|
213
|
-
let replaying = history.previous_started_event_id > 0;
|
|
217
|
+
pub(crate) fn new(basics: RunBasics, driven_wf: DrivenWorkflow) -> Self {
|
|
218
|
+
let replaying = basics.history.previous_wft_started_id > 0;
|
|
219
|
+
let mut observed_internal_flags = InternalFlags::new(basics.capabilities);
|
|
220
|
+
// Peek ahead to determine used patches in the first WFT.
|
|
221
|
+
if let Some(attrs) = basics.history.peek_next_wft_completed(0) {
|
|
222
|
+
observed_internal_flags.add_from_complete(attrs);
|
|
223
|
+
};
|
|
214
224
|
Self {
|
|
215
|
-
last_history_from_server: history,
|
|
216
|
-
namespace,
|
|
217
|
-
workflow_id,
|
|
218
|
-
workflow_type,
|
|
219
|
-
run_id,
|
|
225
|
+
last_history_from_server: basics.history,
|
|
226
|
+
namespace: basics.namespace,
|
|
227
|
+
workflow_id: basics.workflow_id,
|
|
228
|
+
workflow_type: basics.workflow_type,
|
|
229
|
+
run_id: basics.run_id,
|
|
220
230
|
drive_me: driven_wf,
|
|
221
231
|
replaying,
|
|
222
|
-
metrics,
|
|
232
|
+
metrics: basics.metrics,
|
|
223
233
|
// In an ideal world one could say ..Default::default() here and it'd still work.
|
|
224
234
|
current_started_event_id: 0,
|
|
225
235
|
next_started_event_id: 0,
|
|
@@ -228,6 +238,7 @@ impl WorkflowMachines {
|
|
|
228
238
|
workflow_end_time: None,
|
|
229
239
|
wft_start_time: None,
|
|
230
240
|
current_wf_time: None,
|
|
241
|
+
observed_internal_flags: Rc::new(RefCell::new(observed_internal_flags)),
|
|
231
242
|
all_machines: Default::default(),
|
|
232
243
|
machine_is_core_created: Default::default(),
|
|
233
244
|
machines_by_event_id: Default::default(),
|
|
@@ -253,10 +264,10 @@ impl WorkflowMachines {
|
|
|
253
264
|
.and_then(|(st, et)| et.duration_since(st).ok())
|
|
254
265
|
}
|
|
255
266
|
|
|
256
|
-
pub(crate)
|
|
267
|
+
pub(crate) fn new_history_from_server(&mut self, update: HistoryUpdate) -> Result<()> {
|
|
257
268
|
self.last_history_from_server = update;
|
|
258
|
-
self.replaying = self.last_history_from_server.
|
|
259
|
-
self.apply_next_wft_from_history()
|
|
269
|
+
self.replaying = self.last_history_from_server.previous_wft_started_id > 0;
|
|
270
|
+
self.apply_next_wft_from_history()?;
|
|
260
271
|
Ok(())
|
|
261
272
|
}
|
|
262
273
|
|
|
@@ -288,9 +299,8 @@ impl WorkflowMachines {
|
|
|
288
299
|
self.process_machine_responses(mk, resps)?;
|
|
289
300
|
} else {
|
|
290
301
|
return Err(WFMachinesError::Nondeterminism(format!(
|
|
291
|
-
"Command matching activity with seq num {} existed but was not a \
|
|
292
|
-
local activity!"
|
|
293
|
-
seq
|
|
302
|
+
"Command matching activity with seq num {seq} existed but was not a \
|
|
303
|
+
local activity!"
|
|
294
304
|
)));
|
|
295
305
|
}
|
|
296
306
|
self.local_activity_data.done_executing(seq);
|
|
@@ -315,6 +325,237 @@ impl WorkflowMachines {
|
|
|
315
325
|
self.drive_me.get_started_info()
|
|
316
326
|
}
|
|
317
327
|
|
|
328
|
+
/// Fetches commands which are ready for processing from the state machines, generally to be
|
|
329
|
+
/// sent off to the server. They are not removed from the internal queue, that happens when
|
|
330
|
+
/// corresponding history events from the server are being handled.
|
|
331
|
+
pub(crate) fn get_commands(&self) -> Vec<ProtoCommand> {
|
|
332
|
+
self.commands
|
|
333
|
+
.iter()
|
|
334
|
+
.filter_map(|c| {
|
|
335
|
+
if !self.machine(c.machine).is_final_state() {
|
|
336
|
+
match &c.command {
|
|
337
|
+
MachineAssociatedCommand::Real(cmd) => Some((**cmd).clone()),
|
|
338
|
+
MachineAssociatedCommand::FakeLocalActivityMarker(_) => None,
|
|
339
|
+
}
|
|
340
|
+
} else {
|
|
341
|
+
None
|
|
342
|
+
}
|
|
343
|
+
})
|
|
344
|
+
.collect()
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/// Returns the next activation that needs to be performed by the lang sdk. Things like unblock
|
|
348
|
+
/// timer, etc. This does *not* cause any advancement of the state machines, it merely drains
|
|
349
|
+
/// from the outgoing queue of activation jobs.
|
|
350
|
+
///
|
|
351
|
+
/// The job list may be empty, in which case it is expected the caller handles what to do in a
|
|
352
|
+
/// "no work" situation. Possibly, it may know about some work the machines don't, like queries.
|
|
353
|
+
pub(crate) fn get_wf_activation(&mut self) -> WorkflowActivation {
|
|
354
|
+
let jobs = self.drive_me.drain_jobs();
|
|
355
|
+
WorkflowActivation {
|
|
356
|
+
timestamp: self.current_wf_time.map(Into::into),
|
|
357
|
+
is_replaying: self.replaying,
|
|
358
|
+
run_id: self.run_id.clone(),
|
|
359
|
+
history_length: self.last_processed_event as u32,
|
|
360
|
+
jobs,
|
|
361
|
+
available_internal_flags: (*self.observed_internal_flags)
|
|
362
|
+
.borrow()
|
|
363
|
+
.all_lang()
|
|
364
|
+
.iter()
|
|
365
|
+
.copied()
|
|
366
|
+
.collect(),
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
pub(crate) fn has_pending_jobs(&self) -> bool {
|
|
371
|
+
!self.drive_me.peek_pending_jobs().is_empty()
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
pub(crate) fn has_pending_la_resolutions(&self) -> bool {
|
|
375
|
+
self.drive_me
|
|
376
|
+
.peek_pending_jobs()
|
|
377
|
+
.iter()
|
|
378
|
+
.any(|v| v.is_la_resolution)
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
pub(crate) fn get_metadata_for_wft_complete(&self) -> WorkflowTaskCompletedMetadata {
|
|
382
|
+
(*self.observed_internal_flags)
|
|
383
|
+
.borrow_mut()
|
|
384
|
+
.gather_for_wft_complete()
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
pub(crate) fn add_lang_used_flags(&self, flags: Vec<u32>) {
|
|
388
|
+
(*self.observed_internal_flags)
|
|
389
|
+
.borrow_mut()
|
|
390
|
+
.add_lang_used(flags);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/// Iterate the state machines, which consists of grabbing any pending outgoing commands from
|
|
394
|
+
/// the workflow code, handling them, and preparing them to be sent off to the server.
|
|
395
|
+
pub(crate) fn iterate_machines(&mut self) -> Result<()> {
|
|
396
|
+
let results = self.drive_me.fetch_workflow_iteration_output();
|
|
397
|
+
self.handle_driven_results(results)?;
|
|
398
|
+
self.prepare_commands()?;
|
|
399
|
+
if self.workflow_is_finished() {
|
|
400
|
+
if let Some(rt) = self.total_runtime() {
|
|
401
|
+
self.metrics.wf_e2e_latency(rt);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
Ok(())
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/// Returns true if machines are ready to apply the next WFT sequence, false if events will need
|
|
408
|
+
/// to be fetched in order to create a complete update with the entire next WFT sequence.
|
|
409
|
+
pub(crate) fn ready_to_apply_next_wft(&self) -> bool {
|
|
410
|
+
self.last_history_from_server
|
|
411
|
+
.can_take_next_wft_sequence(self.current_started_event_id)
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/// Apply the next (unapplied) entire workflow task from history to these machines. Will replay
|
|
415
|
+
/// any events that need to be replayed until caught up to the newest WFT.
|
|
416
|
+
pub(crate) fn apply_next_wft_from_history(&mut self) -> Result<usize> {
|
|
417
|
+
// If we have already seen the terminal event for the entire workflow in a previous WFT,
|
|
418
|
+
// then we don't need to do anything here, and in fact we need to avoid re-applying the
|
|
419
|
+
// final WFT.
|
|
420
|
+
if self.have_seen_terminal_event {
|
|
421
|
+
return Ok(0);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Update observed patches with any that were used in the task
|
|
425
|
+
if let Some(next_complete) = self
|
|
426
|
+
.last_history_from_server
|
|
427
|
+
.peek_next_wft_completed(self.last_processed_event)
|
|
428
|
+
{
|
|
429
|
+
(*self.observed_internal_flags)
|
|
430
|
+
.borrow_mut()
|
|
431
|
+
.add_from_complete(next_complete);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
let last_handled_wft_started_id = self.current_started_event_id;
|
|
435
|
+
let (events, has_final_event) = match self
|
|
436
|
+
.last_history_from_server
|
|
437
|
+
.take_next_wft_sequence(last_handled_wft_started_id)
|
|
438
|
+
{
|
|
439
|
+
NextWFT::ReplayOver => (vec![], true),
|
|
440
|
+
NextWFT::WFT(mut evts, has_final_event) => {
|
|
441
|
+
// Do not re-process events we have already processed
|
|
442
|
+
evts.retain(|e| e.event_id > self.last_processed_event);
|
|
443
|
+
(evts, has_final_event)
|
|
444
|
+
}
|
|
445
|
+
NextWFT::NeedFetch => {
|
|
446
|
+
return Err(WFMachinesError::Fatal(
|
|
447
|
+
"Need to fetch history events to continue applying workflow task, but this \
|
|
448
|
+
should be prevented ahead of time! This is a Core SDK bug."
|
|
449
|
+
.to_string(),
|
|
450
|
+
));
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
let num_events_to_process = events.len();
|
|
454
|
+
|
|
455
|
+
// We're caught up on reply if there are no new events to process
|
|
456
|
+
if events.is_empty() {
|
|
457
|
+
self.replaying = false;
|
|
458
|
+
}
|
|
459
|
+
let replay_start = Instant::now();
|
|
460
|
+
|
|
461
|
+
if let Some(last_event) = events.last() {
|
|
462
|
+
if last_event.event_type == EventType::WorkflowTaskStarted as i32 {
|
|
463
|
+
self.next_started_event_id = last_event.event_id;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
let mut saw_completed = false;
|
|
468
|
+
let mut history = events.into_iter().peekable();
|
|
469
|
+
while let Some(event) = history.next() {
|
|
470
|
+
if event.event_id != self.last_processed_event + 1 {
|
|
471
|
+
return Err(WFMachinesError::Fatal(format!(
|
|
472
|
+
"History is out of order. Last processed event: {}, event id: {}",
|
|
473
|
+
self.last_processed_event, event.event_id
|
|
474
|
+
)));
|
|
475
|
+
}
|
|
476
|
+
let next_event = history.peek();
|
|
477
|
+
let eid = event.event_id;
|
|
478
|
+
|
|
479
|
+
// This definition of replaying here is that we are no longer replaying as soon as we
|
|
480
|
+
// see new events that have never been seen or produced by the SDK.
|
|
481
|
+
//
|
|
482
|
+
// Specifically, replay ends once we have seen the last command-event which was produced
|
|
483
|
+
// as a result of the last completed WFT. Thus, replay would be false for things like
|
|
484
|
+
// signals which were received and after the last completion, and thus generated the
|
|
485
|
+
// current WFT being handled.
|
|
486
|
+
if self.replaying && has_final_event && saw_completed && !event.is_command_event() {
|
|
487
|
+
// Replay is finished
|
|
488
|
+
self.replaying = false;
|
|
489
|
+
}
|
|
490
|
+
if event.event_type() == EventType::WorkflowTaskCompleted {
|
|
491
|
+
saw_completed = true;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
self.handle_event(
|
|
495
|
+
HistEventData {
|
|
496
|
+
event,
|
|
497
|
+
replaying: self.replaying,
|
|
498
|
+
current_task_is_last_in_history: has_final_event,
|
|
499
|
+
},
|
|
500
|
+
next_event.is_some() || !has_final_event,
|
|
501
|
+
)?;
|
|
502
|
+
self.last_processed_event = eid;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Scan through to the next WFT, searching for any patch / la markers, so that we can
|
|
506
|
+
// pre-resolve them.
|
|
507
|
+
let mut wake_las = vec![];
|
|
508
|
+
for e in self
|
|
509
|
+
.last_history_from_server
|
|
510
|
+
.peek_next_wft_sequence(last_handled_wft_started_id)
|
|
511
|
+
{
|
|
512
|
+
if let Some((patch_id, _)) = e.get_patch_marker_details() {
|
|
513
|
+
self.encountered_change_markers.insert(
|
|
514
|
+
patch_id.clone(),
|
|
515
|
+
ChangeInfo {
|
|
516
|
+
created_command: false,
|
|
517
|
+
},
|
|
518
|
+
);
|
|
519
|
+
// Found a patch marker
|
|
520
|
+
self.drive_me.send_job(
|
|
521
|
+
workflow_activation_job::Variant::NotifyHasPatch(NotifyHasPatch { patch_id })
|
|
522
|
+
.into(),
|
|
523
|
+
);
|
|
524
|
+
} else if e.is_local_activity_marker() {
|
|
525
|
+
if let Some(la_dat) = e.clone().into_local_activity_marker_details() {
|
|
526
|
+
if let Ok(mk) =
|
|
527
|
+
self.get_machine_key(CommandID::LocalActivity(la_dat.marker_dat.seq))
|
|
528
|
+
{
|
|
529
|
+
wake_las.push((mk, la_dat));
|
|
530
|
+
} else {
|
|
531
|
+
self.local_activity_data.insert_peeked_marker(la_dat);
|
|
532
|
+
}
|
|
533
|
+
} else {
|
|
534
|
+
return Err(WFMachinesError::Fatal(format!(
|
|
535
|
+
"Local activity marker was unparsable: {e:?}"
|
|
536
|
+
)));
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
for (mk, la_dat) in wake_las {
|
|
541
|
+
let mach = self.machine_mut(mk);
|
|
542
|
+
if let Machines::LocalActivityMachine(ref mut lam) = *mach {
|
|
543
|
+
if lam.will_accept_resolve_marker() {
|
|
544
|
+
let resps = lam.try_resolve_with_dat(la_dat.into())?;
|
|
545
|
+
self.process_machine_responses(mk, resps)?;
|
|
546
|
+
} else {
|
|
547
|
+
self.local_activity_data.insert_peeked_marker(la_dat);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
if !self.replaying {
|
|
553
|
+
self.metrics.wf_task_replay_latency(replay_start.elapsed());
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
Ok(num_events_to_process)
|
|
557
|
+
}
|
|
558
|
+
|
|
318
559
|
/// Handle a single event from the workflow history. `has_next_event` should be false if `event`
|
|
319
560
|
/// is the last event in the history.
|
|
320
561
|
///
|
|
@@ -323,14 +564,9 @@ impl WorkflowMachines {
|
|
|
323
564
|
/// event is applied to the machine, which may also return a nondeterminism error if the machine
|
|
324
565
|
/// does not match the expected type. A fatal error may be returned if the machine is in an
|
|
325
566
|
/// invalid state.
|
|
326
|
-
#[instrument(
|
|
327
|
-
fn handle_event(&mut self,
|
|
328
|
-
|
|
329
|
-
return Err(WFMachinesError::Fatal(format!(
|
|
330
|
-
"Event type is unspecified! This history is invalid. Event detail: {:?}",
|
|
331
|
-
event
|
|
332
|
-
)));
|
|
333
|
-
}
|
|
567
|
+
#[instrument(skip(self, event_dat), fields(event=%event_dat))]
|
|
568
|
+
fn handle_event(&mut self, event_dat: HistEventData, has_next_event: bool) -> Result<()> {
|
|
569
|
+
let event = &event_dat.event;
|
|
334
570
|
if event.is_final_wf_execution_event() {
|
|
335
571
|
self.have_seen_terminal_event = true;
|
|
336
572
|
}
|
|
@@ -348,69 +584,45 @@ impl WorkflowMachines {
|
|
|
348
584
|
Ok(())
|
|
349
585
|
};
|
|
350
586
|
}
|
|
587
|
+
if event.event_type() == EventType::Unspecified || event.attributes.is_none() {
|
|
588
|
+
return if !event.worker_may_ignore {
|
|
589
|
+
Err(WFMachinesError::Fatal(format!(
|
|
590
|
+
"Event type is unspecified! This history is invalid. Event detail: {event:?}"
|
|
591
|
+
)))
|
|
592
|
+
} else {
|
|
593
|
+
debug!("Event is ignorable");
|
|
594
|
+
Ok(())
|
|
595
|
+
};
|
|
596
|
+
}
|
|
351
597
|
|
|
352
598
|
if event.is_command_event() {
|
|
353
|
-
self.handle_command_event(
|
|
599
|
+
self.handle_command_event(event_dat)?;
|
|
354
600
|
return Ok(());
|
|
355
601
|
}
|
|
356
|
-
if self.replaying
|
|
357
|
-
&& self.current_started_event_id
|
|
358
|
-
>= self.last_history_from_server.previous_started_event_id
|
|
359
|
-
&& event.event_type() != EventType::WorkflowTaskCompleted
|
|
360
|
-
{
|
|
361
|
-
// Replay is finished
|
|
362
|
-
self.replaying = false;
|
|
363
|
-
}
|
|
364
602
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
self.machines_by_event_id.insert(initial_cmd_id, sm);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
None => {
|
|
379
|
-
return Err(WFMachinesError::Nondeterminism(format!(
|
|
380
|
-
"During event handling, this event had an initial command ID but we \
|
|
381
|
-
could not find a matching command for it: {:?}",
|
|
382
|
-
event
|
|
383
|
-
)));
|
|
603
|
+
if let Some(initial_cmd_id) = event.get_initial_command_event_id() {
|
|
604
|
+
// We remove the machine while we it handles events, then return it, to avoid
|
|
605
|
+
// borrowing from ourself mutably.
|
|
606
|
+
let maybe_machine = self.machines_by_event_id.remove(&initial_cmd_id);
|
|
607
|
+
match maybe_machine {
|
|
608
|
+
Some(sm) => {
|
|
609
|
+
self.submachine_handle_event(sm, event_dat)?;
|
|
610
|
+
// Restore machine if not in it's final state
|
|
611
|
+
if !self.machine(sm).is_final_state() {
|
|
612
|
+
self.machines_by_event_id.insert(initial_cmd_id, sm);
|
|
384
613
|
}
|
|
385
614
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
/// Called when a workflow task started event has triggered. Ensures we are tracking the ID
|
|
394
|
-
/// of the current started event as well as workflow time properly.
|
|
395
|
-
fn task_started(&mut self, task_started_event_id: i64, time: SystemTime) -> Result<()> {
|
|
396
|
-
self.current_started_event_id = task_started_event_id;
|
|
397
|
-
self.wft_start_time = Some(time);
|
|
398
|
-
self.set_current_time(time);
|
|
399
|
-
|
|
400
|
-
// Notify local activity machines that we started a non-replay WFT, which will allow any
|
|
401
|
-
// which were waiting for a marker to instead decide to execute the LA since it clearly
|
|
402
|
-
// will not be resolved via marker.
|
|
403
|
-
if !self.replaying {
|
|
404
|
-
let mut resps = vec![];
|
|
405
|
-
for (k, mach) in self.all_machines.iter_mut() {
|
|
406
|
-
if let Machines::LocalActivityMachine(lam) = mach {
|
|
407
|
-
resps.push((k, lam.encountered_non_replay_wft()?));
|
|
615
|
+
None => {
|
|
616
|
+
return Err(WFMachinesError::Nondeterminism(format!(
|
|
617
|
+
"During event handling, this event had an initial command ID but we \
|
|
618
|
+
could not find a matching command for it: {event:?}"
|
|
619
|
+
)));
|
|
408
620
|
}
|
|
409
621
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
}
|
|
622
|
+
} else {
|
|
623
|
+
self.handle_non_stateful_event(event_dat)?;
|
|
413
624
|
}
|
|
625
|
+
|
|
414
626
|
Ok(())
|
|
415
627
|
}
|
|
416
628
|
|
|
@@ -423,23 +635,23 @@ impl WorkflowMachines {
|
|
|
423
635
|
/// The handling consists of verifying that the next command in the commands queue is associated
|
|
424
636
|
/// with a state machine, which is then notified about the event and the command is removed from
|
|
425
637
|
/// the commands queue.
|
|
426
|
-
fn handle_command_event(&mut self,
|
|
638
|
+
fn handle_command_event(&mut self, event_dat: HistEventData) -> Result<()> {
|
|
639
|
+
let event = &event_dat.event;
|
|
427
640
|
if event.is_local_activity_marker() {
|
|
428
641
|
let deets = event.extract_local_activity_marker_data().ok_or_else(|| {
|
|
429
|
-
WFMachinesError::Fatal(format!("Local activity marker was unparsable: {:?}"
|
|
642
|
+
WFMachinesError::Fatal(format!("Local activity marker was unparsable: {event:?}"))
|
|
430
643
|
})?;
|
|
431
644
|
let cmdid = CommandID::LocalActivity(deets.seq);
|
|
432
645
|
let mkey = self.get_machine_key(cmdid)?;
|
|
433
646
|
if let Machines::LocalActivityMachine(lam) = self.machine(mkey) {
|
|
434
647
|
if lam.marker_should_get_special_handling()? {
|
|
435
|
-
self.submachine_handle_event(mkey,
|
|
648
|
+
self.submachine_handle_event(mkey, event_dat)?;
|
|
436
649
|
return Ok(());
|
|
437
650
|
}
|
|
438
651
|
} else {
|
|
439
652
|
return Err(WFMachinesError::Fatal(format!(
|
|
440
653
|
"Encountered local activity marker but the associated machine was of the \
|
|
441
|
-
wrong type! {:?}"
|
|
442
|
-
event
|
|
654
|
+
wrong type! {event:?}"
|
|
443
655
|
)));
|
|
444
656
|
}
|
|
445
657
|
}
|
|
@@ -449,7 +661,7 @@ impl WorkflowMachines {
|
|
|
449
661
|
let consumed_cmd = loop {
|
|
450
662
|
if let Some(peek_machine) = self.commands.front() {
|
|
451
663
|
let mach = self.machine(peek_machine.machine);
|
|
452
|
-
match change_marker_handling(
|
|
664
|
+
match change_marker_handling(event, mach)? {
|
|
453
665
|
ChangeMarkerOutcome::SkipEvent => return Ok(()),
|
|
454
666
|
ChangeMarkerOutcome::SkipCommand => {
|
|
455
667
|
self.commands.pop_front();
|
|
@@ -464,8 +676,7 @@ impl WorkflowMachines {
|
|
|
464
676
|
c
|
|
465
677
|
} else {
|
|
466
678
|
return Err(WFMachinesError::Nondeterminism(format!(
|
|
467
|
-
"No command scheduled for event {}"
|
|
468
|
-
event
|
|
679
|
+
"No command scheduled for event {event}"
|
|
469
680
|
)));
|
|
470
681
|
};
|
|
471
682
|
|
|
@@ -475,7 +686,7 @@ impl WorkflowMachines {
|
|
|
475
686
|
|
|
476
687
|
if !canceled_before_sent {
|
|
477
688
|
// Feed the machine the event
|
|
478
|
-
self.submachine_handle_event(command.machine,
|
|
689
|
+
self.submachine_handle_event(command.machine, event_dat)?;
|
|
479
690
|
break command;
|
|
480
691
|
}
|
|
481
692
|
};
|
|
@@ -488,23 +699,19 @@ impl WorkflowMachines {
|
|
|
488
699
|
Ok(())
|
|
489
700
|
}
|
|
490
701
|
|
|
491
|
-
fn handle_non_stateful_event(
|
|
492
|
-
&mut self,
|
|
493
|
-
event: HistoryEvent,
|
|
494
|
-
has_next_event: bool,
|
|
495
|
-
) -> Result<()> {
|
|
702
|
+
fn handle_non_stateful_event(&mut self, event_dat: HistEventData) -> Result<()> {
|
|
496
703
|
trace!(
|
|
497
|
-
event = %event,
|
|
704
|
+
event = %event_dat.event,
|
|
498
705
|
"handling non-stateful event"
|
|
499
706
|
);
|
|
500
|
-
let event_id = event.event_id;
|
|
501
|
-
match EventType::from_i32(event.event_type) {
|
|
707
|
+
let event_id = event_dat.event.event_id;
|
|
708
|
+
match EventType::from_i32(event_dat.event.event_type) {
|
|
502
709
|
Some(EventType::WorkflowExecutionStarted) => {
|
|
503
710
|
if let Some(history_event::Attributes::WorkflowExecutionStartedEventAttributes(
|
|
504
711
|
attrs,
|
|
505
|
-
)) = event.attributes
|
|
712
|
+
)) = event_dat.event.attributes
|
|
506
713
|
{
|
|
507
|
-
if let Some(st) = event.event_time {
|
|
714
|
+
if let Some(st) = event_dat.event.event_time.clone() {
|
|
508
715
|
let as_systime: SystemTime = st.try_into()?;
|
|
509
716
|
self.workflow_start_time = Some(as_systime);
|
|
510
717
|
// Set the workflow time to be the event time of the first event, so that
|
|
@@ -516,27 +723,28 @@ impl WorkflowMachines {
|
|
|
516
723
|
self.drive_me.start(
|
|
517
724
|
self.workflow_id.clone(),
|
|
518
725
|
str_to_randomness_seed(&attrs.original_execution_run_id),
|
|
726
|
+
event_dat.event.event_time.unwrap_or_default(),
|
|
519
727
|
attrs,
|
|
520
728
|
);
|
|
521
729
|
} else {
|
|
522
730
|
return Err(WFMachinesError::Fatal(format!(
|
|
523
|
-
"WorkflowExecutionStarted event did not have appropriate attributes: {}"
|
|
524
|
-
event
|
|
731
|
+
"WorkflowExecutionStarted event did not have appropriate attributes: {event_dat}"
|
|
525
732
|
)));
|
|
526
733
|
}
|
|
527
734
|
}
|
|
528
735
|
Some(EventType::WorkflowTaskScheduled) => {
|
|
529
736
|
let wf_task_sm = WorkflowTaskMachine::new(self.next_started_event_id);
|
|
530
737
|
let key = self.all_machines.insert(wf_task_sm.into());
|
|
531
|
-
self.submachine_handle_event(key,
|
|
738
|
+
self.submachine_handle_event(key, event_dat)?;
|
|
532
739
|
self.machines_by_event_id.insert(event_id, key);
|
|
533
740
|
}
|
|
534
741
|
Some(EventType::WorkflowExecutionSignaled) => {
|
|
535
742
|
if let Some(history_event::Attributes::WorkflowExecutionSignaledEventAttributes(
|
|
536
743
|
attrs,
|
|
537
|
-
)) = event.attributes
|
|
744
|
+
)) = event_dat.event.attributes
|
|
538
745
|
{
|
|
539
|
-
self.drive_me
|
|
746
|
+
self.drive_me
|
|
747
|
+
.send_job(workflow_activation::SignalWorkflow::from(attrs).into());
|
|
540
748
|
} else {
|
|
541
749
|
// err
|
|
542
750
|
}
|
|
@@ -546,63 +754,23 @@ impl WorkflowMachines {
|
|
|
546
754
|
history_event::Attributes::WorkflowExecutionCancelRequestedEventAttributes(
|
|
547
755
|
attrs,
|
|
548
756
|
),
|
|
549
|
-
) = event.attributes
|
|
757
|
+
) = event_dat.event.attributes
|
|
550
758
|
{
|
|
551
|
-
self.drive_me
|
|
759
|
+
self.drive_me
|
|
760
|
+
.send_job(workflow_activation::CancelWorkflow::from(attrs).into());
|
|
552
761
|
} else {
|
|
553
762
|
// err
|
|
554
763
|
}
|
|
555
764
|
}
|
|
556
765
|
_ => {
|
|
557
766
|
return Err(WFMachinesError::Fatal(format!(
|
|
558
|
-
"The event is not a non-stateful event, but we tried to handle it as one: {}"
|
|
559
|
-
event
|
|
767
|
+
"The event is not a non-stateful event, but we tried to handle it as one: {event_dat}"
|
|
560
768
|
)));
|
|
561
769
|
}
|
|
562
770
|
}
|
|
563
771
|
Ok(())
|
|
564
772
|
}
|
|
565
773
|
|
|
566
|
-
/// Fetches commands which are ready for processing from the state machines, generally to be
|
|
567
|
-
/// sent off to the server. They are not removed from the internal queue, that happens when
|
|
568
|
-
/// corresponding history events from the server are being handled.
|
|
569
|
-
pub(crate) fn get_commands(&self) -> Vec<ProtoCommand> {
|
|
570
|
-
self.commands
|
|
571
|
-
.iter()
|
|
572
|
-
.filter_map(|c| {
|
|
573
|
-
if !self.machine(c.machine).is_final_state() {
|
|
574
|
-
match &c.command {
|
|
575
|
-
MachineAssociatedCommand::Real(cmd) => Some((**cmd).clone()),
|
|
576
|
-
MachineAssociatedCommand::FakeLocalActivityMarker(_) => None,
|
|
577
|
-
}
|
|
578
|
-
} else {
|
|
579
|
-
None
|
|
580
|
-
}
|
|
581
|
-
})
|
|
582
|
-
.collect()
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
/// Returns the next activation that needs to be performed by the lang sdk. Things like unblock
|
|
586
|
-
/// timer, etc. This does *not* cause any advancement of the state machines, it merely drains
|
|
587
|
-
/// from the outgoing queue of activation jobs.
|
|
588
|
-
///
|
|
589
|
-
/// The job list may be empty, in which case it is expected the caller handles what to do in a
|
|
590
|
-
/// "no work" situation. Possibly, it may know about some work the machines don't, like queries.
|
|
591
|
-
pub(crate) fn get_wf_activation(&mut self) -> WorkflowActivation {
|
|
592
|
-
let jobs = self.drive_me.drain_jobs();
|
|
593
|
-
WorkflowActivation {
|
|
594
|
-
timestamp: self.current_wf_time.map(Into::into),
|
|
595
|
-
is_replaying: self.replaying,
|
|
596
|
-
run_id: self.run_id.clone(),
|
|
597
|
-
history_length: self.last_processed_event as u32,
|
|
598
|
-
jobs,
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
pub(crate) fn has_pending_jobs(&self) -> bool {
|
|
603
|
-
!self.drive_me.peek_pending_jobs().is_empty()
|
|
604
|
-
}
|
|
605
|
-
|
|
606
774
|
fn set_current_time(&mut self, time: SystemTime) -> SystemTime {
|
|
607
775
|
if self.current_wf_time.map_or(true, |t| t < time) {
|
|
608
776
|
self.current_wf_time = Some(time);
|
|
@@ -611,111 +779,10 @@ impl WorkflowMachines {
|
|
|
611
779
|
.expect("We have just ensured this is populated")
|
|
612
780
|
}
|
|
613
781
|
|
|
614
|
-
/// Iterate the state machines, which consists of grabbing any pending outgoing commands from
|
|
615
|
-
/// the workflow code, handling them, and preparing them to be sent off to the server.
|
|
616
|
-
pub(crate) async fn iterate_machines(&mut self) -> Result<()> {
|
|
617
|
-
let results = self.drive_me.fetch_workflow_iteration_output().await;
|
|
618
|
-
self.handle_driven_results(results)?;
|
|
619
|
-
self.prepare_commands()?;
|
|
620
|
-
if self.workflow_is_finished() {
|
|
621
|
-
if let Some(rt) = self.total_runtime() {
|
|
622
|
-
self.metrics.wf_e2e_latency(rt);
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
Ok(())
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
/// Apply the next (unapplied) entire workflow task from history to these machines. Will replay
|
|
629
|
-
/// any events that need to be replayed until caught up to the newest WFT. May also fetch
|
|
630
|
-
/// history from server if needed.
|
|
631
|
-
pub(crate) async fn apply_next_wft_from_history(&mut self) -> Result<usize> {
|
|
632
|
-
// If we have already seen the terminal event for the entire workflow in a previous WFT,
|
|
633
|
-
// then we don't need to do anything here, and in fact we need to avoid re-applying the
|
|
634
|
-
// final WFT.
|
|
635
|
-
if self.have_seen_terminal_event {
|
|
636
|
-
return Ok(0);
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
let last_handled_wft_started_id = self.current_started_event_id;
|
|
640
|
-
let events = {
|
|
641
|
-
let mut evts = self
|
|
642
|
-
.last_history_from_server
|
|
643
|
-
.take_next_wft_sequence(last_handled_wft_started_id)
|
|
644
|
-
.await
|
|
645
|
-
.map_err(WFMachinesError::HistoryFetchingError)?;
|
|
646
|
-
// Do not re-process events we have already processed
|
|
647
|
-
evts.retain(|e| e.event_id > self.last_processed_event);
|
|
648
|
-
evts
|
|
649
|
-
};
|
|
650
|
-
let num_events_to_process = events.len();
|
|
651
|
-
|
|
652
|
-
// We're caught up on reply if there are no new events to process
|
|
653
|
-
// TODO: Probably this is unneeded if we evict whenever history is from non-sticky queue
|
|
654
|
-
if events.is_empty() {
|
|
655
|
-
self.replaying = false;
|
|
656
|
-
}
|
|
657
|
-
let replay_start = Instant::now();
|
|
658
|
-
|
|
659
|
-
if let Some(last_event) = events.last() {
|
|
660
|
-
if last_event.event_type == EventType::WorkflowTaskStarted as i32 {
|
|
661
|
-
self.next_started_event_id = last_event.event_id;
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
let mut history = events.into_iter().peekable();
|
|
666
|
-
while let Some(event) = history.next() {
|
|
667
|
-
if event.event_id != self.last_processed_event + 1 {
|
|
668
|
-
return Err(WFMachinesError::Fatal(format!(
|
|
669
|
-
"History is out of order. Last processed event: {}, event id: {}",
|
|
670
|
-
self.last_processed_event, event.event_id
|
|
671
|
-
)));
|
|
672
|
-
}
|
|
673
|
-
let next_event = history.peek();
|
|
674
|
-
let eid = event.event_id;
|
|
675
|
-
let etype = event.event_type;
|
|
676
|
-
self.handle_event(event, next_event.is_some())?;
|
|
677
|
-
self.last_processed_event = eid;
|
|
678
|
-
if etype == EventType::WorkflowTaskStarted as i32 && next_event.is_none() {
|
|
679
|
-
break;
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
// Scan through to the next WFT, searching for any patch markers, so that we can
|
|
684
|
-
// pre-resolve them.
|
|
685
|
-
for e in self.last_history_from_server.peek_next_wft_sequence() {
|
|
686
|
-
if let Some((patch_id, _)) = e.get_patch_marker_details() {
|
|
687
|
-
self.encountered_change_markers.insert(
|
|
688
|
-
patch_id.clone(),
|
|
689
|
-
ChangeInfo {
|
|
690
|
-
created_command: false,
|
|
691
|
-
},
|
|
692
|
-
);
|
|
693
|
-
// Found a patch marker
|
|
694
|
-
self.drive_me
|
|
695
|
-
.send_job(workflow_activation_job::Variant::NotifyHasPatch(
|
|
696
|
-
NotifyHasPatch { patch_id },
|
|
697
|
-
));
|
|
698
|
-
} else if e.is_local_activity_marker() {
|
|
699
|
-
self.local_activity_data.process_peekahead_marker(e)?;
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
if !self.replaying {
|
|
704
|
-
self.metrics.wf_task_replay_latency(replay_start.elapsed());
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
Ok(num_events_to_process)
|
|
708
|
-
}
|
|
709
|
-
|
|
710
782
|
/// Wrapper for calling [TemporalStateMachine::handle_event] which appropriately takes action
|
|
711
783
|
/// on the returned machine responses
|
|
712
|
-
fn submachine_handle_event(
|
|
713
|
-
|
|
714
|
-
sm: MachineKey,
|
|
715
|
-
event: HistoryEvent,
|
|
716
|
-
has_next_event: bool,
|
|
717
|
-
) -> Result<()> {
|
|
718
|
-
let machine_responses = self.machine_mut(sm).handle_event(event, has_next_event)?;
|
|
784
|
+
fn submachine_handle_event(&mut self, sm: MachineKey, event: HistEventData) -> Result<()> {
|
|
785
|
+
let machine_responses = self.machine_mut(sm).handle_event(event)?;
|
|
719
786
|
self.process_machine_responses(sm, machine_responses)?;
|
|
720
787
|
Ok(())
|
|
721
788
|
}
|
|
@@ -765,7 +832,7 @@ impl WorkflowMachines {
|
|
|
765
832
|
) -> Result<()> {
|
|
766
833
|
let sm = self.machine(smk);
|
|
767
834
|
if !machine_responses.is_empty() {
|
|
768
|
-
|
|
835
|
+
trace!(responses = %machine_responses.display(), machine_name = %sm.name(),
|
|
769
836
|
"Machine produced responses");
|
|
770
837
|
}
|
|
771
838
|
self.process_machine_resps_impl(smk, machine_responses)
|
|
@@ -791,14 +858,12 @@ impl WorkflowMachines {
|
|
|
791
858
|
self.task_started(task_started_event_id, time)?;
|
|
792
859
|
}
|
|
793
860
|
MachineResponse::UpdateRunIdOnWorkflowReset { run_id: new_run_id } => {
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
},
|
|
801
|
-
));
|
|
861
|
+
self.drive_me.send_job(
|
|
862
|
+
workflow_activation_job::Variant::UpdateRandomSeed(UpdateRandomSeed {
|
|
863
|
+
randomness_seed: str_to_randomness_seed(&new_run_id),
|
|
864
|
+
})
|
|
865
|
+
.into(),
|
|
866
|
+
);
|
|
802
867
|
}
|
|
803
868
|
MachineResponse::IssueNewCommand(c) => {
|
|
804
869
|
self.current_wf_task_commands.push_back(CommandAndMachine {
|
|
@@ -822,8 +887,7 @@ impl WorkflowMachines {
|
|
|
822
887
|
}
|
|
823
888
|
c => {
|
|
824
889
|
return Err(WFMachinesError::Fatal(format!(
|
|
825
|
-
"A machine requested to create a new command of an unsupported type: {:?}"
|
|
826
|
-
c
|
|
890
|
+
"A machine requested to create a new command of an unsupported type: {c:?}"
|
|
827
891
|
)))
|
|
828
892
|
}
|
|
829
893
|
},
|
|
@@ -860,7 +924,7 @@ impl WorkflowMachines {
|
|
|
860
924
|
Duration::from_secs(0),
|
|
861
925
|
removed_act.attempt,
|
|
862
926
|
None,
|
|
863
|
-
|
|
927
|
+
removed_act.original_schedule_time,
|
|
864
928
|
)?;
|
|
865
929
|
self.process_machine_responses(smk, more_responses)?;
|
|
866
930
|
} else {
|
|
@@ -888,6 +952,30 @@ impl WorkflowMachines {
|
|
|
888
952
|
Ok(())
|
|
889
953
|
}
|
|
890
954
|
|
|
955
|
+
/// Called when a workflow task started event has triggered. Ensures we are tracking the ID
|
|
956
|
+
/// of the current started event as well as workflow time properly.
|
|
957
|
+
fn task_started(&mut self, task_started_event_id: i64, time: SystemTime) -> Result<()> {
|
|
958
|
+
self.current_started_event_id = task_started_event_id;
|
|
959
|
+
self.wft_start_time = Some(time);
|
|
960
|
+
self.set_current_time(time);
|
|
961
|
+
|
|
962
|
+
// Notify local activity machines that we started a non-replay WFT, which will allow any
|
|
963
|
+
// which were waiting for a marker to instead decide to execute the LA since it clearly
|
|
964
|
+
// will not be resolved via marker.
|
|
965
|
+
if !self.replaying {
|
|
966
|
+
let mut resps = vec![];
|
|
967
|
+
for (k, mach) in self.all_machines.iter_mut() {
|
|
968
|
+
if let Machines::LocalActivityMachine(lam) = mach {
|
|
969
|
+
resps.push((k, lam.encountered_non_replay_wft()?));
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
for (mkey, resp_set) in resps {
|
|
973
|
+
self.process_machine_responses(mkey, resp_set)?;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
Ok(())
|
|
977
|
+
}
|
|
978
|
+
|
|
891
979
|
/// Handles results of the workflow activation, delegating work to the appropriate state
|
|
892
980
|
/// machine. Returns a list of workflow jobs that should be queued in the pending activation for
|
|
893
981
|
/// the next poll. This list will be populated only if state machine produced lang activations
|
|
@@ -912,7 +1000,10 @@ impl WorkflowMachines {
|
|
|
912
1000
|
}
|
|
913
1001
|
WFCommand::AddActivity(attrs) => {
|
|
914
1002
|
let seq = attrs.seq;
|
|
915
|
-
self.add_cmd_to_wf_task(
|
|
1003
|
+
self.add_cmd_to_wf_task(
|
|
1004
|
+
ActivityMachine::new_scheduled(attrs, self.observed_internal_flags.clone()),
|
|
1005
|
+
CommandID::Activity(seq).into(),
|
|
1006
|
+
);
|
|
916
1007
|
}
|
|
917
1008
|
WFCommand::AddLocalActivity(attrs) => {
|
|
918
1009
|
let seq = attrs.seq;
|
|
@@ -924,8 +1015,7 @@ impl WorkflowMachines {
|
|
|
924
1015
|
)
|
|
925
1016
|
.map_err(|e| {
|
|
926
1017
|
WFMachinesError::Fatal(format!(
|
|
927
|
-
"Invalid schedule local activity request (seq {}): {}"
|
|
928
|
-
seq, e
|
|
1018
|
+
"Invalid schedule local activity request (seq {seq}): {e}"
|
|
929
1019
|
))
|
|
930
1020
|
})?;
|
|
931
1021
|
let (la, mach_resp) = new_local_activity(
|
|
@@ -933,6 +1023,7 @@ impl WorkflowMachines {
|
|
|
933
1023
|
self.replaying,
|
|
934
1024
|
self.local_activity_data.take_preresolution(seq),
|
|
935
1025
|
self.current_wf_time,
|
|
1026
|
+
self.observed_internal_flags.clone(),
|
|
936
1027
|
)?;
|
|
937
1028
|
let machkey = self.all_machines.insert(la.into());
|
|
938
1029
|
self.id_to_machine
|
|
@@ -988,7 +1079,10 @@ impl WorkflowMachines {
|
|
|
988
1079
|
WFCommand::AddChildWorkflow(attrs) => {
|
|
989
1080
|
let seq = attrs.seq;
|
|
990
1081
|
self.add_cmd_to_wf_task(
|
|
991
|
-
|
|
1082
|
+
ChildWorkflowMachine::new_scheduled(
|
|
1083
|
+
attrs,
|
|
1084
|
+
self.observed_internal_flags.clone(),
|
|
1085
|
+
),
|
|
992
1086
|
CommandID::ChildWorkflowStart(seq).into(),
|
|
993
1087
|
);
|
|
994
1088
|
}
|
|
@@ -1037,6 +1131,12 @@ impl WorkflowMachines {
|
|
|
1037
1131
|
// Nothing to do here, queries are handled above the machine level
|
|
1038
1132
|
unimplemented!("Query responses should not make it down into the machines")
|
|
1039
1133
|
}
|
|
1134
|
+
WFCommand::ModifyWorkflowProperties(attrs) => {
|
|
1135
|
+
self.add_cmd_to_wf_task(
|
|
1136
|
+
modify_workflow_properties(attrs),
|
|
1137
|
+
CommandIdKind::NeverResolves,
|
|
1138
|
+
);
|
|
1139
|
+
}
|
|
1040
1140
|
WFCommand::NoCommandsFromLang => (),
|
|
1041
1141
|
}
|
|
1042
1142
|
}
|
|
@@ -1056,7 +1156,7 @@ impl WorkflowMachines {
|
|
|
1056
1156
|
|
|
1057
1157
|
fn get_machine_key(&self, id: CommandID) -> Result<MachineKey> {
|
|
1058
1158
|
Ok(*self.id_to_machine.get(&id).ok_or_else(|| {
|
|
1059
|
-
WFMachinesError::Fatal(format!("Missing associated machine for {:?}"
|
|
1159
|
+
WFMachinesError::Fatal(format!("Missing associated machine for {id:?}"))
|
|
1060
1160
|
})?)
|
|
1061
1161
|
}
|
|
1062
1162
|
|
|
@@ -1143,10 +1243,7 @@ enum ChangeMarkerOutcome {
|
|
|
1143
1243
|
|
|
1144
1244
|
/// Special handling for patch markers, when handling command events as in
|
|
1145
1245
|
/// [WorkflowMachines::handle_command_event]
|
|
1146
|
-
fn change_marker_handling(
|
|
1147
|
-
event: &HistoryEvent,
|
|
1148
|
-
mach: &dyn TemporalStateMachine,
|
|
1149
|
-
) -> Result<ChangeMarkerOutcome> {
|
|
1246
|
+
fn change_marker_handling(event: &HistoryEvent, mach: &Machines) -> Result<ChangeMarkerOutcome> {
|
|
1150
1247
|
if !mach.matches_event(event) {
|
|
1151
1248
|
// Version markers can be skipped in the event they are deprecated
|
|
1152
1249
|
if let Some((patch_name, deprecated)) = event.get_patch_marker_details() {
|
|
@@ -1157,16 +1254,15 @@ fn change_marker_handling(
|
|
|
1157
1254
|
return Ok(ChangeMarkerOutcome::SkipEvent);
|
|
1158
1255
|
}
|
|
1159
1256
|
return Err(WFMachinesError::Nondeterminism(format!(
|
|
1160
|
-
"Non-deprecated patch marker encountered for change {}, \
|
|
1161
|
-
but there is no corresponding change command!"
|
|
1162
|
-
patch_name
|
|
1257
|
+
"Non-deprecated patch marker encountered for change {patch_name}, \
|
|
1258
|
+
but there is no corresponding change command!"
|
|
1163
1259
|
)));
|
|
1164
1260
|
}
|
|
1165
|
-
//
|
|
1261
|
+
// Patch machines themselves may also not *have* matching markers, where non-deprecated
|
|
1166
1262
|
// calls take the old path, and deprecated calls assume history is produced by a new-code
|
|
1167
1263
|
// worker.
|
|
1168
|
-
if mach
|
|
1169
|
-
debug!("Skipping non-matching event against
|
|
1264
|
+
if matches!(mach, Machines::PatchMachine(_)) {
|
|
1265
|
+
debug!("Skipping non-matching event against patch machine");
|
|
1170
1266
|
return Ok(ChangeMarkerOutcome::SkipCommand);
|
|
1171
1267
|
}
|
|
1172
1268
|
}
|