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,4 +1,5 @@
|
|
|
1
1
|
mod activity_heartbeat_manager;
|
|
2
|
+
mod activity_task_poller_stream;
|
|
2
3
|
mod local_activities;
|
|
3
4
|
|
|
4
5
|
pub(crate) use local_activities::{
|
|
@@ -7,10 +8,14 @@ pub(crate) use local_activities::{
|
|
|
7
8
|
LocalInFlightActInfo, NewLocalAct,
|
|
8
9
|
};
|
|
9
10
|
|
|
11
|
+
use crate::abstractions::{ClosableMeteredSemaphore, TrackedOwnedMeteredSemPermit};
|
|
12
|
+
use crate::worker::activities::activity_task_poller_stream::new_activity_task_poller;
|
|
10
13
|
use crate::{
|
|
11
|
-
abstractions::{MeteredSemaphore, OwnedMeteredSemPermit},
|
|
14
|
+
abstractions::{MeteredSemaphore, OwnedMeteredSemPermit, UsedMeteredSemPermit},
|
|
12
15
|
pollers::BoxedActPoller,
|
|
13
|
-
telemetry::metrics::{
|
|
16
|
+
telemetry::metrics::{
|
|
17
|
+
activity_type, activity_worker_type, eager, workflow_type, MetricsContext,
|
|
18
|
+
},
|
|
14
19
|
worker::{
|
|
15
20
|
activities::activity_heartbeat_manager::ActivityHeartbeatError, client::WorkerClient,
|
|
16
21
|
},
|
|
@@ -18,14 +23,11 @@ use crate::{
|
|
|
18
23
|
};
|
|
19
24
|
use activity_heartbeat_manager::ActivityHeartbeatManager;
|
|
20
25
|
use dashmap::DashMap;
|
|
21
|
-
use
|
|
22
|
-
|
|
23
|
-
middleware::NoOpMiddleware,
|
|
24
|
-
state::{InMemoryState, NotKeyed},
|
|
25
|
-
Quota, RateLimiter,
|
|
26
|
-
};
|
|
26
|
+
use futures::{stream, stream::BoxStream, stream::PollNext, Stream, StreamExt};
|
|
27
|
+
use governor::{Quota, RateLimiter};
|
|
27
28
|
use std::{
|
|
28
29
|
convert::TryInto,
|
|
30
|
+
future,
|
|
29
31
|
sync::Arc,
|
|
30
32
|
time::{Duration, Instant},
|
|
31
33
|
};
|
|
@@ -40,7 +42,11 @@ use temporal_sdk_core_protos::{
|
|
|
40
42
|
workflowservice::v1::PollActivityTaskQueueResponse,
|
|
41
43
|
},
|
|
42
44
|
};
|
|
43
|
-
use tokio::sync::
|
|
45
|
+
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
|
|
46
|
+
use tokio::sync::{Mutex, Notify};
|
|
47
|
+
use tokio_stream::wrappers::UnboundedReceiverStream;
|
|
48
|
+
use tokio_util::sync::CancellationToken;
|
|
49
|
+
use tracing::Span;
|
|
44
50
|
|
|
45
51
|
#[derive(Debug, derive_more::Constructor)]
|
|
46
52
|
struct PendingActivityCancel {
|
|
@@ -48,11 +54,15 @@ struct PendingActivityCancel {
|
|
|
48
54
|
reason: ActivityCancelReason,
|
|
49
55
|
}
|
|
50
56
|
|
|
51
|
-
/// Contains
|
|
57
|
+
/// Contains details that core wants to store while an activity is running.
|
|
52
58
|
#[derive(Debug)]
|
|
53
59
|
struct InFlightActInfo {
|
|
54
60
|
pub activity_type: String,
|
|
55
61
|
pub workflow_type: String,
|
|
62
|
+
/// Only kept for logging reasons
|
|
63
|
+
pub workflow_id: String,
|
|
64
|
+
/// Only kept for logging reasons
|
|
65
|
+
pub workflow_run_id: String,
|
|
56
66
|
start_time: Instant,
|
|
57
67
|
}
|
|
58
68
|
|
|
@@ -68,22 +78,20 @@ struct RemoteInFlightActInfo {
|
|
|
68
78
|
/// discard the reply.
|
|
69
79
|
pub known_not_found: bool,
|
|
70
80
|
/// The permit from the max concurrent semaphore
|
|
71
|
-
_permit:
|
|
81
|
+
_permit: UsedMeteredSemPermit,
|
|
72
82
|
}
|
|
73
83
|
impl RemoteInFlightActInfo {
|
|
74
|
-
fn new(
|
|
75
|
-
|
|
76
|
-
workflow_type: String,
|
|
77
|
-
heartbeat_timeout: Option<prost_types::Duration>,
|
|
78
|
-
permit: OwnedMeteredSemPermit,
|
|
79
|
-
) -> Self {
|
|
84
|
+
fn new(poll_resp: &PollActivityTaskQueueResponse, permit: UsedMeteredSemPermit) -> Self {
|
|
85
|
+
let wec = poll_resp.workflow_execution.clone().unwrap_or_default();
|
|
80
86
|
Self {
|
|
81
87
|
base: InFlightActInfo {
|
|
82
|
-
activity_type,
|
|
83
|
-
workflow_type,
|
|
88
|
+
activity_type: poll_resp.activity_type.clone().unwrap_or_default().name,
|
|
89
|
+
workflow_type: poll_resp.workflow_type.clone().unwrap_or_default().name,
|
|
90
|
+
workflow_id: wec.workflow_id,
|
|
91
|
+
workflow_run_id: wec.run_id,
|
|
84
92
|
start_time: Instant::now(),
|
|
85
93
|
},
|
|
86
|
-
heartbeat_timeout,
|
|
94
|
+
heartbeat_timeout: poll_resp.heartbeat_timeout.clone(),
|
|
87
95
|
issued_cancel_to_lang: false,
|
|
88
96
|
known_not_found: false,
|
|
89
97
|
_permit: permit,
|
|
@@ -91,43 +99,38 @@ impl RemoteInFlightActInfo {
|
|
|
91
99
|
}
|
|
92
100
|
}
|
|
93
101
|
|
|
94
|
-
struct NonPollActBuffer {
|
|
95
|
-
tx: async_channel::Sender<PermittedTqResp>,
|
|
96
|
-
rx: async_channel::Receiver<PermittedTqResp>,
|
|
97
|
-
}
|
|
98
|
-
impl NonPollActBuffer {
|
|
99
|
-
pub fn new() -> Self {
|
|
100
|
-
let (tx, rx) = async_channel::unbounded();
|
|
101
|
-
Self { tx, rx }
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
pub async fn next(&self) -> PermittedTqResp {
|
|
105
|
-
self.rx.recv().await.expect("Send half cannot be dropped")
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
102
|
pub(crate) struct WorkerActivityTasks {
|
|
103
|
+
/// Token used to signal the server task poller that shutdown is beginning
|
|
104
|
+
poller_shutdown_token: CancellationToken,
|
|
110
105
|
/// Centralizes management of heartbeat issuing / throttling
|
|
111
106
|
heartbeat_manager: ActivityHeartbeatManager,
|
|
107
|
+
/// Combined stream for any ActivityTask producing source (polls, eager activities, cancellations)
|
|
108
|
+
activity_task_stream: Mutex<BoxStream<'static, Result<ActivityTask, PollActivityError>>>,
|
|
112
109
|
/// Activities that have been issued to lang but not yet completed
|
|
113
|
-
outstanding_activity_tasks: DashMap<TaskToken, RemoteInFlightActInfo
|
|
114
|
-
///
|
|
115
|
-
///
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
/// workflow task completion.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
activities_semaphore: Arc<MeteredSemaphore>,
|
|
122
|
-
/// Enables per-worker rate-limiting of activity tasks
|
|
123
|
-
ratelimiter: Option<RateLimiter<NotKeyed, InMemoryState, DefaultClock, NoOpMiddleware>>,
|
|
124
|
-
/// Wakes every time an activity is removed from the outstanding map
|
|
125
|
-
complete_notify: Notify,
|
|
110
|
+
outstanding_activity_tasks: Arc<DashMap<TaskToken, RemoteInFlightActInfo>>,
|
|
111
|
+
/// Ensures we don't exceed this worker's maximum concurrent activity limit for activities.
|
|
112
|
+
/// This semaphore is used to limit eager activities but shares the same underlying [MeteredSemaphore] that is used
|
|
113
|
+
/// to limit the concurrency for non-eager activities.
|
|
114
|
+
eager_activities_semaphore: Arc<ClosableMeteredSemaphore>,
|
|
115
|
+
/// Holds activity tasks we have received in direct response to workflow task completion (a.k.a eager activities).
|
|
116
|
+
/// Tasks received in this stream hold a "tracked" permit that is issued by the `eager_activities_semaphore`.
|
|
117
|
+
eager_activities_tx: UnboundedSender<TrackedPermittedTqResp>,
|
|
126
118
|
|
|
127
119
|
metrics: MetricsContext,
|
|
128
120
|
|
|
129
121
|
max_heartbeat_throttle_interval: Duration,
|
|
130
122
|
default_heartbeat_throttle_interval: Duration,
|
|
123
|
+
|
|
124
|
+
/// Wakes every time an activity is removed from the outstanding map
|
|
125
|
+
complete_notify: Arc<Notify>,
|
|
126
|
+
/// Token to notify when poll returned a shutdown error
|
|
127
|
+
poll_returned_shutdown_token: CancellationToken,
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
#[derive(derive_more::From)]
|
|
131
|
+
enum ActivityTaskSource {
|
|
132
|
+
PendingCancel(PendingActivityCancel),
|
|
133
|
+
PendingStart(Result<(PermittedTqResp, bool), PollActivityError>),
|
|
131
134
|
}
|
|
132
135
|
|
|
133
136
|
impl WorkerActivityTasks {
|
|
@@ -140,90 +143,186 @@ impl WorkerActivityTasks {
|
|
|
140
143
|
max_heartbeat_throttle_interval: Duration,
|
|
141
144
|
default_heartbeat_throttle_interval: Duration,
|
|
142
145
|
) -> Self {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
+
let semaphore = Arc::new(MeteredSemaphore::new(
|
|
147
|
+
max_activity_tasks,
|
|
148
|
+
metrics.with_new_attrs([activity_worker_type()]),
|
|
149
|
+
MetricsContext::available_task_slots,
|
|
150
|
+
));
|
|
151
|
+
let poller_shutdown_token = CancellationToken::new();
|
|
152
|
+
let rate_limiter = max_worker_act_per_sec.and_then(|ps| {
|
|
153
|
+
Quota::with_period(Duration::from_secs_f64(ps.recip())).map(RateLimiter::direct)
|
|
154
|
+
});
|
|
155
|
+
let outstanding_activity_tasks = Arc::new(DashMap::new());
|
|
156
|
+
let server_poller_stream = new_activity_task_poller(
|
|
146
157
|
poller,
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
158
|
+
semaphore.clone(),
|
|
159
|
+
rate_limiter,
|
|
160
|
+
metrics.clone(),
|
|
161
|
+
poller_shutdown_token.clone(),
|
|
162
|
+
);
|
|
163
|
+
let (eager_activities_tx, eager_activities_rx) = unbounded_channel();
|
|
164
|
+
let eager_activities_semaphore = ClosableMeteredSemaphore::new_arc(semaphore);
|
|
165
|
+
|
|
166
|
+
let start_tasks_stream_complete = CancellationToken::new();
|
|
167
|
+
let starts_stream = Self::merge_start_task_sources(
|
|
168
|
+
eager_activities_rx,
|
|
169
|
+
server_poller_stream,
|
|
170
|
+
eager_activities_semaphore.clone(),
|
|
171
|
+
start_tasks_stream_complete.clone(),
|
|
172
|
+
);
|
|
173
|
+
let (heartbeat_manager, cancels_rx) = ActivityHeartbeatManager::new(client);
|
|
174
|
+
let complete_notify = Arc::new(Notify::new());
|
|
175
|
+
let source_stream = stream::select_with_strategy(
|
|
176
|
+
UnboundedReceiverStream::new(cancels_rx).map(ActivityTaskSource::from),
|
|
177
|
+
starts_stream.map(ActivityTaskSource::from),
|
|
178
|
+
|_: &mut ()| PollNext::Left,
|
|
179
|
+
);
|
|
180
|
+
// Create a task stream composed of (in poll preference order):
|
|
181
|
+
// cancels_stream ------------------------------+--- activity_task_stream
|
|
182
|
+
// eager_activities_rx ---+--- starts_stream ---|
|
|
183
|
+
// server_poll_stream ---|
|
|
184
|
+
let activity_task_stream = Self::merge_source_streams(
|
|
185
|
+
source_stream,
|
|
186
|
+
outstanding_activity_tasks.clone(),
|
|
187
|
+
start_tasks_stream_complete,
|
|
188
|
+
complete_notify.clone(),
|
|
189
|
+
metrics.clone(),
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
Self {
|
|
193
|
+
poller_shutdown_token,
|
|
194
|
+
eager_activities_tx,
|
|
195
|
+
heartbeat_manager,
|
|
196
|
+
activity_task_stream: Mutex::new(activity_task_stream.boxed()),
|
|
197
|
+
outstanding_activity_tasks,
|
|
198
|
+
eager_activities_semaphore,
|
|
199
|
+
complete_notify,
|
|
157
200
|
metrics,
|
|
158
201
|
max_heartbeat_throttle_interval,
|
|
159
202
|
default_heartbeat_throttle_interval,
|
|
203
|
+
poll_returned_shutdown_token: CancellationToken::new(),
|
|
160
204
|
}
|
|
161
205
|
}
|
|
162
206
|
|
|
163
|
-
|
|
164
|
-
|
|
207
|
+
/// Merges the server poll and eager [ActivityTask] sources
|
|
208
|
+
fn merge_start_task_sources(
|
|
209
|
+
non_poll_tasks_rx: UnboundedReceiver<TrackedPermittedTqResp>,
|
|
210
|
+
poller_stream: impl Stream<Item = Result<PermittedTqResp, tonic::Status>>,
|
|
211
|
+
eager_activities_semaphore: Arc<ClosableMeteredSemaphore>,
|
|
212
|
+
on_complete_token: CancellationToken,
|
|
213
|
+
) -> impl Stream<Item = Result<(PermittedTqResp, bool), PollActivityError>> {
|
|
214
|
+
let non_poll_stream = stream::unfold(
|
|
215
|
+
(non_poll_tasks_rx, eager_activities_semaphore),
|
|
216
|
+
|(mut non_poll_tasks_rx, eager_activities_semaphore)| async move {
|
|
217
|
+
loop {
|
|
218
|
+
tokio::select! {
|
|
219
|
+
biased;
|
|
220
|
+
|
|
221
|
+
task_opt = non_poll_tasks_rx.recv() => {
|
|
222
|
+
// Add is_eager true and wrap in Result
|
|
223
|
+
return task_opt.map(|task| (Ok((PermittedTqResp{ permit: task.permit.into(), resp: task.resp }, true)), (non_poll_tasks_rx, eager_activities_semaphore)));
|
|
224
|
+
}
|
|
225
|
+
_ = eager_activities_semaphore.close_complete() => {
|
|
226
|
+
// Once shutting down, we stop accepting eager activities
|
|
227
|
+
non_poll_tasks_rx.close();
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
);
|
|
234
|
+
// Add is_eager false
|
|
235
|
+
let poller_stream = poller_stream.map(|res| res.map(|task| (task, false)));
|
|
236
|
+
|
|
237
|
+
// Prefer eager activities over polling the server
|
|
238
|
+
stream::select_with_strategy(non_poll_stream, poller_stream, |_: &mut ()| PollNext::Left)
|
|
239
|
+
.map(|res| res.map_err(|err| err.into()))
|
|
240
|
+
// This map, chain, filter_map sequence is here to cancel the token when this stream ends.
|
|
241
|
+
.map(Some)
|
|
242
|
+
.chain(futures::stream::once(async move {
|
|
243
|
+
on_complete_token.cancel();
|
|
244
|
+
None
|
|
245
|
+
}))
|
|
246
|
+
.filter_map(future::ready)
|
|
165
247
|
}
|
|
166
248
|
|
|
167
|
-
///
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
249
|
+
/// Builds an [ActivityTask] stream for cancellation tasks from cancels delivered from heartbeats
|
|
250
|
+
fn merge_source_streams(
|
|
251
|
+
source_stream: impl Stream<Item = ActivityTaskSource>,
|
|
252
|
+
outstanding_tasks: Arc<DashMap<TaskToken, RemoteInFlightActInfo>>,
|
|
253
|
+
start_tasks_stream_complete: CancellationToken,
|
|
254
|
+
complete_notify: Arc<Notify>,
|
|
255
|
+
metrics: MetricsContext,
|
|
256
|
+
) -> impl Stream<Item = Result<ActivityTask, PollActivityError>> {
|
|
257
|
+
let outstanding_tasks_clone = outstanding_tasks.clone();
|
|
258
|
+
source_stream.filter_map(move |source| {
|
|
259
|
+
let outstanding_tasks = outstanding_tasks.clone();
|
|
260
|
+
let metrics = metrics.clone();
|
|
261
|
+
async move {
|
|
262
|
+
match source {
|
|
263
|
+
ActivityTaskSource::PendingCancel(next_pc) => {
|
|
264
|
+
// It's possible that activity has been completed and we no longer have an
|
|
265
|
+
// outstanding activity task. This is fine because it means that we no
|
|
266
|
+
// longer need to cancel this activity, so we'll just ignore such orphaned
|
|
267
|
+
// cancellations.
|
|
268
|
+
if let Some(mut details) = outstanding_tasks.get_mut(&next_pc.task_token) {
|
|
269
|
+
if details.issued_cancel_to_lang {
|
|
270
|
+
// Don't double-issue cancellations
|
|
271
|
+
return None
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
details.issued_cancel_to_lang = true;
|
|
275
|
+
if next_pc.reason == ActivityCancelReason::NotFound {
|
|
276
|
+
details.known_not_found = true;
|
|
277
|
+
}
|
|
278
|
+
Some(Ok(ActivityTask::cancel_from_ids(next_pc.task_token.0, next_pc.reason)))
|
|
279
|
+
} else {
|
|
280
|
+
debug!(task_token = ?next_pc.task_token, "Unknown activity task when issuing cancel");
|
|
281
|
+
// If we can't find the activity here, it's already been completed,
|
|
282
|
+
// in which case issuing a cancel again is pointless.
|
|
283
|
+
None
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
ActivityTaskSource::PendingStart(res) => {
|
|
287
|
+
Some(res.map(|(task, is_eager)| {
|
|
288
|
+
Self::about_to_issue_task(outstanding_tasks, task, is_eager, metrics)
|
|
289
|
+
}))
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}).take_until(async move {
|
|
294
|
+
start_tasks_stream_complete.cancelled().await;
|
|
295
|
+
while !outstanding_tasks_clone.is_empty() {
|
|
296
|
+
complete_notify.notified().await
|
|
297
|
+
}
|
|
298
|
+
})
|
|
172
299
|
}
|
|
173
300
|
|
|
174
|
-
pub(crate)
|
|
175
|
-
self.
|
|
176
|
-
self.
|
|
301
|
+
pub(crate) fn notify_shutdown(&self) {
|
|
302
|
+
self.poller_shutdown_token.cancel();
|
|
303
|
+
self.eager_activities_semaphore.close();
|
|
177
304
|
}
|
|
178
305
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
let poll_with_semaphore = async {
|
|
184
|
-
// Acquire and subsequently forget a permit for an outstanding activity. When they are
|
|
185
|
-
// completed, we must add a new permit to the semaphore, since holding the permit the
|
|
186
|
-
// entire time lang does work would be a challenge.
|
|
187
|
-
let perm = self
|
|
188
|
-
.activities_semaphore
|
|
189
|
-
.acquire_owned()
|
|
190
|
-
.await
|
|
191
|
-
.expect("outstanding activity semaphore not closed");
|
|
192
|
-
if let Some(ref rl) = self.ratelimiter {
|
|
193
|
-
rl.until_ready().await;
|
|
194
|
-
}
|
|
195
|
-
(self.poller.poll().await, perm)
|
|
196
|
-
};
|
|
306
|
+
async fn shutdown_complete(&self) {
|
|
307
|
+
self.poll_returned_shutdown_token.cancelled().await;
|
|
308
|
+
self.heartbeat_manager.shutdown().await;
|
|
309
|
+
}
|
|
197
310
|
|
|
198
|
-
|
|
199
|
-
|
|
311
|
+
pub(crate) async fn shutdown(&self) {
|
|
312
|
+
self.notify_shutdown();
|
|
313
|
+
self.shutdown_complete().await;
|
|
314
|
+
}
|
|
200
315
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
// Timeout
|
|
212
|
-
self.metrics.act_poll_timeout();
|
|
213
|
-
return Ok(None)
|
|
214
|
-
}
|
|
215
|
-
let work = self.about_to_issue_task(PermittedTqResp {
|
|
216
|
-
resp: work, permit
|
|
217
|
-
});
|
|
218
|
-
Ok(Some(work))
|
|
219
|
-
}
|
|
220
|
-
None => {
|
|
221
|
-
Err(PollActivityError::ShutDown)
|
|
222
|
-
}
|
|
223
|
-
Some(Err(e)) => Err(e.into())
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
316
|
+
/// Exclusive poll for activity tasks
|
|
317
|
+
///
|
|
318
|
+
/// Polls the various task sources (server polls, eager activities, cancellations) while respecting the provided rate limits and allowed concurrency.
|
|
319
|
+
/// Returns Err(PollActivityError::ShutDown) after shutdown is completed and all tasks sources are depleted.
|
|
320
|
+
pub(crate) async fn poll(&self) -> Result<ActivityTask, PollActivityError> {
|
|
321
|
+
let mut poller_stream = self.activity_task_stream.lock().await;
|
|
322
|
+
poller_stream.next().await.unwrap_or_else(|| {
|
|
323
|
+
self.poll_returned_shutdown_token.cancel();
|
|
324
|
+
Err(PollActivityError::ShutDown)
|
|
325
|
+
})
|
|
227
326
|
}
|
|
228
327
|
|
|
229
328
|
pub(crate) async fn complete(
|
|
@@ -234,12 +333,14 @@ impl WorkerActivityTasks {
|
|
|
234
333
|
) {
|
|
235
334
|
if let Some((_, act_info)) = self.outstanding_activity_tasks.remove(&task_token) {
|
|
236
335
|
let act_metrics = self.metrics.with_new_attrs([
|
|
237
|
-
activity_type(act_info.base.activity_type
|
|
238
|
-
workflow_type(act_info.base.workflow_type
|
|
336
|
+
activity_type(act_info.base.activity_type),
|
|
337
|
+
workflow_type(act_info.base.workflow_type),
|
|
239
338
|
]);
|
|
339
|
+
Span::current().record("workflow_id", act_info.base.workflow_id);
|
|
340
|
+
Span::current().record("run_id", act_info.base.workflow_run_id);
|
|
240
341
|
act_metrics.act_execution_latency(act_info.base.start_time.elapsed());
|
|
241
342
|
let known_not_found = act_info.known_not_found;
|
|
242
|
-
|
|
343
|
+
|
|
243
344
|
self.heartbeat_manager.evict(task_token.clone()).await;
|
|
244
345
|
self.complete_notify.notify_waiters();
|
|
245
346
|
|
|
@@ -331,57 +432,39 @@ impl WorkerActivityTasks {
|
|
|
331
432
|
/// Returns a handle that the workflows management side can use to interact with this manager
|
|
332
433
|
pub(crate) fn get_handle_for_workflows(&self) -> ActivitiesFromWFTsHandle {
|
|
333
434
|
ActivitiesFromWFTsHandle {
|
|
334
|
-
sem: self.
|
|
335
|
-
tx: self.
|
|
435
|
+
sem: self.eager_activities_semaphore.clone(),
|
|
436
|
+
tx: self.eager_activities_tx.clone(),
|
|
336
437
|
}
|
|
337
438
|
}
|
|
338
439
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
if let Some(
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
details.known_not_found = true;
|
|
356
|
-
}
|
|
357
|
-
Ok(Some(ActivityTask::cancel_from_ids(task_token.0, reason)))
|
|
358
|
-
} else {
|
|
359
|
-
debug!(task_token = ?task_token, "Unknown activity task when issuing cancel");
|
|
360
|
-
// If we can't find the activity here, it's already been completed,
|
|
361
|
-
// in which case issuing a cancel again is pointless.
|
|
362
|
-
Ok(None)
|
|
440
|
+
/// Called when there is a new [ActivityTask] about to be bubbled up out of the poller
|
|
441
|
+
fn about_to_issue_task(
|
|
442
|
+
outstanding_tasks: Arc<DashMap<TaskToken, RemoteInFlightActInfo>>,
|
|
443
|
+
task: PermittedTqResp,
|
|
444
|
+
is_eager: bool,
|
|
445
|
+
metrics: MetricsContext,
|
|
446
|
+
) -> ActivityTask {
|
|
447
|
+
if let Some(ref act_type) = task.resp.activity_type {
|
|
448
|
+
if let Some(ref wf_type) = task.resp.workflow_type {
|
|
449
|
+
metrics
|
|
450
|
+
.with_new_attrs([
|
|
451
|
+
activity_type(act_type.name.clone()),
|
|
452
|
+
workflow_type(wf_type.name.clone()),
|
|
453
|
+
eager(is_eager),
|
|
454
|
+
])
|
|
455
|
+
.act_task_received();
|
|
363
456
|
}
|
|
364
|
-
} else {
|
|
365
|
-
// The only situation where the next cancel would return none is if the manager
|
|
366
|
-
// was dropped, which can only happen on shutdown.
|
|
367
|
-
Err(PollActivityError::ShutDown)
|
|
368
457
|
}
|
|
369
|
-
|
|
458
|
+
// There could be an else statement here but since the response should always contain both
|
|
459
|
+
// activity_type and workflow_type, we won't bother.
|
|
370
460
|
|
|
371
|
-
/// Called when there is a new act task about to be bubbled up out of the manager
|
|
372
|
-
fn about_to_issue_task(&self, task: PermittedTqResp) -> ActivityTask {
|
|
373
461
|
if let Some(dur) = task.resp.sched_to_start() {
|
|
374
|
-
|
|
462
|
+
metrics.act_sched_to_start_latency(dur);
|
|
375
463
|
};
|
|
376
464
|
|
|
377
|
-
|
|
465
|
+
outstanding_tasks.insert(
|
|
378
466
|
task.resp.task_token.clone().into(),
|
|
379
|
-
RemoteInFlightActInfo::new(
|
|
380
|
-
task.resp.activity_type.clone().unwrap_or_default().name,
|
|
381
|
-
task.resp.workflow_type.clone().unwrap_or_default().name,
|
|
382
|
-
task.resp.heartbeat_timeout.clone(),
|
|
383
|
-
task.permit,
|
|
384
|
-
),
|
|
467
|
+
RemoteInFlightActInfo::new(&task.resp, task.permit.into_used()),
|
|
385
468
|
);
|
|
386
469
|
|
|
387
470
|
ActivityTask::start_from_poll_resp(task.resp)
|
|
@@ -389,38 +472,48 @@ impl WorkerActivityTasks {
|
|
|
389
472
|
|
|
390
473
|
#[cfg(test)]
|
|
391
474
|
pub(crate) fn remaining_activity_capacity(&self) -> usize {
|
|
392
|
-
self.
|
|
475
|
+
self.eager_activities_semaphore.available_permits()
|
|
393
476
|
}
|
|
394
477
|
}
|
|
395
478
|
|
|
396
479
|
/// Provides facilities for the workflow side of things to interact with the activity manager.
|
|
397
480
|
/// Allows for the handling of activities returned by WFT completions.
|
|
398
481
|
pub(crate) struct ActivitiesFromWFTsHandle {
|
|
399
|
-
sem: Arc<
|
|
400
|
-
tx:
|
|
482
|
+
sem: Arc<ClosableMeteredSemaphore>,
|
|
483
|
+
tx: UnboundedSender<TrackedPermittedTqResp>,
|
|
401
484
|
}
|
|
402
485
|
|
|
403
486
|
impl ActivitiesFromWFTsHandle {
|
|
404
487
|
/// Returns a handle that can be used to reserve an activity slot. EX: When requesting eager
|
|
405
488
|
/// dispatch of an activity to this worker upon workflow task completion
|
|
406
|
-
pub(crate) fn reserve_slot(&self) -> Option<
|
|
489
|
+
pub(crate) fn reserve_slot(&self) -> Option<TrackedOwnedMeteredSemPermit> {
|
|
490
|
+
// TODO: check if rate limit is not exceeded and count this reservation towards the rate limit
|
|
407
491
|
self.sem.try_acquire_owned().ok()
|
|
408
492
|
}
|
|
409
493
|
|
|
410
494
|
/// Queue new activity tasks for dispatch received from non-polling sources (ex: eager returns
|
|
411
495
|
/// from WFT completion)
|
|
412
|
-
pub(crate) fn add_tasks(&self, tasks: impl IntoIterator<Item =
|
|
496
|
+
pub(crate) fn add_tasks(&self, tasks: impl IntoIterator<Item = TrackedPermittedTqResp>) {
|
|
413
497
|
for t in tasks.into_iter() {
|
|
414
|
-
|
|
498
|
+
// Technically we should be reporting `activity_task_received` here, but for simplicity
|
|
499
|
+
// and time insensitivity, that metric is tracked in `about_to_issue_task`.
|
|
500
|
+
self.tx.send(t).expect("Receive half cannot be dropped");
|
|
415
501
|
}
|
|
416
502
|
}
|
|
417
503
|
}
|
|
418
504
|
|
|
505
|
+
#[derive(Debug)]
|
|
419
506
|
pub(crate) struct PermittedTqResp {
|
|
420
507
|
pub permit: OwnedMeteredSemPermit,
|
|
421
508
|
pub resp: PollActivityTaskQueueResponse,
|
|
422
509
|
}
|
|
423
510
|
|
|
511
|
+
#[derive(Debug)]
|
|
512
|
+
pub(crate) struct TrackedPermittedTqResp {
|
|
513
|
+
pub permit: TrackedOwnedMeteredSemPermit,
|
|
514
|
+
pub resp: PollActivityTaskQueueResponse,
|
|
515
|
+
}
|
|
516
|
+
|
|
424
517
|
#[cfg(test)]
|
|
425
518
|
mod tests {
|
|
426
519
|
use super::*;
|
|
@@ -449,13 +542,13 @@ mod tests {
|
|
|
449
542
|
Some(2.0),
|
|
450
543
|
poller,
|
|
451
544
|
Arc::new(mock_manual_workflow_client()),
|
|
452
|
-
MetricsContext::
|
|
545
|
+
MetricsContext::no_op(),
|
|
453
546
|
Duration::from_secs(1),
|
|
454
547
|
Duration::from_secs(1),
|
|
455
548
|
);
|
|
456
549
|
let start = Instant::now();
|
|
457
|
-
atm.poll().await.unwrap()
|
|
458
|
-
atm.poll().await.unwrap()
|
|
550
|
+
atm.poll().await.unwrap();
|
|
551
|
+
atm.poll().await.unwrap();
|
|
459
552
|
// At least half a second will have elapsed since we only allow 2 tasks per second.
|
|
460
553
|
// With no ratelimit, even on a slow CI server with lots of load, this would typically take
|
|
461
554
|
// low single digit ms or less.
|
|
@@ -1,22 +1,40 @@
|
|
|
1
1
|
use super::*;
|
|
2
2
|
use futures::Future;
|
|
3
3
|
|
|
4
|
+
pub(crate) static DEFAULT_TEST_CAPABILITIES: &Capabilities = &Capabilities {
|
|
5
|
+
signal_and_query_header: true,
|
|
6
|
+
internal_error_differentiation: true,
|
|
7
|
+
activity_failure_include_heartbeat: true,
|
|
8
|
+
supports_schedules: true,
|
|
9
|
+
encoded_failure_attributes: true,
|
|
10
|
+
build_id_based_versioning: true,
|
|
11
|
+
upsert_memo: true,
|
|
12
|
+
eager_workflow_start: true,
|
|
13
|
+
sdk_metadata: true,
|
|
14
|
+
};
|
|
15
|
+
|
|
4
16
|
#[cfg(test)]
|
|
5
17
|
/// Create a mock client primed with basic necessary expectations
|
|
6
18
|
pub(crate) fn mock_workflow_client() -> MockWorkerClient {
|
|
7
|
-
MockWorkerClient::new()
|
|
19
|
+
let mut r = MockWorkerClient::new();
|
|
20
|
+
r.expect_capabilities()
|
|
21
|
+
.returning(|| Some(DEFAULT_TEST_CAPABILITIES));
|
|
22
|
+
r
|
|
8
23
|
}
|
|
9
24
|
|
|
10
25
|
/// Create a mock manual client primed with basic necessary expectations
|
|
11
26
|
pub(crate) fn mock_manual_workflow_client() -> MockManualWorkerClient {
|
|
12
|
-
MockManualWorkerClient::new()
|
|
27
|
+
let mut r = MockManualWorkerClient::new();
|
|
28
|
+
r.expect_capabilities()
|
|
29
|
+
.returning(|| Some(DEFAULT_TEST_CAPABILITIES));
|
|
30
|
+
r
|
|
13
31
|
}
|
|
14
32
|
|
|
15
33
|
// Need a version of the mock that can return futures so we can return potentially pending
|
|
16
34
|
// results. This is really annoying b/c of the async trait stuff. Need
|
|
17
35
|
// https://github.com/asomers/mockall/issues/189 to be fixed for it to go away.
|
|
18
36
|
mockall::mock! {
|
|
19
|
-
pub ManualWorkerClient {}
|
|
37
|
+
pub(crate) ManualWorkerClient {}
|
|
20
38
|
#[allow(unused)]
|
|
21
39
|
impl WorkerClient for ManualWorkerClient {
|
|
22
40
|
fn poll_workflow_task<'a, 'b>(&'a self, task_queue: String, is_sticky: bool)
|
|
@@ -83,5 +101,7 @@ mockall::mock! {
|
|
|
83
101
|
query_result: QueryResult,
|
|
84
102
|
) -> impl Future<Output = Result<RespondQueryTaskCompletedResponse>> + Send + 'b
|
|
85
103
|
where 'a: 'b, Self: 'b;
|
|
104
|
+
|
|
105
|
+
fn capabilities(&self) -> Option<&'static get_system_info_response::Capabilities>;
|
|
86
106
|
}
|
|
87
107
|
}
|