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,43 +1,45 @@
|
|
|
1
|
-
use crate::telemetry::
|
|
1
|
+
use crate::telemetry::default_resource;
|
|
2
2
|
use hyper::{
|
|
3
3
|
header::CONTENT_TYPE,
|
|
4
|
+
server::conn::AddrIncoming,
|
|
4
5
|
service::{make_service_fn, service_fn},
|
|
5
6
|
Body, Method, Request, Response, Server,
|
|
6
7
|
};
|
|
7
|
-
use opentelemetry::{
|
|
8
|
-
metrics::
|
|
9
|
-
|
|
10
|
-
export::metrics::aggregation::TemporalitySelector,
|
|
11
|
-
metrics::{controllers, processors},
|
|
12
|
-
},
|
|
8
|
+
use opentelemetry::sdk::{
|
|
9
|
+
export::metrics::{aggregation::TemporalitySelector, AggregatorSelector},
|
|
10
|
+
metrics::{controllers, processors},
|
|
13
11
|
};
|
|
14
12
|
use opentelemetry_prometheus::{ExporterBuilder, PrometheusExporter};
|
|
15
13
|
use prometheus::{Encoder, TextEncoder};
|
|
16
|
-
use std::{convert::Infallible, net::SocketAddr, sync::Arc};
|
|
14
|
+
use std::{convert::Infallible, net::SocketAddr, sync::Arc, time::Duration};
|
|
17
15
|
|
|
18
16
|
/// Exposes prometheus metrics for scraping
|
|
19
17
|
pub(super) struct PromServer {
|
|
20
|
-
|
|
18
|
+
bound_addr: AddrIncoming,
|
|
21
19
|
pub exporter: Arc<PrometheusExporter>,
|
|
22
20
|
}
|
|
23
21
|
|
|
24
22
|
impl PromServer {
|
|
25
23
|
pub fn new(
|
|
26
24
|
addr: SocketAddr,
|
|
25
|
+
aggregation: impl AggregatorSelector + Send + Sync + 'static,
|
|
27
26
|
temporality: impl TemporalitySelector + Send + Sync + 'static,
|
|
28
|
-
) -> Result<Self,
|
|
27
|
+
) -> Result<Self, anyhow::Error> {
|
|
29
28
|
let controller =
|
|
30
|
-
controllers::basic(processors::factory(
|
|
29
|
+
controllers::basic(processors::factory(aggregation, temporality).with_memory(true))
|
|
30
|
+
// Because Prom is pull-based, make this always refresh
|
|
31
|
+
.with_collect_period(Duration::from_secs(0))
|
|
31
32
|
.with_resource(default_resource())
|
|
32
33
|
.build();
|
|
33
34
|
let exporter = ExporterBuilder::new(controller).try_init()?;
|
|
35
|
+
let bound_addr = AddrIncoming::bind(&addr)?;
|
|
34
36
|
Ok(Self {
|
|
35
37
|
exporter: Arc::new(exporter),
|
|
36
|
-
|
|
38
|
+
bound_addr,
|
|
37
39
|
})
|
|
38
40
|
}
|
|
39
41
|
|
|
40
|
-
pub async fn run(
|
|
42
|
+
pub async fn run(self) -> hyper::Result<()> {
|
|
41
43
|
// Spin up hyper server to serve metrics for scraping. We use hyper since we already depend
|
|
42
44
|
// on it via Tonic.
|
|
43
45
|
let expclone = self.exporter.clone();
|
|
@@ -45,9 +47,13 @@ impl PromServer {
|
|
|
45
47
|
let expclone = expclone.clone();
|
|
46
48
|
async move { Ok::<_, Infallible>(service_fn(move |req| metrics_req(req, expclone.clone()))) }
|
|
47
49
|
});
|
|
48
|
-
let server = Server::
|
|
50
|
+
let server = Server::builder(self.bound_addr).serve(svc);
|
|
49
51
|
server.await
|
|
50
52
|
}
|
|
53
|
+
|
|
54
|
+
pub fn bound_addr(&self) -> SocketAddr {
|
|
55
|
+
self.bound_addr.local_addr()
|
|
56
|
+
}
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
/// Serves prometheus metrics in the expected format for scraping
|
|
@@ -5,12 +5,16 @@ use crate::{
|
|
|
5
5
|
protosext::ValidPollWFTQResponse,
|
|
6
6
|
replay::TestHistoryBuilder,
|
|
7
7
|
sticky_q_name_for_worker,
|
|
8
|
+
telemetry::metrics::MetricsContext,
|
|
8
9
|
worker::{
|
|
9
|
-
client::{
|
|
10
|
+
client::{
|
|
11
|
+
mocks::mock_workflow_client, MockWorkerClient, WorkerClient, WorkflowTaskCompletion,
|
|
12
|
+
},
|
|
10
13
|
new_wft_poller,
|
|
11
14
|
},
|
|
12
15
|
TaskToken, Worker, WorkerConfig, WorkerConfigBuilder,
|
|
13
16
|
};
|
|
17
|
+
use async_trait::async_trait;
|
|
14
18
|
use bimap::BiMap;
|
|
15
19
|
use futures::{future::BoxFuture, stream, stream::BoxStream, FutureExt, Stream, StreamExt};
|
|
16
20
|
use mockall::TimesRange;
|
|
@@ -26,7 +30,7 @@ use std::{
|
|
|
26
30
|
task::{Context, Poll},
|
|
27
31
|
time::Duration,
|
|
28
32
|
};
|
|
29
|
-
use
|
|
33
|
+
use temporal_sdk_core_api::errors::{PollActivityError, PollWfError};
|
|
30
34
|
use temporal_sdk_core_api::Worker as WorkerTrait;
|
|
31
35
|
use temporal_sdk_core_protos::{
|
|
32
36
|
coresdk::{
|
|
@@ -50,13 +54,13 @@ use tokio_stream::wrappers::UnboundedReceiverStream;
|
|
|
50
54
|
use tokio_util::sync::CancellationToken;
|
|
51
55
|
|
|
52
56
|
pub const TEST_Q: &str = "q";
|
|
53
|
-
pub static NO_MORE_WORK_ERROR_MSG: &str = "No more work to do";
|
|
54
57
|
|
|
55
58
|
pub fn test_worker_cfg() -> WorkerConfigBuilder {
|
|
56
59
|
let mut wcb = WorkerConfigBuilder::default();
|
|
57
60
|
wcb.namespace("default")
|
|
58
61
|
.task_queue(TEST_Q)
|
|
59
62
|
.worker_build_id("test_bin_id")
|
|
63
|
+
.ignore_evicts_on_shutdown(true)
|
|
60
64
|
// Serial polling since it makes mocking much easier.
|
|
61
65
|
.max_concurrent_wft_polls(1_usize);
|
|
62
66
|
wcb
|
|
@@ -133,13 +137,19 @@ pub(crate) fn build_fake_worker(
|
|
|
133
137
|
|
|
134
138
|
pub(crate) fn mock_worker(mocks: MocksHolder) -> Worker {
|
|
135
139
|
let sticky_q = sticky_q_name_for_worker("unit-test", &mocks.inputs.config);
|
|
140
|
+
let act_poller = if mocks.inputs.config.no_remote_activities {
|
|
141
|
+
None
|
|
142
|
+
} else {
|
|
143
|
+
mocks.inputs.act_poller
|
|
144
|
+
};
|
|
136
145
|
Worker::new_with_pollers(
|
|
137
146
|
mocks.inputs.config,
|
|
138
147
|
sticky_q,
|
|
139
148
|
mocks.client,
|
|
140
149
|
mocks.inputs.wft_stream,
|
|
141
|
-
|
|
142
|
-
|
|
150
|
+
act_poller,
|
|
151
|
+
MetricsContext::no_op(),
|
|
152
|
+
None,
|
|
143
153
|
CancellationToken::new(),
|
|
144
154
|
)
|
|
145
155
|
}
|
|
@@ -209,7 +219,7 @@ impl MockWorkerInputs {
|
|
|
209
219
|
}
|
|
210
220
|
pub fn new_from_poller(wf_poller: BoxedWFPoller) -> Self {
|
|
211
221
|
Self {
|
|
212
|
-
wft_stream: new_wft_poller(wf_poller,
|
|
222
|
+
wft_stream: new_wft_poller(wf_poller, MetricsContext::no_op()).boxed(),
|
|
213
223
|
act_poller: None,
|
|
214
224
|
config: test_worker_cfg().build().unwrap(),
|
|
215
225
|
}
|
|
@@ -293,7 +303,7 @@ where
|
|
|
293
303
|
}
|
|
294
304
|
.boxed()
|
|
295
305
|
} else {
|
|
296
|
-
async {
|
|
306
|
+
async { None }.boxed()
|
|
297
307
|
}
|
|
298
308
|
});
|
|
299
309
|
Box::new(mock_poller) as BoxedPoller<T>
|
|
@@ -367,10 +377,12 @@ pub(crate) struct MockPollCfg {
|
|
|
367
377
|
pub expect_fail_wft_matcher:
|
|
368
378
|
Box<dyn Fn(&TaskToken, &WorkflowTaskFailedCause, &Option<Failure>) -> bool + Send>,
|
|
369
379
|
pub completion_asserts: Option<Box<dyn Fn(&WorkflowTaskCompletion) + Send>>,
|
|
380
|
+
pub num_expected_completions: Option<TimesRange>,
|
|
370
381
|
/// If being used with the Rust SDK, this is set true. It ensures pollers will not error out
|
|
371
382
|
/// early with no work, since we cannot know the exact number of times polling will happen.
|
|
372
383
|
/// Instead, they will just block forever.
|
|
373
384
|
pub using_rust_sdk: bool,
|
|
385
|
+
pub make_poll_stream_interminable: bool,
|
|
374
386
|
}
|
|
375
387
|
|
|
376
388
|
impl MockPollCfg {
|
|
@@ -387,7 +399,9 @@ impl MockPollCfg {
|
|
|
387
399
|
mock_client: mock_workflow_client(),
|
|
388
400
|
expect_fail_wft_matcher: Box::new(|_, _, _| true),
|
|
389
401
|
completion_asserts: None,
|
|
402
|
+
num_expected_completions: None,
|
|
390
403
|
using_rust_sdk: false,
|
|
404
|
+
make_poll_stream_interminable: false,
|
|
391
405
|
}
|
|
392
406
|
}
|
|
393
407
|
pub fn from_resp_batches(
|
|
@@ -408,7 +422,9 @@ impl MockPollCfg {
|
|
|
408
422
|
mock_client,
|
|
409
423
|
expect_fail_wft_matcher: Box::new(|_, _, _| true),
|
|
410
424
|
completion_asserts: None,
|
|
425
|
+
num_expected_completions: None,
|
|
411
426
|
using_rust_sdk: false,
|
|
427
|
+
make_poll_stream_interminable: false,
|
|
412
428
|
}
|
|
413
429
|
}
|
|
414
430
|
}
|
|
@@ -498,7 +514,7 @@ pub(crate) fn build_mock_pollers(mut cfg: MockPollCfg) -> MocksHolder {
|
|
|
498
514
|
.into_iter()
|
|
499
515
|
.map(|response| {
|
|
500
516
|
let cur_attempt = attempts_at_task_num.entry(response.hashable()).or_insert(1);
|
|
501
|
-
let mut r = hist_to_poll_resp(&hist.hist, hist.wf_id.clone(), response
|
|
517
|
+
let mut r = hist_to_poll_resp(&hist.hist, hist.wf_id.clone(), response);
|
|
502
518
|
r.attempt = *cur_attempt;
|
|
503
519
|
*cur_attempt += 1;
|
|
504
520
|
r
|
|
@@ -576,16 +592,20 @@ pub(crate) fn build_mock_pollers(mut cfg: MockPollCfg) -> MocksHolder {
|
|
|
576
592
|
);
|
|
577
593
|
|
|
578
594
|
let outstanding = outstanding_wf_task_tokens.clone();
|
|
579
|
-
cfg.mock_client
|
|
580
|
-
|
|
581
|
-
.
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
595
|
+
let expect_completes = cfg.mock_client.expect_complete_workflow_task();
|
|
596
|
+
if let Some(range) = cfg.num_expected_completions {
|
|
597
|
+
expect_completes.times(range);
|
|
598
|
+
} else if cfg.completion_asserts.is_some() {
|
|
599
|
+
expect_completes.times(1..);
|
|
600
|
+
}
|
|
601
|
+
expect_completes.returning(move |comp| {
|
|
602
|
+
if let Some(ass) = cfg.completion_asserts.as_ref() {
|
|
603
|
+
// tee hee
|
|
604
|
+
ass(&comp)
|
|
605
|
+
}
|
|
606
|
+
outstanding.release_token(&comp.task_token);
|
|
607
|
+
Ok(RespondWorkflowTaskCompletedResponse::default())
|
|
608
|
+
});
|
|
589
609
|
let outstanding = outstanding_wf_task_tokens.clone();
|
|
590
610
|
cfg.mock_client
|
|
591
611
|
.expect_fail_workflow_task()
|
|
@@ -604,11 +624,15 @@ pub(crate) fn build_mock_pollers(mut cfg: MockPollCfg) -> MocksHolder {
|
|
|
604
624
|
Ok(Default::default())
|
|
605
625
|
});
|
|
606
626
|
|
|
607
|
-
MocksHolder {
|
|
627
|
+
let mut mh = MocksHolder {
|
|
608
628
|
client: Arc::new(cfg.mock_client),
|
|
609
629
|
inputs: mock_worker,
|
|
610
630
|
outstanding_task_map: Some(outstanding_wf_task_tokens),
|
|
631
|
+
};
|
|
632
|
+
if cfg.make_poll_stream_interminable {
|
|
633
|
+
mh.make_wft_stream_interminable();
|
|
611
634
|
}
|
|
635
|
+
mh
|
|
612
636
|
}
|
|
613
637
|
|
|
614
638
|
pub struct QueueResponse<T> {
|
|
@@ -649,7 +673,6 @@ pub fn hist_to_poll_resp(
|
|
|
649
673
|
t: &TestHistoryBuilder,
|
|
650
674
|
wf_id: impl Into<String>,
|
|
651
675
|
response_type: ResponseType,
|
|
652
|
-
task_queue: impl Into<String>,
|
|
653
676
|
) -> QueueResponse<PollWorkflowTaskQueueResponse> {
|
|
654
677
|
let run_id = t.get_orig_run_id();
|
|
655
678
|
let wf = WorkflowExecution {
|
|
@@ -678,7 +701,7 @@ pub fn hist_to_poll_resp(
|
|
|
678
701
|
}
|
|
679
702
|
}
|
|
680
703
|
};
|
|
681
|
-
let mut resp = hist_info.as_poll_wft_response(
|
|
704
|
+
let mut resp = hist_info.as_poll_wft_response();
|
|
682
705
|
resp.workflow_execution = Some(wf);
|
|
683
706
|
QueueResponse { resp, delay_until }
|
|
684
707
|
}
|
|
@@ -828,6 +851,7 @@ pub(crate) fn gen_assert_and_fail(asserter: &dyn Fn(&WorkflowActivation)) -> Ass
|
|
|
828
851
|
message: "Intentional test failure".to_string(),
|
|
829
852
|
..Default::default()
|
|
830
853
|
}),
|
|
854
|
+
..Default::default()
|
|
831
855
|
}
|
|
832
856
|
.into(),
|
|
833
857
|
)
|
|
@@ -873,3 +897,43 @@ macro_rules! prost_dur {
|
|
|
873
897
|
.expect("test duration fits")
|
|
874
898
|
};
|
|
875
899
|
}
|
|
900
|
+
|
|
901
|
+
#[async_trait]
|
|
902
|
+
pub(crate) trait WorkerExt {
|
|
903
|
+
/// Initiate shutdown, drain the pollers, and wait for shutdown to complete.
|
|
904
|
+
async fn drain_pollers_and_shutdown(self);
|
|
905
|
+
/// Initiate shutdown, drain the *activity* poller, and wait for shutdown to complete.
|
|
906
|
+
/// Takes a ref because of that one test that needs it.
|
|
907
|
+
async fn drain_activity_poller_and_shutdown(&self);
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
#[async_trait]
|
|
911
|
+
impl WorkerExt for Worker {
|
|
912
|
+
async fn drain_pollers_and_shutdown(self) {
|
|
913
|
+
self.initiate_shutdown();
|
|
914
|
+
tokio::join!(
|
|
915
|
+
async {
|
|
916
|
+
assert_matches!(
|
|
917
|
+
self.poll_activity_task().await.unwrap_err(),
|
|
918
|
+
PollActivityError::ShutDown
|
|
919
|
+
);
|
|
920
|
+
},
|
|
921
|
+
async {
|
|
922
|
+
assert_matches!(
|
|
923
|
+
self.poll_workflow_activation().await.unwrap_err(),
|
|
924
|
+
PollWfError::ShutDown
|
|
925
|
+
);
|
|
926
|
+
}
|
|
927
|
+
);
|
|
928
|
+
self.finalize_shutdown().await;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
async fn drain_activity_poller_and_shutdown(&self) {
|
|
932
|
+
self.initiate_shutdown();
|
|
933
|
+
assert_matches!(
|
|
934
|
+
self.poll_activity_task().await.unwrap_err(),
|
|
935
|
+
PollActivityError::ShutDown
|
|
936
|
+
);
|
|
937
|
+
self.shutdown().await;
|
|
938
|
+
}
|
|
939
|
+
}
|
|
@@ -26,9 +26,6 @@ use tokio_util::sync::CancellationToken;
|
|
|
26
26
|
/// Used to supply new heartbeat events to the activity heartbeat manager, or to send a shutdown
|
|
27
27
|
/// request.
|
|
28
28
|
pub(crate) struct ActivityHeartbeatManager {
|
|
29
|
-
/// Cancellations that have been received when heartbeating are queued here and can be consumed
|
|
30
|
-
/// by [fetch_cancellations]
|
|
31
|
-
incoming_cancels: Mutex<UnboundedReceiver<PendingActivityCancel>>,
|
|
32
29
|
shutdown_token: CancellationToken,
|
|
33
30
|
/// Used during `shutdown` to await until all inflight requests are sent.
|
|
34
31
|
join_handle: Mutex<Option<JoinHandle<()>>>,
|
|
@@ -74,15 +71,118 @@ pub enum ActivityHeartbeatError {
|
|
|
74
71
|
/// to heartbeat.
|
|
75
72
|
#[error("Unable to parse activity heartbeat timeout.")]
|
|
76
73
|
InvalidHeartbeatTimeout,
|
|
77
|
-
/// Core is shutting down and thus new heartbeats are not accepted
|
|
78
|
-
#[error("New heartbeat requests are not accepted while shutting down")]
|
|
79
|
-
ShuttingDown,
|
|
80
74
|
}
|
|
81
75
|
|
|
82
76
|
/// Manages activity heartbeating for a worker. Allows sending new heartbeats or requesting and
|
|
83
77
|
/// awaiting for the shutdown. When shutdown is requested, signal gets sent to all processors, which
|
|
84
78
|
/// allows them to complete gracefully.
|
|
85
79
|
impl ActivityHeartbeatManager {
|
|
80
|
+
/// Creates a new instance of an activity heartbeat manager and returns a handle to the user,
|
|
81
|
+
/// which allows to send new heartbeats and initiate the shutdown.
|
|
82
|
+
/// Returns the manager and a channel that buffers cancellation notifications to be sent to Lang.
|
|
83
|
+
pub(super) fn new(
|
|
84
|
+
client: Arc<dyn WorkerClient>,
|
|
85
|
+
) -> (Self, UnboundedReceiver<PendingActivityCancel>) {
|
|
86
|
+
let (heartbeat_stream_state, heartbeat_tx_source, shutdown_token) =
|
|
87
|
+
HeartbeatStreamState::new();
|
|
88
|
+
let (cancels_tx, cancels_rx) = unbounded_channel();
|
|
89
|
+
let heartbeat_tx = heartbeat_tx_source.clone();
|
|
90
|
+
|
|
91
|
+
let join_handle = tokio::spawn(
|
|
92
|
+
// The stream of incoming heartbeats uses unfold to carry state across each item in the
|
|
93
|
+
// stream. The closure checks if, for any given activity, we should heartbeat or not
|
|
94
|
+
// depending on its delay and when we last issued a heartbeat for it.
|
|
95
|
+
futures::stream::unfold(heartbeat_stream_state, move |mut hb_states| {
|
|
96
|
+
async move {
|
|
97
|
+
let hb = tokio::select! {
|
|
98
|
+
biased;
|
|
99
|
+
|
|
100
|
+
_ = hb_states.cancellation_token.cancelled() => {
|
|
101
|
+
return None
|
|
102
|
+
}
|
|
103
|
+
hb = hb_states.incoming_hbs.recv() => match hb {
|
|
104
|
+
None => return None,
|
|
105
|
+
Some(hb) => hb,
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
Some((
|
|
110
|
+
match hb {
|
|
111
|
+
HeartbeatAction::SendHeartbeat(hb) => hb_states.record(hb),
|
|
112
|
+
HeartbeatAction::CompleteReport(tt) => hb_states.handle_report_completed(tt),
|
|
113
|
+
HeartbeatAction::CompleteThrottle(tt) => hb_states.handle_throttle_completed(tt),
|
|
114
|
+
HeartbeatAction::Evict{ token, on_complete } => hb_states.evict(token, on_complete),
|
|
115
|
+
},
|
|
116
|
+
hb_states,
|
|
117
|
+
))
|
|
118
|
+
}
|
|
119
|
+
})
|
|
120
|
+
// Filters out `None`s
|
|
121
|
+
.filter_map(|opt| async { opt })
|
|
122
|
+
.for_each_concurrent(None, move |action| {
|
|
123
|
+
let heartbeat_tx = heartbeat_tx_source.clone();
|
|
124
|
+
let sg = client.clone();
|
|
125
|
+
let cancels_tx = cancels_tx.clone();
|
|
126
|
+
async move {
|
|
127
|
+
match action {
|
|
128
|
+
HeartbeatExecutorAction::Sleep(tt, duration, cancellation_token) => {
|
|
129
|
+
tokio::select! {
|
|
130
|
+
_ = cancellation_token.cancelled() => (),
|
|
131
|
+
_ = tokio::time::sleep(duration) => {
|
|
132
|
+
let _ = heartbeat_tx.send(HeartbeatAction::CompleteThrottle(tt));
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
HeartbeatExecutorAction::Report { task_token: tt, details } => {
|
|
137
|
+
match sg
|
|
138
|
+
.record_activity_heartbeat(tt.clone(), details.into_payloads())
|
|
139
|
+
.await
|
|
140
|
+
{
|
|
141
|
+
Ok(RecordActivityTaskHeartbeatResponse { cancel_requested }) => {
|
|
142
|
+
if cancel_requested {
|
|
143
|
+
cancels_tx
|
|
144
|
+
.send(PendingActivityCancel::new(
|
|
145
|
+
tt.clone(),
|
|
146
|
+
ActivityCancelReason::Cancelled,
|
|
147
|
+
))
|
|
148
|
+
.expect(
|
|
149
|
+
"Receive half of heartbeat cancels not blocked",
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Send cancels for any activity that learns its workflow already
|
|
154
|
+
// finished (which is one thing not found implies - other reasons
|
|
155
|
+
// would seem equally valid).
|
|
156
|
+
Err(s) if s.code() == tonic::Code::NotFound => {
|
|
157
|
+
debug!(task_token = %tt,
|
|
158
|
+
"Activity not found when recording heartbeat");
|
|
159
|
+
cancels_tx
|
|
160
|
+
.send(PendingActivityCancel::new(
|
|
161
|
+
tt.clone(),
|
|
162
|
+
ActivityCancelReason::NotFound,
|
|
163
|
+
))
|
|
164
|
+
.expect("Receive half of heartbeat cancels not blocked");
|
|
165
|
+
}
|
|
166
|
+
Err(e) => {
|
|
167
|
+
warn!("Error when recording heartbeat: {:?}", e);
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
let _ = heartbeat_tx.send(HeartbeatAction::CompleteReport(tt));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}),
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
(
|
|
178
|
+
Self {
|
|
179
|
+
join_handle: Mutex::new(Some(join_handle)),
|
|
180
|
+
shutdown_token,
|
|
181
|
+
heartbeat_tx,
|
|
182
|
+
},
|
|
183
|
+
cancels_rx,
|
|
184
|
+
)
|
|
185
|
+
}
|
|
86
186
|
/// Records a new heartbeat, the first call will result in an immediate call to the server,
|
|
87
187
|
/// while rapid successive calls would accumulate for up to `delay` and then latest heartbeat
|
|
88
188
|
/// details will be sent to the server.
|
|
@@ -95,9 +195,6 @@ impl ActivityHeartbeatManager {
|
|
|
95
195
|
hb: ActivityHeartbeat,
|
|
96
196
|
throttle_interval: Duration,
|
|
97
197
|
) -> Result<(), ActivityHeartbeatError> {
|
|
98
|
-
if self.shutdown_token.is_cancelled() {
|
|
99
|
-
return Err(ActivityHeartbeatError::ShuttingDown);
|
|
100
|
-
}
|
|
101
198
|
self.heartbeat_tx
|
|
102
199
|
.send(HeartbeatAction::SendHeartbeat(ValidActivityHeartbeat {
|
|
103
200
|
task_token: TaskToken(hb.task_token),
|
|
@@ -121,13 +218,6 @@ impl ActivityHeartbeatManager {
|
|
|
121
218
|
completed.notified().await;
|
|
122
219
|
}
|
|
123
220
|
|
|
124
|
-
/// Returns a future that resolves any time there is a new activity cancel that must be
|
|
125
|
-
/// dispatched to lang
|
|
126
|
-
pub(super) async fn next_pending_cancel(&self) -> Option<PendingActivityCancel> {
|
|
127
|
-
self.incoming_cancels.lock().await.recv().await
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// TODO: Can own self now!
|
|
131
221
|
/// Initiates shutdown procedure by stopping lifecycle loop and awaiting for all in-flight
|
|
132
222
|
/// heartbeat requests to be flushed to the server.
|
|
133
223
|
pub(super) async fn shutdown(&self) {
|
|
@@ -301,110 +391,6 @@ impl HeartbeatStreamState {
|
|
|
301
391
|
}
|
|
302
392
|
}
|
|
303
393
|
|
|
304
|
-
impl ActivityHeartbeatManager {
|
|
305
|
-
/// Creates a new instance of an activity heartbeat manager and returns a handle to the user,
|
|
306
|
-
/// which allows to send new heartbeats and initiate the shutdown.
|
|
307
|
-
pub fn new(client: Arc<dyn WorkerClient>) -> Self {
|
|
308
|
-
let (heartbeat_stream_state, heartbeat_tx_source, shutdown_token) =
|
|
309
|
-
HeartbeatStreamState::new();
|
|
310
|
-
let (cancels_tx, cancels_rx) = unbounded_channel();
|
|
311
|
-
let heartbeat_tx = heartbeat_tx_source.clone();
|
|
312
|
-
|
|
313
|
-
let join_handle = tokio::spawn(
|
|
314
|
-
// The stream of incoming heartbeats uses unfold to carry state across each item in the
|
|
315
|
-
// stream. The closure checks if, for any given activity, we should heartbeat or not
|
|
316
|
-
// depending on its delay and when we last issued a heartbeat for it.
|
|
317
|
-
futures::stream::unfold(heartbeat_stream_state, move |mut hb_states| {
|
|
318
|
-
async move {
|
|
319
|
-
let hb = tokio::select! {
|
|
320
|
-
biased;
|
|
321
|
-
|
|
322
|
-
_ = hb_states.cancellation_token.cancelled() => {
|
|
323
|
-
return None
|
|
324
|
-
}
|
|
325
|
-
hb = hb_states.incoming_hbs.recv() => match hb {
|
|
326
|
-
None => return None,
|
|
327
|
-
Some(hb) => hb,
|
|
328
|
-
}
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
Some((
|
|
332
|
-
match hb {
|
|
333
|
-
HeartbeatAction::SendHeartbeat(hb) => hb_states.record(hb),
|
|
334
|
-
HeartbeatAction::CompleteReport(tt) => hb_states.handle_report_completed(tt),
|
|
335
|
-
HeartbeatAction::CompleteThrottle(tt) => hb_states.handle_throttle_completed(tt),
|
|
336
|
-
HeartbeatAction::Evict{ token, on_complete } => hb_states.evict(token, on_complete),
|
|
337
|
-
},
|
|
338
|
-
hb_states,
|
|
339
|
-
))
|
|
340
|
-
}
|
|
341
|
-
})
|
|
342
|
-
// Filters out `None`s
|
|
343
|
-
.filter_map(|opt| async { opt })
|
|
344
|
-
.for_each_concurrent(None, move |action| {
|
|
345
|
-
let heartbeat_tx = heartbeat_tx_source.clone();
|
|
346
|
-
let sg = client.clone();
|
|
347
|
-
let cancels_tx = cancels_tx.clone();
|
|
348
|
-
async move {
|
|
349
|
-
match action {
|
|
350
|
-
HeartbeatExecutorAction::Sleep(tt, duration, cancellation_token) => {
|
|
351
|
-
tokio::select! {
|
|
352
|
-
_ = cancellation_token.cancelled() => (),
|
|
353
|
-
_ = tokio::time::sleep(duration) => {
|
|
354
|
-
let _ = heartbeat_tx.send(HeartbeatAction::CompleteThrottle(tt));
|
|
355
|
-
},
|
|
356
|
-
};
|
|
357
|
-
}
|
|
358
|
-
HeartbeatExecutorAction::Report { task_token: tt, details } => {
|
|
359
|
-
match sg
|
|
360
|
-
.record_activity_heartbeat(tt.clone(), details.into_payloads())
|
|
361
|
-
.await
|
|
362
|
-
{
|
|
363
|
-
Ok(RecordActivityTaskHeartbeatResponse { cancel_requested }) => {
|
|
364
|
-
if cancel_requested {
|
|
365
|
-
cancels_tx
|
|
366
|
-
.send(PendingActivityCancel::new(
|
|
367
|
-
tt.clone(),
|
|
368
|
-
ActivityCancelReason::Cancelled,
|
|
369
|
-
))
|
|
370
|
-
.expect(
|
|
371
|
-
"Receive half of heartbeat cancels not blocked",
|
|
372
|
-
);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
// Send cancels for any activity that learns its workflow already
|
|
376
|
-
// finished (which is one thing not found implies - other reasons
|
|
377
|
-
// would seem equally valid).
|
|
378
|
-
Err(s) if s.code() == tonic::Code::NotFound => {
|
|
379
|
-
debug!(task_token = %tt,
|
|
380
|
-
"Activity not found when recording heartbeat");
|
|
381
|
-
cancels_tx
|
|
382
|
-
.send(PendingActivityCancel::new(
|
|
383
|
-
tt.clone(),
|
|
384
|
-
ActivityCancelReason::NotFound,
|
|
385
|
-
))
|
|
386
|
-
.expect("Receive half of heartbeat cancels not blocked");
|
|
387
|
-
}
|
|
388
|
-
Err(e) => {
|
|
389
|
-
warn!("Error when recording heartbeat: {:?}", e);
|
|
390
|
-
}
|
|
391
|
-
};
|
|
392
|
-
let _ = heartbeat_tx.send(HeartbeatAction::CompleteReport(tt));
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
}),
|
|
397
|
-
);
|
|
398
|
-
|
|
399
|
-
Self {
|
|
400
|
-
incoming_cancels: Mutex::new(cancels_rx),
|
|
401
|
-
join_handle: Mutex::new(Some(join_handle)),
|
|
402
|
-
shutdown_token,
|
|
403
|
-
heartbeat_tx,
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
|
|
408
394
|
#[cfg(test)]
|
|
409
395
|
mod test {
|
|
410
396
|
use super::*;
|
|
@@ -425,7 +411,7 @@ mod test {
|
|
|
425
411
|
.expect_record_activity_heartbeat()
|
|
426
412
|
.returning(|_, _| Ok(RecordActivityTaskHeartbeatResponse::default()))
|
|
427
413
|
.times(2);
|
|
428
|
-
let hm = ActivityHeartbeatManager::new(Arc::new(mock_client));
|
|
414
|
+
let (hm, _) = ActivityHeartbeatManager::new(Arc::new(mock_client));
|
|
429
415
|
let fake_task_token = vec![1, 2, 3];
|
|
430
416
|
// Send 2 heartbeat requests for 20ms apart.
|
|
431
417
|
// The first heartbeat should be sent right away, and
|
|
@@ -446,14 +432,13 @@ mod test {
|
|
|
446
432
|
.expect_record_activity_heartbeat()
|
|
447
433
|
.returning(|_, _| Ok(RecordActivityTaskHeartbeatResponse::default()))
|
|
448
434
|
.times(3);
|
|
449
|
-
let hm = ActivityHeartbeatManager::new(Arc::new(mock_client));
|
|
435
|
+
let (hm, _) = ActivityHeartbeatManager::new(Arc::new(mock_client));
|
|
450
436
|
let fake_task_token = vec![1, 2, 3];
|
|
451
437
|
// Heartbeats always get sent if recorded less frequently than the throttle interval
|
|
452
438
|
for i in 0_u8..3 {
|
|
453
439
|
record_heartbeat(&hm, fake_task_token.clone(), i, Duration::from_millis(10));
|
|
454
440
|
sleep(Duration::from_millis(20)).await;
|
|
455
441
|
}
|
|
456
|
-
// sleep again to let heartbeats be flushed
|
|
457
442
|
hm.shutdown().await;
|
|
458
443
|
}
|
|
459
444
|
|
|
@@ -466,7 +451,7 @@ mod test {
|
|
|
466
451
|
.expect_record_activity_heartbeat()
|
|
467
452
|
.returning(|_, _| Ok(RecordActivityTaskHeartbeatResponse::default()))
|
|
468
453
|
.times(1);
|
|
469
|
-
let hm = ActivityHeartbeatManager::new(Arc::new(mock_client));
|
|
454
|
+
let (hm, _) = ActivityHeartbeatManager::new(Arc::new(mock_client));
|
|
470
455
|
let fake_task_token = vec![1, 2, 3];
|
|
471
456
|
// Send a whole bunch of heartbeats very fast. We should still only send one total.
|
|
472
457
|
for i in 0_u8..50 {
|
|
@@ -485,7 +470,7 @@ mod test {
|
|
|
485
470
|
.expect_record_activity_heartbeat()
|
|
486
471
|
.returning(|_, _| Ok(RecordActivityTaskHeartbeatResponse::default()))
|
|
487
472
|
.times(2);
|
|
488
|
-
let hm = ActivityHeartbeatManager::new(Arc::new(mock_client));
|
|
473
|
+
let (hm, _) = ActivityHeartbeatManager::new(Arc::new(mock_client));
|
|
489
474
|
let fake_task_token = vec![1, 2, 3];
|
|
490
475
|
record_heartbeat(&hm, fake_task_token.clone(), 0, Duration::from_millis(100));
|
|
491
476
|
sleep(Duration::from_millis(500)).await;
|
|
@@ -502,7 +487,7 @@ mod test {
|
|
|
502
487
|
.expect_record_activity_heartbeat()
|
|
503
488
|
.returning(|_, _| Ok(RecordActivityTaskHeartbeatResponse::default()))
|
|
504
489
|
.times(2);
|
|
505
|
-
let hm = ActivityHeartbeatManager::new(Arc::new(mock_client));
|
|
490
|
+
let (hm, _) = ActivityHeartbeatManager::new(Arc::new(mock_client));
|
|
506
491
|
let fake_task_token = vec![1, 2, 3];
|
|
507
492
|
record_heartbeat(&hm, fake_task_token.clone(), 0, Duration::from_millis(100));
|
|
508
493
|
// Let it propagate
|
|
@@ -522,42 +507,13 @@ mod test {
|
|
|
522
507
|
.expect_record_activity_heartbeat()
|
|
523
508
|
.returning(|_, _| Ok(RecordActivityTaskHeartbeatResponse::default()))
|
|
524
509
|
.times(1);
|
|
525
|
-
let hm = ActivityHeartbeatManager::new(Arc::new(mock_client));
|
|
510
|
+
let (hm, _) = ActivityHeartbeatManager::new(Arc::new(mock_client));
|
|
526
511
|
let fake_task_token = vec![1, 2, 3];
|
|
527
512
|
record_heartbeat(&hm, fake_task_token.clone(), 0, Duration::from_millis(100));
|
|
528
513
|
hm.evict(fake_task_token.clone().into()).await;
|
|
529
514
|
hm.shutdown().await;
|
|
530
515
|
}
|
|
531
516
|
|
|
532
|
-
/// Recording new heartbeats after shutdown is not allowed, and will result in error.
|
|
533
|
-
#[tokio::test]
|
|
534
|
-
async fn record_after_shutdown() {
|
|
535
|
-
let mut mock_client = mock_workflow_client();
|
|
536
|
-
mock_client
|
|
537
|
-
.expect_record_activity_heartbeat()
|
|
538
|
-
.returning(|_, _| Ok(RecordActivityTaskHeartbeatResponse::default()))
|
|
539
|
-
.times(0);
|
|
540
|
-
let hm = ActivityHeartbeatManager::new(Arc::new(mock_client));
|
|
541
|
-
hm.shutdown().await;
|
|
542
|
-
match hm.record(
|
|
543
|
-
ActivityHeartbeat {
|
|
544
|
-
task_token: vec![1, 2, 3],
|
|
545
|
-
details: vec![Payload {
|
|
546
|
-
// payload doesn't matter in this case, as it shouldn't get sent anyways.
|
|
547
|
-
..Default::default()
|
|
548
|
-
}],
|
|
549
|
-
},
|
|
550
|
-
Duration::from_millis(1000),
|
|
551
|
-
) {
|
|
552
|
-
Ok(_) => {
|
|
553
|
-
unreachable!("heartbeat should not be recorded after the shutdown");
|
|
554
|
-
}
|
|
555
|
-
Err(e) => {
|
|
556
|
-
matches!(e, ActivityHeartbeatError::ShuttingDown);
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
|
|
561
517
|
fn record_heartbeat(
|
|
562
518
|
hm: &ActivityHeartbeatManager,
|
|
563
519
|
task_token: Vec<u8>,
|