@temporalio/core-bridge 1.8.6 → 1.9.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.
- package/Cargo.lock +670 -594
- package/Cargo.toml +2 -1
- package/lib/errors.js +6 -6
- package/lib/errors.js.map +1 -1
- package/lib/index.d.ts +17 -44
- package/lib/index.js.map +1 -1
- package/package.json +5 -6
- package/releases/aarch64-apple-darwin/index.node +0 -0
- package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
- package/releases/x86_64-apple-darwin/index.node +0 -0
- package/releases/x86_64-pc-windows-msvc/index.node +0 -0
- package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
- package/sdk-core/.github/workflows/heavy.yml +4 -0
- package/sdk-core/.github/workflows/per-pr.yml +96 -0
- package/sdk-core/ARCHITECTURE.md +1 -1
- package/sdk-core/Cargo.toml +10 -0
- package/sdk-core/LICENSE.txt +0 -2
- package/sdk-core/README.md +37 -21
- package/sdk-core/client/Cargo.toml +7 -4
- package/sdk-core/client/src/lib.rs +274 -142
- package/sdk-core/client/src/metrics.rs +68 -57
- package/sdk-core/client/src/raw.rs +191 -45
- package/sdk-core/client/src/retry.rs +20 -0
- package/sdk-core/client/src/worker_registry/mod.rs +264 -0
- package/sdk-core/client/src/workflow_handle/mod.rs +2 -1
- package/sdk-core/core/Cargo.toml +17 -19
- package/sdk-core/core/src/core_tests/activity_tasks.rs +4 -2
- package/sdk-core/core/src/core_tests/child_workflows.rs +7 -7
- package/sdk-core/core/src/core_tests/mod.rs +1 -0
- package/sdk-core/core/src/core_tests/queries.rs +42 -1
- package/sdk-core/core/src/core_tests/replay_flag.rs +29 -39
- package/sdk-core/core/src/core_tests/updates.rs +73 -0
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +52 -1
- package/sdk-core/core/src/ephemeral_server/mod.rs +34 -11
- package/sdk-core/core/src/internal_flags.rs +7 -1
- package/sdk-core/core/src/lib.rs +19 -36
- package/sdk-core/core/src/protosext/mod.rs +12 -4
- package/sdk-core/core/src/protosext/protocol_messages.rs +102 -0
- package/sdk-core/core/src/replay/mod.rs +99 -48
- package/sdk-core/core/src/telemetry/log_export.rs +161 -28
- package/sdk-core/core/src/telemetry/metrics.rs +869 -248
- package/sdk-core/core/src/telemetry/mod.rs +153 -257
- package/sdk-core/core/src/telemetry/prometheus_server.rs +36 -31
- package/sdk-core/core/src/test_help/mod.rs +64 -5
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +12 -2
- package/sdk-core/core/src/worker/activities.rs +276 -10
- package/sdk-core/core/src/worker/client/mocks.rs +18 -0
- package/sdk-core/core/src/worker/client.rs +16 -3
- package/sdk-core/core/src/worker/mod.rs +45 -28
- package/sdk-core/core/src/worker/slot_provider.rs +175 -0
- package/sdk-core/core/src/worker/workflow/driven_workflow.rs +27 -34
- package/sdk-core/core/src/worker/workflow/history_update.rs +5 -2
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +71 -95
- package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +34 -22
- package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +50 -34
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +106 -92
- package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +22 -21
- package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +386 -499
- package/sdk-core/core/src/worker/workflow/machines/mod.rs +12 -2
- package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +33 -26
- package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +198 -215
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +67 -63
- package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +88 -119
- package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +3 -1
- package/sdk-core/core/src/worker/workflow/machines/update_state_machine.rs +411 -0
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +27 -26
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +319 -94
- package/sdk-core/core/src/worker/workflow/managed_run.rs +179 -132
- package/sdk-core/core/src/worker/workflow/mod.rs +129 -58
- package/sdk-core/core/src/worker/workflow/run_cache.rs +16 -26
- package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +2 -2
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +48 -43
- package/sdk-core/core-api/Cargo.toml +8 -7
- package/sdk-core/core-api/src/lib.rs +4 -12
- package/sdk-core/core-api/src/telemetry/metrics.rs +334 -0
- package/sdk-core/core-api/src/telemetry.rs +53 -42
- package/sdk-core/core-api/src/worker.rs +7 -0
- package/sdk-core/{.buildkite/docker → docker}/docker-compose.yaml +1 -1
- package/sdk-core/etc/dynamic-config.yaml +11 -1
- package/sdk-core/fsm/LICENSE.txt +0 -2
- package/sdk-core/fsm/rustfsm_procmacro/Cargo.toml +1 -1
- package/sdk-core/fsm/rustfsm_procmacro/LICENSE.txt +0 -2
- package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +1 -3
- package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +2 -2
- package/sdk-core/fsm/rustfsm_trait/LICENSE.txt +0 -2
- package/sdk-core/sdk/Cargo.toml +2 -2
- package/sdk-core/sdk/src/lib.rs +85 -7
- package/sdk-core/sdk/src/workflow_context/options.rs +4 -0
- package/sdk-core/sdk/src/workflow_context.rs +43 -15
- package/sdk-core/sdk/src/workflow_future.rs +334 -204
- package/sdk-core/sdk-core-protos/Cargo.toml +3 -3
- package/sdk-core/sdk-core-protos/build.rs +14 -14
- package/sdk-core/sdk-core-protos/protos/api_upstream/.buildkite/Dockerfile +2 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/Makefile +99 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/api-linter.yaml +56 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/buf.gen.yaml +20 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/buf.lock +11 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/buf.yaml +18 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/api/annotations.proto +31 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/api/http.proto +379 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/any.proto +162 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/descriptor.proto +1212 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/duration.proto +115 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/empty.proto +51 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/timestamp.proto +144 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/wrappers.proto +123 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/batch/v1/message.proto +12 -9
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/command/v1/message.proto +11 -13
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/common/v1/message.proto +33 -4
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/failed_cause.proto +2 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/reset.proto +4 -4
- package/sdk-core/{protos/api_upstream/build/tools.go → sdk-core-protos/protos/api_upstream/temporal/api/export/v1/message.proto} +22 -6
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/filter/v1/message.proto +2 -4
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/history/v1/message.proto +21 -23
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/namespace/v1/message.proto +2 -4
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/operatorservice/v1/request_response.proto +2 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/operatorservice/v1/service.proto +4 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/replication/v1/message.proto +1 -3
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/schedule/v1/message.proto +36 -20
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +13 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/workflow_metadata.proto +66 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -4
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/update/v1/message.proto +1 -1
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/version/v1/message.proto +2 -3
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/workflow/v1/message.proto +24 -22
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/workflowservice/v1/request_response.proto +84 -32
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/workflowservice/v1/service.proto +205 -47
- package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +57 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +27 -0
- package/sdk-core/sdk-core-protos/src/history_builder.rs +67 -2
- package/sdk-core/sdk-core-protos/src/history_info.rs +1 -1
- package/sdk-core/sdk-core-protos/src/lib.rs +76 -3
- package/sdk-core/sdk-core-protos/src/utilities.rs +14 -0
- package/sdk-core/test-utils/Cargo.toml +6 -1
- package/sdk-core/test-utils/src/canned_histories.rs +3 -57
- package/sdk-core/test-utils/src/interceptors.rs +46 -0
- package/sdk-core/test-utils/src/lib.rs +106 -38
- package/sdk-core/tests/integ_tests/metrics_tests.rs +110 -15
- package/sdk-core/tests/integ_tests/queries_tests.rs +174 -3
- package/sdk-core/tests/integ_tests/update_tests.rs +908 -0
- package/sdk-core/tests/integ_tests/visibility_tests.rs +4 -4
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +44 -1
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +4 -4
- package/sdk-core/tests/integ_tests/workflow_tests/eager.rs +61 -0
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +27 -2
- package/sdk-core/tests/integ_tests/workflow_tests.rs +142 -3
- package/sdk-core/tests/main.rs +2 -1
- package/sdk-core/tests/runner.rs +15 -2
- package/src/conversions.rs +107 -96
- package/src/helpers.rs +74 -0
- package/src/runtime.rs +29 -15
- package/src/worker.rs +14 -61
- package/ts/index.ts +23 -54
- package/sdk-core/.buildkite/docker/Dockerfile +0 -9
- package/sdk-core/.buildkite/docker/build.sh +0 -5
- package/sdk-core/.buildkite/docker/docker-compose-ci.yaml +0 -27
- package/sdk-core/.buildkite/pipeline.yml +0 -57
- package/sdk-core/.github/workflows/semgrep.yml +0 -25
- package/sdk-core/client/LICENSE.txt +0 -23
- package/sdk-core/core/LICENSE.txt +0 -23
- package/sdk-core/core/src/worker/workflow/bridge.rs +0 -35
- package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +0 -215
- package/sdk-core/core-api/LICENSE.txt +0 -23
- package/sdk-core/protos/api_upstream/.buildkite/Dockerfile +0 -2
- package/sdk-core/protos/api_upstream/Makefile +0 -80
- package/sdk-core/protos/api_upstream/api-linter.yaml +0 -40
- package/sdk-core/protos/api_upstream/buf.yaml +0 -9
- package/sdk-core/protos/api_upstream/build/go.mod +0 -7
- package/sdk-core/protos/api_upstream/build/go.sum +0 -5
- package/sdk-core/protos/api_upstream/go.mod +0 -6
- package/sdk-core/protos/testsrv_upstream/dependencies/gogoproto/gogo.proto +0 -141
- package/sdk-core/sdk/LICENSE.txt +0 -23
- package/sdk-core/sdk-core-protos/LICENSE.txt +0 -23
- /package/sdk-core/{.buildkite/docker → docker}/docker-compose-telem.yaml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.buildkite/docker-compose.yml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.buildkite/pipeline.yml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.github/CODEOWNERS +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.github/workflows/publish-docs.yml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.github/workflows/trigger-api-go-update.yml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/LICENSE +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/README.md +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/batch_operation.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/command_type.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/common.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/event_type.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/namespace.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/query.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/schedule.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/task_queue.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/update.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/workflow.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/errordetails/v1/message.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/failure/v1/message.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/protocol/v1/message.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/query/v1/message.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/google/rpc/status.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/grpc/health/v1/health.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/activity_result/activity_result.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/activity_task/activity_task.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/child_workflow/child_workflow.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/common/common.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/core_interface.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/external_data/external_data.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/Makefile +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/api-linter.yaml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/buf.yaml +0 -0
- /package/sdk-core/{protos/api_upstream → sdk-core-protos/protos/testsrv_upstream}/dependencies/gogoproto/gogo.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/temporal/api/testservice/v1/service.proto +0 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
//! This module enables the tracking of workers that are associated with a client instance.
|
|
2
|
+
//! This is needed to implement Eager Workflow Start, a latency optimization in which the client,
|
|
3
|
+
//! after reserving a slot, directly forwards a WFT to a local worker.
|
|
4
|
+
|
|
5
|
+
use parking_lot::RwLock;
|
|
6
|
+
use slotmap::SlotMap;
|
|
7
|
+
use std::collections::{hash_map::Entry::Vacant, HashMap};
|
|
8
|
+
|
|
9
|
+
use temporal_sdk_core_protos::temporal::api::workflowservice::v1::PollWorkflowTaskQueueResponse;
|
|
10
|
+
|
|
11
|
+
slotmap::new_key_type! {
|
|
12
|
+
/// Registration key for a worker
|
|
13
|
+
pub struct WorkerKey;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/// This trait is implemented by an object associated with a worker, which provides WFT processing slots.
|
|
17
|
+
#[cfg_attr(test, mockall::automock)]
|
|
18
|
+
pub trait SlotProvider: std::fmt::Debug {
|
|
19
|
+
/// The namespace for the WFTs that it can process.
|
|
20
|
+
fn namespace(&self) -> &str;
|
|
21
|
+
/// The task queue this provider listens to.
|
|
22
|
+
fn task_queue(&self) -> &str;
|
|
23
|
+
/// Try to reserve a slot on this worker.
|
|
24
|
+
fn try_reserve_wft_slot(&self) -> Option<Box<dyn Slot + Send>>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/// This trait represents a slot reserved for processing a WFT by a worker.
|
|
28
|
+
#[cfg_attr(test, mockall::automock)]
|
|
29
|
+
pub trait Slot {
|
|
30
|
+
/// Consumes this slot by dispatching a WFT to its worker. This can only be called once.
|
|
31
|
+
fn schedule_wft(
|
|
32
|
+
self: Box<Self>,
|
|
33
|
+
task: PollWorkflowTaskQueueResponse,
|
|
34
|
+
) -> Result<(), anyhow::Error>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
|
|
38
|
+
struct SlotKey {
|
|
39
|
+
namespace: String,
|
|
40
|
+
task_queue: String,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
impl SlotKey {
|
|
44
|
+
fn new(namespace: String, task_queue: String) -> SlotKey {
|
|
45
|
+
SlotKey {
|
|
46
|
+
namespace,
|
|
47
|
+
task_queue,
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/// This is an inner class for [SlotManager] needed to hide the mutex.
|
|
53
|
+
#[derive(Default, Debug)]
|
|
54
|
+
struct SlotManagerImpl {
|
|
55
|
+
/// Maps keys, i.e., namespace#task_queue, to provider.
|
|
56
|
+
providers: HashMap<SlotKey, Box<dyn SlotProvider + Send + Sync>>,
|
|
57
|
+
/// Maps ids to keys in `providers`.
|
|
58
|
+
index: SlotMap<WorkerKey, SlotKey>,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
impl SlotManagerImpl {
|
|
62
|
+
/// Factory method.
|
|
63
|
+
fn new() -> Self {
|
|
64
|
+
Self {
|
|
65
|
+
index: Default::default(),
|
|
66
|
+
providers: Default::default(),
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fn try_reserve_wft_slot(
|
|
71
|
+
&self,
|
|
72
|
+
namespace: String,
|
|
73
|
+
task_queue: String,
|
|
74
|
+
) -> Option<Box<dyn Slot + Send>> {
|
|
75
|
+
let key = SlotKey::new(namespace, task_queue);
|
|
76
|
+
if let Some(p) = self.providers.get(&key) {
|
|
77
|
+
if let Some(slot) = p.try_reserve_wft_slot() {
|
|
78
|
+
return Some(slot);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
None
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
fn register(&mut self, provider: Box<dyn SlotProvider + Send + Sync>) -> Option<WorkerKey> {
|
|
85
|
+
let key = SlotKey::new(
|
|
86
|
+
provider.namespace().to_string(),
|
|
87
|
+
provider.task_queue().to_string(),
|
|
88
|
+
);
|
|
89
|
+
if let Vacant(p) = self.providers.entry(key.clone()) {
|
|
90
|
+
p.insert(provider);
|
|
91
|
+
Some(self.index.insert(key))
|
|
92
|
+
} else {
|
|
93
|
+
warn!("Ignoring registration for worker: {key:?}.");
|
|
94
|
+
None
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
fn unregister(&mut self, id: WorkerKey) {
|
|
99
|
+
if let Some(key) = self.index.remove(id) {
|
|
100
|
+
self.providers.remove(&key);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
#[cfg(test)]
|
|
105
|
+
fn num_providers(&self) -> (usize, usize) {
|
|
106
|
+
(self.index.len(), self.providers.len())
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/// Enables local workers to made themselves visible to a shared client instance.
|
|
111
|
+
/// There can only be one worker registered per namespace+queue_name+client, others will get ignored.
|
|
112
|
+
/// It also provides a convenient method to find compatible slots within the collection.
|
|
113
|
+
#[derive(Default, Debug)]
|
|
114
|
+
pub struct SlotManager {
|
|
115
|
+
manager: RwLock<SlotManagerImpl>,
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
impl SlotManager {
|
|
119
|
+
/// Factory method.
|
|
120
|
+
pub fn new() -> Self {
|
|
121
|
+
Self {
|
|
122
|
+
manager: RwLock::new(SlotManagerImpl::new()),
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/// Try to reserve a compatible processing slot in any of the registered workers.
|
|
127
|
+
pub(crate) fn try_reserve_wft_slot(
|
|
128
|
+
&self,
|
|
129
|
+
namespace: String,
|
|
130
|
+
task_queue: String,
|
|
131
|
+
) -> Option<Box<dyn Slot + Send>> {
|
|
132
|
+
self.manager
|
|
133
|
+
.read()
|
|
134
|
+
.try_reserve_wft_slot(namespace, task_queue)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/// Register a local worker that can provide WFT processing slots.
|
|
138
|
+
pub fn register(&self, provider: Box<dyn SlotProvider + Send + Sync>) -> Option<WorkerKey> {
|
|
139
|
+
self.manager.write().register(provider)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/// Unregister a provider, typically when its worker starts shutdown.
|
|
143
|
+
pub fn unregister(&self, id: WorkerKey) {
|
|
144
|
+
self.manager.write().unregister(id)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
#[cfg(test)]
|
|
148
|
+
/// Returns (num_providers, num_buckets), where a bucket key is namespace+task_queue.
|
|
149
|
+
/// There is only one provider per bucket so `num_providers` should be equal to `num_buckets`.
|
|
150
|
+
pub fn num_providers(&self) -> (usize, usize) {
|
|
151
|
+
self.manager.read().num_providers()
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
#[cfg(test)]
|
|
156
|
+
mod tests {
|
|
157
|
+
use super::*;
|
|
158
|
+
|
|
159
|
+
fn new_mock_slot(with_error: bool) -> Box<MockSlot> {
|
|
160
|
+
let mut mock_slot = MockSlot::new();
|
|
161
|
+
if with_error {
|
|
162
|
+
mock_slot
|
|
163
|
+
.expect_schedule_wft()
|
|
164
|
+
.returning(|_| Err(anyhow::anyhow!("Changed my mind")));
|
|
165
|
+
} else {
|
|
166
|
+
mock_slot.expect_schedule_wft().returning(|_| Ok(()));
|
|
167
|
+
}
|
|
168
|
+
Box::new(mock_slot)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
fn new_mock_provider(
|
|
172
|
+
namespace: String,
|
|
173
|
+
task_queue: String,
|
|
174
|
+
with_error: bool,
|
|
175
|
+
no_slots: bool,
|
|
176
|
+
) -> MockSlotProvider {
|
|
177
|
+
let mut mock_provider = MockSlotProvider::new();
|
|
178
|
+
mock_provider
|
|
179
|
+
.expect_try_reserve_wft_slot()
|
|
180
|
+
.returning(move || {
|
|
181
|
+
if no_slots {
|
|
182
|
+
None
|
|
183
|
+
} else {
|
|
184
|
+
Some(new_mock_slot(with_error))
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
mock_provider.expect_namespace().return_const(namespace);
|
|
188
|
+
mock_provider.expect_task_queue().return_const(task_queue);
|
|
189
|
+
mock_provider
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
#[test]
|
|
193
|
+
fn registry_respects_registration_order() {
|
|
194
|
+
let mock_provider1 =
|
|
195
|
+
new_mock_provider("foo".to_string(), "bar_q".to_string(), false, false);
|
|
196
|
+
let mock_provider2 = new_mock_provider("foo".to_string(), "bar_q".to_string(), false, true);
|
|
197
|
+
|
|
198
|
+
let manager = SlotManager::new();
|
|
199
|
+
let some_slots = manager.register(Box::new(mock_provider1));
|
|
200
|
+
let no_slots = manager.register(Box::new(mock_provider2));
|
|
201
|
+
assert!(no_slots.is_none());
|
|
202
|
+
|
|
203
|
+
let mut found = 0;
|
|
204
|
+
for _ in 0..10 {
|
|
205
|
+
if manager
|
|
206
|
+
.try_reserve_wft_slot("foo".to_string(), "bar_q".to_string())
|
|
207
|
+
.is_some()
|
|
208
|
+
{
|
|
209
|
+
found += 1;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
assert_eq!(found, 10);
|
|
213
|
+
assert_eq!((1, 1), manager.num_providers());
|
|
214
|
+
|
|
215
|
+
manager.unregister(some_slots.unwrap());
|
|
216
|
+
assert_eq!((0, 0), manager.num_providers());
|
|
217
|
+
|
|
218
|
+
let mock_provider1 =
|
|
219
|
+
new_mock_provider("foo".to_string(), "bar_q".to_string(), false, false);
|
|
220
|
+
let mock_provider2 = new_mock_provider("foo".to_string(), "bar_q".to_string(), false, true);
|
|
221
|
+
|
|
222
|
+
let no_slots = manager.register(Box::new(mock_provider2));
|
|
223
|
+
let some_slots = manager.register(Box::new(mock_provider1));
|
|
224
|
+
assert!(some_slots.is_none());
|
|
225
|
+
|
|
226
|
+
let mut not_found = 0;
|
|
227
|
+
for _ in 0..10 {
|
|
228
|
+
if manager
|
|
229
|
+
.try_reserve_wft_slot("foo".to_string(), "bar_q".to_string())
|
|
230
|
+
.is_none()
|
|
231
|
+
{
|
|
232
|
+
not_found += 1;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
assert_eq!(not_found, 10);
|
|
236
|
+
assert_eq!((1, 1), manager.num_providers());
|
|
237
|
+
manager.unregister(no_slots.unwrap());
|
|
238
|
+
assert_eq!((0, 0), manager.num_providers());
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
#[test]
|
|
242
|
+
fn registry_keeps_one_provider_per_namespace() {
|
|
243
|
+
let manager = SlotManager::new();
|
|
244
|
+
let mut worker_keys = vec![];
|
|
245
|
+
for i in 0..10 {
|
|
246
|
+
let namespace = format!("myId{}", i % 3);
|
|
247
|
+
let mock_provider = new_mock_provider(namespace, "bar_q".to_string(), false, false);
|
|
248
|
+
worker_keys.push(manager.register(Box::new(mock_provider)));
|
|
249
|
+
}
|
|
250
|
+
assert_eq!((3, 3), manager.num_providers());
|
|
251
|
+
|
|
252
|
+
let count = worker_keys
|
|
253
|
+
.iter()
|
|
254
|
+
.filter(|key| key.is_some())
|
|
255
|
+
.fold(0, |count, key| {
|
|
256
|
+
manager.unregister(key.unwrap());
|
|
257
|
+
// Should be idempotent
|
|
258
|
+
manager.unregister(key.unwrap());
|
|
259
|
+
count + 1
|
|
260
|
+
});
|
|
261
|
+
assert_eq!(3, count);
|
|
262
|
+
assert_eq!((0, 0), manager.num_providers());
|
|
263
|
+
}
|
|
264
|
+
}
|
|
@@ -54,6 +54,7 @@ pub struct WorkflowHandle<ClientT, ResultT> {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
/// Holds needed information to refer to a specific workflow run, or workflow execution chain
|
|
57
|
+
#[derive(Debug)]
|
|
57
58
|
pub struct WorkflowExecutionInfo {
|
|
58
59
|
/// Namespace the workflow lives in
|
|
59
60
|
pub namespace: String,
|
|
@@ -100,7 +101,7 @@ where
|
|
|
100
101
|
let server_res = self
|
|
101
102
|
.client
|
|
102
103
|
.clone()
|
|
103
|
-
.
|
|
104
|
+
.workflow_client_mut()
|
|
104
105
|
.get_workflow_execution_history(GetWorkflowExecutionHistoryRequest {
|
|
105
106
|
namespace: self.info.namespace.to_string(),
|
|
106
107
|
execution: Some(WorkflowExecution {
|
package/sdk-core/core/Cargo.toml
CHANGED
|
@@ -3,7 +3,7 @@ name = "temporal-sdk-core"
|
|
|
3
3
|
version = "0.1.0"
|
|
4
4
|
authors = ["Spencer Judge <spencer@temporal.io>", "Vitaly Arbuzov <vitaly@temporal.io>"]
|
|
5
5
|
edition = "2021"
|
|
6
|
-
license-file =
|
|
6
|
+
license-file = { workspace = true }
|
|
7
7
|
description = "Library for building new Temporal SDKs"
|
|
8
8
|
homepage = "https://temporal.io/"
|
|
9
9
|
repository = "https://github.com/temporalio/sdk-core"
|
|
@@ -28,7 +28,7 @@ async-trait = "0.1"
|
|
|
28
28
|
base64 = "0.21"
|
|
29
29
|
console-subscriber = { version = "0.1", optional = true }
|
|
30
30
|
crossbeam = "0.8"
|
|
31
|
-
dashmap = "5.
|
|
31
|
+
dashmap = "5.5"
|
|
32
32
|
derive_builder = "0.12"
|
|
33
33
|
derive_more = "0.99"
|
|
34
34
|
enum_dispatch = "0.3"
|
|
@@ -36,18 +36,19 @@ enum-iterator = "1.4"
|
|
|
36
36
|
flate2 = { version = "1.0", optional = true }
|
|
37
37
|
futures = "0.3"
|
|
38
38
|
futures-util = "0.3"
|
|
39
|
-
governor = "0.
|
|
39
|
+
governor = "0.6"
|
|
40
40
|
http = "0.2"
|
|
41
41
|
hyper = "0.14"
|
|
42
|
-
itertools = "0.
|
|
42
|
+
itertools = "0.11"
|
|
43
43
|
lazy_static = "1.4"
|
|
44
|
-
lru = "0.
|
|
44
|
+
lru = "0.11"
|
|
45
45
|
mockall = "0.11"
|
|
46
|
-
nix = { version = "0.
|
|
46
|
+
nix = { version = "0.27", optional = true, features = ["process", "signal"] }
|
|
47
47
|
once_cell = "1.5"
|
|
48
|
-
opentelemetry = {
|
|
49
|
-
|
|
50
|
-
opentelemetry-
|
|
48
|
+
opentelemetry = { workspace = true, features = ["metrics"] }
|
|
49
|
+
opentelemetry_sdk = { version = "0.21", features = ["rt-tokio", "metrics"] }
|
|
50
|
+
opentelemetry-otlp = { version = "0.14", features = ["tokio", "metrics"] }
|
|
51
|
+
opentelemetry-prometheus = "0.14"
|
|
51
52
|
parking_lot = { version = "0.12", features = ["send_guard"] }
|
|
52
53
|
pin-project = "1.0"
|
|
53
54
|
prometheus = "0.13"
|
|
@@ -59,51 +60,48 @@ ringbuf = "0.3"
|
|
|
59
60
|
rmp-serde = { version = "1.1", optional = true }
|
|
60
61
|
serde = "1.0"
|
|
61
62
|
serde_json = "1.0"
|
|
62
|
-
siphasher = "0
|
|
63
|
+
siphasher = "1.0"
|
|
63
64
|
slotmap = "1.0"
|
|
64
65
|
tar = { version = "0.4", optional = true }
|
|
65
66
|
thiserror = "1.0"
|
|
66
67
|
tokio = { version = "1.26", features = ["rt", "rt-multi-thread", "parking_lot", "time", "fs", "process"] }
|
|
67
68
|
tokio-util = { version = "0.7", features = ["io", "io-util"] }
|
|
68
69
|
tokio-stream = "0.1"
|
|
69
|
-
tonic = {
|
|
70
|
+
tonic = { workspace = true, features = ["tls", "tls-roots"] }
|
|
70
71
|
tracing = "0.1"
|
|
71
72
|
tracing-futures = "0.2"
|
|
72
|
-
tracing-opentelemetry = "0.18"
|
|
73
73
|
tracing-subscriber = { version = "0.3", features = ["parking_lot", "env-filter", "registry"] }
|
|
74
74
|
url = "2.2"
|
|
75
75
|
uuid = { version = "1.1", features = ["v4"] }
|
|
76
76
|
zip = { version = "0.6.3", optional = true }
|
|
77
|
+
log = "0.4.20"
|
|
77
78
|
|
|
78
79
|
# 1st party local deps
|
|
79
80
|
[dependencies.temporal-sdk-core-api]
|
|
80
81
|
path = "../core-api"
|
|
81
|
-
|
|
82
|
+
features = ["otel_impls"]
|
|
82
83
|
|
|
83
84
|
[dependencies.temporal-sdk-core-protos]
|
|
84
85
|
path = "../sdk-core-protos"
|
|
85
|
-
version = "0.1"
|
|
86
86
|
features = ["history_builders"]
|
|
87
87
|
|
|
88
88
|
[dependencies.temporal-client]
|
|
89
89
|
path = "../client"
|
|
90
|
-
version = "0.1"
|
|
91
90
|
|
|
92
91
|
[dependencies.rustfsm]
|
|
93
92
|
path = "../fsm"
|
|
94
|
-
version = "0.1"
|
|
95
93
|
|
|
96
94
|
[dev-dependencies]
|
|
97
95
|
assert_matches = "1.4"
|
|
98
96
|
bimap = "0.6.1"
|
|
99
97
|
clap = { version = "4.0", features = ["derive"] }
|
|
100
|
-
criterion = "0.
|
|
101
|
-
rstest = "0.
|
|
98
|
+
criterion = "0.5"
|
|
99
|
+
rstest = "0.18"
|
|
102
100
|
temporal-sdk-core-test-utils = { path = "../test-utils" }
|
|
103
101
|
temporal-sdk = { path = "../sdk" }
|
|
104
102
|
|
|
105
103
|
[build-dependencies]
|
|
106
|
-
tonic-build =
|
|
104
|
+
tonic-build = { workspace = true }
|
|
107
105
|
|
|
108
106
|
[[test]]
|
|
109
107
|
name = "integ_tests"
|
|
@@ -906,8 +906,10 @@ async fn activity_tasks_from_completion_reserve_slots() {
|
|
|
906
906
|
mh.completion_asserts = Some(Box::new(|wftc| {
|
|
907
907
|
// Make sure when we see the completion with the schedule act command that it does
|
|
908
908
|
// not have the eager execution flag set the first time, and does the second.
|
|
909
|
-
if let Some(Attributes::ScheduleActivityTaskCommandAttributes(attrs)) =
|
|
910
|
-
|
|
909
|
+
if let Some(Attributes::ScheduleActivityTaskCommandAttributes(attrs)) = wftc
|
|
910
|
+
.commands
|
|
911
|
+
.first()
|
|
912
|
+
.and_then(|cmd| cmd.attributes.as_ref())
|
|
911
913
|
{
|
|
912
914
|
if attrs.activity_id == "1" {
|
|
913
915
|
assert!(!attrs.request_eager_execution);
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
use crate::{
|
|
2
2
|
replay::DEFAULT_WORKFLOW_TYPE,
|
|
3
3
|
test_help::{
|
|
4
|
-
canned_histories, mock_sdk, mock_worker, single_hist_mock_sg, MockPollCfg,
|
|
4
|
+
build_fake_sdk, canned_histories, mock_sdk, mock_worker, single_hist_mock_sg, MockPollCfg,
|
|
5
|
+
ResponseType,
|
|
5
6
|
},
|
|
6
|
-
worker::
|
|
7
|
+
worker::client::mocks::mock_workflow_client,
|
|
7
8
|
};
|
|
8
9
|
use temporal_client::WorkflowOptions;
|
|
9
|
-
use temporal_sdk::{ChildWorkflowOptions, Signal, WfContext,
|
|
10
|
+
use temporal_sdk::{ChildWorkflowOptions, Signal, WfContext, WorkflowResult};
|
|
10
11
|
use temporal_sdk_core_api::Worker;
|
|
11
12
|
use temporal_sdk_core_protos::coresdk::{
|
|
12
13
|
child_workflow::{child_workflow_result, ChildWorkflowCancellationType},
|
|
@@ -100,11 +101,10 @@ async fn parent_cancels_child_wf(ctx: WfContext) -> WorkflowResult<()> {
|
|
|
100
101
|
|
|
101
102
|
#[tokio::test]
|
|
102
103
|
async fn cancel_child_workflow() {
|
|
103
|
-
let func = WorkflowFunction::new(parent_cancels_child_wf);
|
|
104
104
|
let t = canned_histories::single_child_workflow_cancelled("child-id-1");
|
|
105
|
-
let mut
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
let mut worker = build_fake_sdk(MockPollCfg::from_resps(t, [ResponseType::AllHistory]));
|
|
106
|
+
worker.register_wf(DEFAULT_WORKFLOW_TYPE, parent_cancels_child_wf);
|
|
107
|
+
worker.run().await.unwrap();
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
#[rstest::rstest]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
use crate::{
|
|
2
2
|
test_help::{
|
|
3
3
|
build_mock_pollers, canned_histories, hist_to_poll_resp, mock_worker, single_hist_mock_sg,
|
|
4
|
-
MockPollCfg, ResponseType,
|
|
4
|
+
MockPollCfg, ResponseType, WorkerExt,
|
|
5
5
|
},
|
|
6
6
|
worker::{client::mocks::mock_workflow_client, LEGACY_QUERY_ID},
|
|
7
7
|
};
|
|
@@ -850,3 +850,44 @@ async fn legacy_query_combined_with_timer_fire_repro() {
|
|
|
850
850
|
.unwrap();
|
|
851
851
|
core.shutdown().await;
|
|
852
852
|
}
|
|
853
|
+
|
|
854
|
+
#[tokio::test]
|
|
855
|
+
async fn build_id_set_properly_on_query_on_first_task() {
|
|
856
|
+
let wfid = "fake_wf_id";
|
|
857
|
+
let mut t = TestHistoryBuilder::default();
|
|
858
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
859
|
+
t.add_workflow_task_scheduled_and_started();
|
|
860
|
+
let tasks = VecDeque::from(vec![{
|
|
861
|
+
let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::AllHistory);
|
|
862
|
+
pr.queries.insert(
|
|
863
|
+
"q".to_string(),
|
|
864
|
+
WorkflowQuery {
|
|
865
|
+
query_type: "query-type".to_string(),
|
|
866
|
+
query_args: Some(b"hi".into()),
|
|
867
|
+
header: None,
|
|
868
|
+
},
|
|
869
|
+
);
|
|
870
|
+
pr
|
|
871
|
+
}]);
|
|
872
|
+
let mut mock_client = mock_workflow_client();
|
|
873
|
+
mock_client.expect_respond_legacy_query().times(0);
|
|
874
|
+
let mh = MockPollCfg::from_resp_batches(wfid, t, tasks, mock_workflow_client());
|
|
875
|
+
let mut mock = build_mock_pollers(mh);
|
|
876
|
+
mock.worker_cfg(|wc| {
|
|
877
|
+
wc.max_cached_workflows = 10;
|
|
878
|
+
wc.worker_build_id = "1.0".to_string();
|
|
879
|
+
});
|
|
880
|
+
let core = mock_worker(mock);
|
|
881
|
+
|
|
882
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
883
|
+
assert_eq!(task.build_id_for_current_task, "1.0");
|
|
884
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::empty(task.run_id))
|
|
885
|
+
.await
|
|
886
|
+
.unwrap();
|
|
887
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
888
|
+
assert_eq!(task.build_id_for_current_task, "1.0");
|
|
889
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::empty(task.run_id))
|
|
890
|
+
.await
|
|
891
|
+
.unwrap();
|
|
892
|
+
core.drain_pollers_and_shutdown().await;
|
|
893
|
+
}
|
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
use crate::{
|
|
2
2
|
test_help::{
|
|
3
|
-
build_mock_pollers, canned_histories, hist_to_poll_resp, mock_worker,
|
|
4
|
-
ResponseType,
|
|
3
|
+
build_fake_sdk, build_mock_pollers, canned_histories, hist_to_poll_resp, mock_worker,
|
|
4
|
+
MockPollCfg, ResponseType,
|
|
5
5
|
},
|
|
6
|
-
worker::{client::mocks::mock_workflow_client,
|
|
6
|
+
worker::{client::mocks::mock_workflow_client, LEGACY_QUERY_ID},
|
|
7
7
|
};
|
|
8
8
|
use rstest::{fixture, rstest};
|
|
9
9
|
use std::{collections::VecDeque, time::Duration};
|
|
10
|
-
use temporal_sdk::{WfContext, WorkflowFunction};
|
|
11
|
-
use temporal_sdk_core_api::Worker;
|
|
10
|
+
use temporal_sdk::{WfContext, Worker, WorkflowFunction};
|
|
11
|
+
use temporal_sdk_core_api::Worker as CoreWorker;
|
|
12
12
|
use temporal_sdk_core_protos::{
|
|
13
13
|
coresdk::{
|
|
14
14
|
workflow_activation::{workflow_activation_job, WorkflowActivationJob},
|
|
15
15
|
workflow_completion::WorkflowActivationCompletion,
|
|
16
16
|
},
|
|
17
|
-
temporal::api::{
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
temporal::api::{enums::v1::EventType, query::v1::WorkflowQuery},
|
|
18
|
+
TestHistoryBuilder, DEFAULT_WORKFLOW_TYPE,
|
|
19
|
+
};
|
|
20
|
+
use temporal_sdk_core_test_utils::{
|
|
21
|
+
interceptors::ActivationAssertionsInterceptor, query_ok, start_timer_cmd,
|
|
22
22
|
};
|
|
23
|
-
use temporal_sdk_core_test_utils::{query_ok, start_timer_cmd};
|
|
24
23
|
|
|
25
24
|
fn timers_wf(num_timers: u32) -> WorkflowFunction {
|
|
26
25
|
WorkflowFunction::new(move |command_sink: WfContext| async move {
|
|
@@ -32,38 +31,31 @@ fn timers_wf(num_timers: u32) -> WorkflowFunction {
|
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
#[fixture(num_timers = 1)]
|
|
35
|
-
fn fire_happy_hist(num_timers: u32) ->
|
|
34
|
+
fn fire_happy_hist(num_timers: u32) -> Worker {
|
|
36
35
|
let func = timers_wf(num_timers);
|
|
37
36
|
// Add 1 b/c history takes # wf tasks, not timers
|
|
38
37
|
let t = canned_histories::long_sequential_timers(num_timers as usize);
|
|
39
|
-
|
|
38
|
+
let mut worker = build_fake_sdk(MockPollCfg::from_resps(t, [ResponseType::AllHistory]));
|
|
39
|
+
worker.register_wf(DEFAULT_WORKFLOW_TYPE, func);
|
|
40
|
+
worker
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
#[rstest]
|
|
43
44
|
#[case::one_timer(fire_happy_hist(1), 1)]
|
|
44
45
|
#[case::five_timers(fire_happy_hist(5), 5)]
|
|
45
46
|
#[tokio::test]
|
|
46
|
-
async fn replay_flag_is_correct(#[case] mut
|
|
47
|
+
async fn replay_flag_is_correct(#[case] mut worker: Worker, #[case] num_timers: usize) {
|
|
47
48
|
// Verify replay flag is correct by constructing a workflow manager that already has a complete
|
|
48
49
|
// history fed into it. It should always be replaying, because history is complete.
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
assert_eq!(commands.len(), 1);
|
|
55
|
-
assert_eq!(commands[0].command_type, CommandType::StartTimer as i32);
|
|
51
|
+
let mut aai = ActivationAssertionsInterceptor::default();
|
|
52
|
+
|
|
53
|
+
for _ in 1..=num_timers + 1 {
|
|
54
|
+
aai.then(|a| assert!(a.is_replaying));
|
|
56
55
|
}
|
|
57
56
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
let commands = wfm.get_server_commands().commands;
|
|
61
|
-
assert_eq!(commands.len(), 1);
|
|
62
|
-
assert_eq!(
|
|
63
|
-
commands[0].command_type,
|
|
64
|
-
CommandType::CompleteWorkflowExecution as i32
|
|
65
|
-
);
|
|
66
|
-
wfm.shutdown().await.unwrap();
|
|
57
|
+
worker.set_worker_interceptor(aai);
|
|
58
|
+
worker.run().await.unwrap();
|
|
67
59
|
}
|
|
68
60
|
|
|
69
61
|
#[tokio::test(flavor = "multi_thread")]
|
|
@@ -71,15 +63,14 @@ async fn replay_flag_is_correct_partial_history() {
|
|
|
71
63
|
let func = timers_wf(1);
|
|
72
64
|
// Add 1 b/c history takes # wf tasks, not timers
|
|
73
65
|
let t = canned_histories::long_sequential_timers(2);
|
|
74
|
-
let mut
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
let
|
|
78
|
-
assert!(!
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
wfm.shutdown().await.unwrap();
|
|
66
|
+
let mut worker = build_fake_sdk(MockPollCfg::from_resps(t, [1]));
|
|
67
|
+
worker.register_wf(DEFAULT_WORKFLOW_TYPE, func);
|
|
68
|
+
|
|
69
|
+
let mut aai = ActivationAssertionsInterceptor::default();
|
|
70
|
+
aai.then(|a| assert!(!a.is_replaying));
|
|
71
|
+
|
|
72
|
+
worker.set_worker_interceptor(aai);
|
|
73
|
+
worker.run().await.unwrap();
|
|
83
74
|
}
|
|
84
75
|
|
|
85
76
|
#[tokio::test]
|
|
@@ -99,7 +90,6 @@ async fn replay_flag_correct_with_query() {
|
|
|
99
90
|
let h = pr.history.as_mut().unwrap();
|
|
100
91
|
h.events.truncate(5);
|
|
101
92
|
pr.started_event_id = 3;
|
|
102
|
-
dbg!(&pr.resp);
|
|
103
93
|
pr
|
|
104
94
|
},
|
|
105
95
|
hist_to_poll_resp(&t, wfid.to_owned(), 2.into()),
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
use crate::test_help::{build_mock_pollers, mock_worker, MockPollCfg, ResponseType};
|
|
2
|
+
use temporal_sdk_core_api::Worker;
|
|
3
|
+
use temporal_sdk_core_protos::{
|
|
4
|
+
coresdk::{
|
|
5
|
+
workflow_activation::{workflow_activation_job, WorkflowActivationJob},
|
|
6
|
+
workflow_commands::{update_response::Response, CompleteWorkflowExecution, UpdateResponse},
|
|
7
|
+
workflow_completion::WorkflowActivationCompletion,
|
|
8
|
+
},
|
|
9
|
+
temporal::api::{common::v1::Payload, enums::v1::EventType},
|
|
10
|
+
TestHistoryBuilder,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
#[tokio::test]
|
|
14
|
+
async fn replay_with_empty_first_task() {
|
|
15
|
+
let mut t = TestHistoryBuilder::default();
|
|
16
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
17
|
+
t.add_full_wf_task();
|
|
18
|
+
t.add_full_wf_task();
|
|
19
|
+
let accept_id = t.add_update_accepted("upd1", "update");
|
|
20
|
+
t.add_we_signaled("hi", vec![]);
|
|
21
|
+
t.add_full_wf_task();
|
|
22
|
+
t.add_update_completed(accept_id);
|
|
23
|
+
t.add_workflow_execution_completed();
|
|
24
|
+
|
|
25
|
+
let mock = MockPollCfg::from_resps(t, [ResponseType::AllHistory]);
|
|
26
|
+
let mut mock = build_mock_pollers(mock);
|
|
27
|
+
mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
|
|
28
|
+
let core = mock_worker(mock);
|
|
29
|
+
|
|
30
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
31
|
+
assert_matches!(
|
|
32
|
+
task.jobs.as_slice(),
|
|
33
|
+
[
|
|
34
|
+
WorkflowActivationJob {
|
|
35
|
+
variant: Some(workflow_activation_job::Variant::DoUpdate(_)),
|
|
36
|
+
},
|
|
37
|
+
WorkflowActivationJob {
|
|
38
|
+
variant: Some(workflow_activation_job::Variant::StartWorkflow(_)),
|
|
39
|
+
},
|
|
40
|
+
]
|
|
41
|
+
);
|
|
42
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
43
|
+
task.run_id,
|
|
44
|
+
UpdateResponse {
|
|
45
|
+
protocol_instance_id: "upd1".to_string(),
|
|
46
|
+
response: Some(Response::Accepted(())),
|
|
47
|
+
}
|
|
48
|
+
.into(),
|
|
49
|
+
))
|
|
50
|
+
.await
|
|
51
|
+
.unwrap();
|
|
52
|
+
|
|
53
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
54
|
+
assert_matches!(
|
|
55
|
+
task.jobs.as_slice(),
|
|
56
|
+
[WorkflowActivationJob {
|
|
57
|
+
variant: Some(workflow_activation_job::Variant::SignalWorkflow(_)),
|
|
58
|
+
}]
|
|
59
|
+
);
|
|
60
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
|
|
61
|
+
task.run_id,
|
|
62
|
+
vec![
|
|
63
|
+
UpdateResponse {
|
|
64
|
+
protocol_instance_id: "upd1".to_string(),
|
|
65
|
+
response: Some(Response::Completed(Payload::default())),
|
|
66
|
+
}
|
|
67
|
+
.into(),
|
|
68
|
+
CompleteWorkflowExecution { result: None }.into(),
|
|
69
|
+
],
|
|
70
|
+
))
|
|
71
|
+
.await
|
|
72
|
+
.unwrap();
|
|
73
|
+
}
|