@temporalio/core-bridge 1.6.0 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +520 -456
- package/lib/index.d.ts +8 -6
- package/lib/index.js.map +1 -1
- package/package.json +8 -3
- 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/.buildkite/docker/Dockerfile +2 -2
- package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
- package/sdk-core/.buildkite/pipeline.yml +1 -1
- package/sdk-core/.github/workflows/heavy.yml +1 -0
- package/sdk-core/README.md +13 -7
- package/sdk-core/client/src/lib.rs +27 -9
- package/sdk-core/client/src/metrics.rs +17 -8
- package/sdk-core/client/src/raw.rs +3 -3
- package/sdk-core/core/Cargo.toml +3 -4
- package/sdk-core/core/src/abstractions/take_cell.rs +28 -0
- package/sdk-core/core/src/abstractions.rs +197 -18
- package/sdk-core/core/src/core_tests/activity_tasks.rs +137 -45
- package/sdk-core/core/src/core_tests/child_workflows.rs +6 -5
- package/sdk-core/core/src/core_tests/determinism.rs +212 -2
- package/sdk-core/core/src/core_tests/local_activities.rs +183 -36
- package/sdk-core/core/src/core_tests/queries.rs +32 -14
- package/sdk-core/core/src/core_tests/workers.rs +8 -5
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +340 -51
- package/sdk-core/core/src/ephemeral_server/mod.rs +110 -8
- package/sdk-core/core/src/internal_flags.rs +141 -0
- package/sdk-core/core/src/lib.rs +14 -9
- package/sdk-core/core/src/replay/mod.rs +16 -27
- package/sdk-core/core/src/telemetry/metrics.rs +69 -35
- package/sdk-core/core/src/telemetry/mod.rs +38 -14
- package/sdk-core/core/src/telemetry/prometheus_server.rs +19 -13
- package/sdk-core/core/src/test_help/mod.rs +65 -13
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +119 -160
- package/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
- package/sdk-core/core/src/worker/activities/local_activities.rs +122 -6
- package/sdk-core/core/src/worker/activities.rs +347 -173
- package/sdk-core/core/src/worker/client/mocks.rs +22 -2
- package/sdk-core/core/src/worker/client.rs +18 -2
- package/sdk-core/core/src/worker/mod.rs +137 -44
- package/sdk-core/core/src/worker/workflow/history_update.rs +132 -51
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +207 -166
- package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +6 -7
- package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +6 -7
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +157 -82
- package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +12 -12
- package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +6 -7
- package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +13 -15
- package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +170 -60
- package/sdk-core/core/src/worker/workflow/machines/mod.rs +24 -16
- package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +6 -8
- package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +320 -204
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +10 -13
- package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +15 -23
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +187 -46
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +237 -111
- package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +13 -13
- package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +10 -6
- package/sdk-core/core/src/worker/workflow/managed_run.rs +81 -62
- package/sdk-core/core/src/worker/workflow/mod.rs +341 -79
- package/sdk-core/core/src/worker/workflow/run_cache.rs +18 -11
- package/sdk-core/core/src/worker/workflow/wft_extraction.rs +15 -3
- package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +2 -0
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +75 -52
- package/sdk-core/core-api/Cargo.toml +0 -1
- package/sdk-core/core-api/src/lib.rs +13 -7
- package/sdk-core/core-api/src/telemetry.rs +4 -6
- package/sdk-core/core-api/src/worker.rs +5 -0
- package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +80 -55
- package/sdk-core/fsm/rustfsm_trait/src/lib.rs +22 -68
- package/sdk-core/histories/ends_empty_wft_complete.bin +0 -0
- package/sdk-core/histories/old_change_marker_format.bin +0 -0
- package/sdk-core/protos/api_upstream/.github/CODEOWNERS +2 -1
- package/sdk-core/protos/api_upstream/Makefile +1 -1
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +5 -17
- package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +11 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +1 -6
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +6 -6
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +5 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +22 -6
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +48 -19
- package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +2 -0
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +3 -0
- package/sdk-core/protos/api_upstream/temporal/api/{enums/v1/interaction_type.proto → protocol/v1/message.proto} +29 -11
- package/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
- package/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +111 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +59 -28
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +2 -2
- package/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +7 -8
- package/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +10 -7
- package/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +19 -30
- package/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
- package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
- package/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +8 -0
- package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +65 -60
- package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +85 -84
- package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +9 -3
- package/sdk-core/sdk/Cargo.toml +1 -1
- package/sdk-core/sdk/src/lib.rs +21 -5
- package/sdk-core/sdk/src/workflow_context/options.rs +7 -1
- package/sdk-core/sdk/src/workflow_context.rs +24 -17
- package/sdk-core/sdk/src/workflow_future.rs +9 -3
- package/sdk-core/sdk-core-protos/src/history_builder.rs +114 -89
- package/sdk-core/sdk-core-protos/src/history_info.rs +6 -1
- package/sdk-core/sdk-core-protos/src/lib.rs +205 -64
- package/sdk-core/test-utils/src/canned_histories.rs +106 -296
- package/sdk-core/test-utils/src/lib.rs +32 -5
- package/sdk-core/tests/heavy_tests.rs +10 -43
- package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +5 -3
- package/sdk-core/tests/integ_tests/metrics_tests.rs +218 -16
- package/sdk-core/tests/integ_tests/polling_tests.rs +3 -8
- package/sdk-core/tests/integ_tests/queries_tests.rs +4 -2
- package/sdk-core/tests/integ_tests/visibility_tests.rs +34 -23
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +97 -81
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +80 -3
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +5 -1
- package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +25 -3
- package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +2 -4
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +30 -0
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +64 -0
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +4 -0
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +3 -1
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +7 -2
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +6 -7
- package/sdk-core/tests/integ_tests/workflow_tests.rs +8 -8
- package/sdk-core/tests/main.rs +16 -25
- package/sdk-core/tests/runner.rs +11 -9
- package/src/conversions.rs +14 -8
- package/src/runtime.rs +9 -8
- package/ts/index.ts +8 -6
- package/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +0 -87
|
@@ -1,15 +1,33 @@
|
|
|
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
|
|
@@ -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
|
}
|
|
@@ -7,12 +7,13 @@ use temporal_sdk_core_protos::{
|
|
|
7
7
|
coresdk::workflow_commands::QueryResult,
|
|
8
8
|
temporal::api::{
|
|
9
9
|
command::v1::Command,
|
|
10
|
-
common::v1::{Payloads, WorkflowExecution},
|
|
10
|
+
common::v1::{MeteringMetadata, Payloads, WorkflowExecution},
|
|
11
11
|
enums::v1::{TaskQueueKind, WorkflowTaskFailedCause},
|
|
12
12
|
failure::v1::Failure,
|
|
13
13
|
query::v1::WorkflowQueryResult,
|
|
14
|
+
sdk::v1::WorkflowTaskCompletedMetadata,
|
|
14
15
|
taskqueue::v1::{StickyExecutionAttributes, TaskQueue, TaskQueueMetadata, VersionId},
|
|
15
|
-
workflowservice::v1
|
|
16
|
+
workflowservice::v1::{get_system_info_response::Capabilities, *},
|
|
16
17
|
},
|
|
17
18
|
TaskToken,
|
|
18
19
|
};
|
|
@@ -109,6 +110,9 @@ pub(crate) trait WorkerClient: Sync + Send {
|
|
|
109
110
|
task_token: TaskToken,
|
|
110
111
|
query_result: QueryResult,
|
|
111
112
|
) -> Result<RespondQueryTaskCompletedResponse>;
|
|
113
|
+
|
|
114
|
+
#[allow(clippy::needless_lifetimes)] // Clippy is wrong here
|
|
115
|
+
fn capabilities<'a>(&'a self) -> Option<&'a get_system_info_response::Capabilities>;
|
|
112
116
|
}
|
|
113
117
|
|
|
114
118
|
#[async_trait::async_trait]
|
|
@@ -189,6 +193,7 @@ impl WorkerClient for WorkerClientBag {
|
|
|
189
193
|
worker_versioning_id: Some(VersionId {
|
|
190
194
|
worker_build_id: self.versioning_build_id(),
|
|
191
195
|
}),
|
|
196
|
+
messages: vec![],
|
|
192
197
|
binary_checksum: self.worker_build_id.clone(),
|
|
193
198
|
query_results: request
|
|
194
199
|
.query_responses
|
|
@@ -206,6 +211,8 @@ impl WorkerClient for WorkerClientBag {
|
|
|
206
211
|
})
|
|
207
212
|
.collect(),
|
|
208
213
|
namespace: self.namespace.clone(),
|
|
214
|
+
sdk_metadata: Some(request.sdk_metadata),
|
|
215
|
+
metering_metadata: Some(request.metering_metadata),
|
|
209
216
|
};
|
|
210
217
|
Ok(self
|
|
211
218
|
.client
|
|
@@ -302,6 +309,7 @@ impl WorkerClient for WorkerClientBag {
|
|
|
302
309
|
identity: self.identity.clone(),
|
|
303
310
|
binary_checksum: self.worker_build_id.clone(),
|
|
304
311
|
namespace: self.namespace.clone(),
|
|
312
|
+
messages: vec![],
|
|
305
313
|
};
|
|
306
314
|
Ok(self
|
|
307
315
|
.client
|
|
@@ -352,6 +360,10 @@ impl WorkerClient for WorkerClientBag {
|
|
|
352
360
|
.await?
|
|
353
361
|
.into_inner())
|
|
354
362
|
}
|
|
363
|
+
|
|
364
|
+
fn capabilities(&self) -> Option<&Capabilities> {
|
|
365
|
+
self.client.get_client().inner().capabilities()
|
|
366
|
+
}
|
|
355
367
|
}
|
|
356
368
|
|
|
357
369
|
/// A version of [RespondWorkflowTaskCompletedRequest] that will finish being filled out by the
|
|
@@ -370,4 +382,8 @@ pub(crate) struct WorkflowTaskCompletion {
|
|
|
370
382
|
pub return_new_workflow_task: bool,
|
|
371
383
|
/// Force a new WFT to be created after this completion
|
|
372
384
|
pub force_create_new_workflow_task: bool,
|
|
385
|
+
/// SDK-specific metadata to send
|
|
386
|
+
pub sdk_metadata: WorkflowTaskCompletedMetadata,
|
|
387
|
+
/// Metering info
|
|
388
|
+
pub metering_metadata: MeteringMetadata,
|
|
373
389
|
}
|
|
@@ -21,9 +21,12 @@ use crate::{
|
|
|
21
21
|
WorkflowTaskPoller,
|
|
22
22
|
},
|
|
23
23
|
protosext::{validate_activity_completion, ValidPollWFTQResponse},
|
|
24
|
-
telemetry::
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
telemetry::{
|
|
25
|
+
metrics::{
|
|
26
|
+
activity_poller, local_activity_worker_type, workflow_poller, workflow_sticky_poller,
|
|
27
|
+
MetricsContext,
|
|
28
|
+
},
|
|
29
|
+
TelemetryInstance,
|
|
27
30
|
},
|
|
28
31
|
worker::{
|
|
29
32
|
activities::{DispatchOrTimeoutLA, LACompleteAction, LocalActivityManager},
|
|
@@ -34,7 +37,14 @@ use crate::{
|
|
|
34
37
|
};
|
|
35
38
|
use activities::{LocalInFlightActInfo, WorkerActivityTasks};
|
|
36
39
|
use futures::Stream;
|
|
37
|
-
use std::{
|
|
40
|
+
use std::{
|
|
41
|
+
convert::TryInto,
|
|
42
|
+
future,
|
|
43
|
+
sync::{
|
|
44
|
+
atomic::{AtomicBool, Ordering},
|
|
45
|
+
Arc,
|
|
46
|
+
},
|
|
47
|
+
};
|
|
38
48
|
use temporal_sdk_core_protos::{
|
|
39
49
|
coresdk::{
|
|
40
50
|
activity_result::activity_execution_result,
|
|
@@ -46,7 +56,7 @@ use temporal_sdk_core_protos::{
|
|
|
46
56
|
temporal::api::{
|
|
47
57
|
enums::v1::TaskQueueKind,
|
|
48
58
|
taskqueue::v1::{StickyExecutionAttributes, TaskQueue},
|
|
49
|
-
workflowservice::v1::PollActivityTaskQueueResponse,
|
|
59
|
+
workflowservice::v1::{get_system_info_response, PollActivityTaskQueueResponse},
|
|
50
60
|
},
|
|
51
61
|
TaskToken,
|
|
52
62
|
};
|
|
@@ -68,7 +78,11 @@ pub struct Worker {
|
|
|
68
78
|
shutdown_token: CancellationToken,
|
|
69
79
|
/// Will be called at the end of each activation completion
|
|
70
80
|
#[allow(clippy::type_complexity)] // Sorry clippy, there's no simple way to re-use here.
|
|
71
|
-
post_activate_hook: Option<Box<dyn Fn(&Self,
|
|
81
|
+
post_activate_hook: Option<Box<dyn Fn(&Self, PostActivateHookData) + Send + Sync>>,
|
|
82
|
+
/// Set when non-local activities are complete and should stop being polled
|
|
83
|
+
non_local_activities_complete: Arc<AtomicBool>,
|
|
84
|
+
/// Set when local activities are complete and should stop being polled
|
|
85
|
+
local_activities_complete: Arc<AtomicBool>,
|
|
72
86
|
}
|
|
73
87
|
|
|
74
88
|
#[async_trait::async_trait]
|
|
@@ -135,7 +149,13 @@ impl WorkerTrait for Worker {
|
|
|
135
149
|
self.shutdown_token.cancel();
|
|
136
150
|
// First, we want to stop polling of both activity and workflow tasks
|
|
137
151
|
if let Some(atm) = self.at_task_mgr.as_ref() {
|
|
138
|
-
atm.
|
|
152
|
+
atm.initiate_shutdown();
|
|
153
|
+
}
|
|
154
|
+
// Let the manager know that shutdown has been initiated to try to unblock the local
|
|
155
|
+
// activity poll in case this worker is an activity-only worker.
|
|
156
|
+
self.local_act_mgr.shutdown_initiated();
|
|
157
|
+
if !self.workflows.ever_polled() {
|
|
158
|
+
self.local_act_mgr.workflows_have_shutdown();
|
|
139
159
|
}
|
|
140
160
|
info!(
|
|
141
161
|
task_queue=%self.config.task_queue,
|
|
@@ -159,11 +179,17 @@ impl Worker {
|
|
|
159
179
|
config: WorkerConfig,
|
|
160
180
|
sticky_queue_name: Option<String>,
|
|
161
181
|
client: Arc<dyn WorkerClient>,
|
|
162
|
-
|
|
182
|
+
telem_instance: Option<&TelemetryInstance>,
|
|
163
183
|
) -> Self {
|
|
164
184
|
info!(task_queue=%config.task_queue,
|
|
165
185
|
namespace=%config.namespace,
|
|
166
186
|
"Initializing worker");
|
|
187
|
+
let metrics = if let Some(ti) = telem_instance {
|
|
188
|
+
MetricsContext::top_level(config.namespace.clone(), ti)
|
|
189
|
+
.with_task_q(config.task_queue.clone())
|
|
190
|
+
} else {
|
|
191
|
+
MetricsContext::no_op()
|
|
192
|
+
};
|
|
167
193
|
metrics.worker_registered();
|
|
168
194
|
|
|
169
195
|
let shutdown_token = CancellationToken::new();
|
|
@@ -226,15 +252,17 @@ impl Worker {
|
|
|
226
252
|
wft_stream,
|
|
227
253
|
act_poll_buffer,
|
|
228
254
|
metrics,
|
|
255
|
+
telem_instance,
|
|
229
256
|
shutdown_token,
|
|
230
257
|
)
|
|
231
258
|
}
|
|
232
259
|
|
|
233
260
|
#[cfg(test)]
|
|
234
261
|
pub(crate) fn new_test(config: WorkerConfig, client: impl WorkerClient + 'static) -> Self {
|
|
235
|
-
Self::new(config, None, Arc::new(client),
|
|
262
|
+
Self::new(config, None, Arc::new(client), None)
|
|
236
263
|
}
|
|
237
264
|
|
|
265
|
+
#[allow(clippy::too_many_arguments)] // Not much worth combining here
|
|
238
266
|
pub(crate) fn new_with_pollers(
|
|
239
267
|
mut config: WorkerConfig,
|
|
240
268
|
sticky_queue_name: Option<String>,
|
|
@@ -242,6 +270,7 @@ impl Worker {
|
|
|
242
270
|
wft_stream: impl Stream<Item = Result<ValidPollWFTQResponse, tonic::Status>> + Send + 'static,
|
|
243
271
|
act_poller: Option<BoxedActPoller>,
|
|
244
272
|
metrics: MetricsContext,
|
|
273
|
+
telem_instance: Option<&TelemetryInstance>,
|
|
245
274
|
shutdown_token: CancellationToken,
|
|
246
275
|
) -> Self {
|
|
247
276
|
let (hb_tx, hb_rx) = unbounded_channel();
|
|
@@ -251,7 +280,6 @@ impl Worker {
|
|
|
251
280
|
hb_tx,
|
|
252
281
|
metrics.with_new_attrs([local_activity_worker_type()]),
|
|
253
282
|
));
|
|
254
|
-
let lam_clone = local_act_mgr.clone();
|
|
255
283
|
let at_task_mgr = act_poller.map(|ap| {
|
|
256
284
|
WorkerActivityTasks::new(
|
|
257
285
|
config.max_outstanding_activities,
|
|
@@ -261,16 +289,23 @@ impl Worker {
|
|
|
261
289
|
metrics.clone(),
|
|
262
290
|
config.max_heartbeat_throttle_interval,
|
|
263
291
|
config.default_heartbeat_throttle_interval,
|
|
292
|
+
config.graceful_shutdown_period,
|
|
264
293
|
)
|
|
265
294
|
});
|
|
266
|
-
|
|
295
|
+
let poll_on_non_local_activities = at_task_mgr.is_some();
|
|
296
|
+
if !poll_on_non_local_activities {
|
|
267
297
|
info!("Activity polling is disabled for this worker");
|
|
268
|
-
}
|
|
269
|
-
let la_sink = LAReqSink::new(
|
|
298
|
+
};
|
|
299
|
+
let la_sink = LAReqSink::new(local_act_mgr.clone(), config.wf_state_inputs.clone());
|
|
270
300
|
Self {
|
|
271
301
|
wf_client: client.clone(),
|
|
272
302
|
workflows: Workflows::new(
|
|
273
|
-
build_wf_basics(
|
|
303
|
+
build_wf_basics(
|
|
304
|
+
&mut config,
|
|
305
|
+
metrics,
|
|
306
|
+
shutdown_token.child_token(),
|
|
307
|
+
client.capabilities().cloned().unwrap_or_default(),
|
|
308
|
+
),
|
|
274
309
|
sticky_queue_name.map(|sq| StickyExecutionAttributes {
|
|
275
310
|
worker_task_queue: Some(TaskQueue {
|
|
276
311
|
name: sq,
|
|
@@ -286,16 +321,21 @@ impl Worker {
|
|
|
286
321
|
client,
|
|
287
322
|
wft_stream,
|
|
288
323
|
la_sink,
|
|
324
|
+
local_act_mgr.clone(),
|
|
289
325
|
hb_rx,
|
|
290
326
|
at_task_mgr
|
|
291
327
|
.as_ref()
|
|
292
328
|
.map(|mgr| mgr.get_handle_for_workflows()),
|
|
329
|
+
telem_instance,
|
|
293
330
|
),
|
|
294
331
|
at_task_mgr,
|
|
295
332
|
local_act_mgr,
|
|
296
333
|
config,
|
|
297
334
|
shutdown_token,
|
|
298
335
|
post_activate_hook: None,
|
|
336
|
+
// Complete if there configured not to poll on non-local activities.
|
|
337
|
+
non_local_activities_complete: Arc::new(AtomicBool::new(!poll_on_non_local_activities)),
|
|
338
|
+
local_activities_complete: Default::default(),
|
|
299
339
|
}
|
|
300
340
|
}
|
|
301
341
|
|
|
@@ -303,8 +343,8 @@ impl Worker {
|
|
|
303
343
|
/// completed
|
|
304
344
|
async fn shutdown(&self) {
|
|
305
345
|
self.initiate_shutdown();
|
|
306
|
-
//
|
|
307
|
-
//
|
|
346
|
+
// We need to wait for all local activities to finish so no more workflow task heartbeats
|
|
347
|
+
// will be generated
|
|
308
348
|
self.local_act_mgr
|
|
309
349
|
.wait_all_outstanding_tasks_finished()
|
|
310
350
|
.await;
|
|
@@ -315,12 +355,13 @@ impl Worker {
|
|
|
315
355
|
.expect("Workflow processing terminates cleanly");
|
|
316
356
|
// Wait for activities to finish
|
|
317
357
|
if let Some(acts) = self.at_task_mgr.as_ref() {
|
|
318
|
-
acts.
|
|
358
|
+
acts.shutdown().await;
|
|
319
359
|
}
|
|
320
360
|
}
|
|
321
361
|
|
|
322
362
|
/// Finish shutting down by consuming the background pollers and freeing all resources
|
|
323
363
|
async fn finalize_shutdown(self) {
|
|
364
|
+
self.shutdown().await;
|
|
324
365
|
if let Some(b) = self.at_task_mgr {
|
|
325
366
|
b.shutdown().await;
|
|
326
367
|
}
|
|
@@ -360,9 +401,27 @@ impl Worker {
|
|
|
360
401
|
/// Returns `Ok(None)` in the event of a poll timeout or if the polling loop should otherwise
|
|
361
402
|
/// be restarted
|
|
362
403
|
async fn activity_poll(&self) -> Result<Option<ActivityTask>, PollActivityError> {
|
|
404
|
+
let local_activities_complete = self.local_activities_complete.load(Ordering::Relaxed);
|
|
405
|
+
let non_local_activities_complete =
|
|
406
|
+
self.non_local_activities_complete.load(Ordering::Relaxed);
|
|
407
|
+
if local_activities_complete && non_local_activities_complete {
|
|
408
|
+
return Err(PollActivityError::ShutDown);
|
|
409
|
+
}
|
|
363
410
|
let act_mgr_poll = async {
|
|
411
|
+
if non_local_activities_complete {
|
|
412
|
+
future::pending::<()>().await;
|
|
413
|
+
unreachable!()
|
|
414
|
+
}
|
|
364
415
|
if let Some(ref act_mgr) = self.at_task_mgr {
|
|
365
|
-
act_mgr.poll().await
|
|
416
|
+
let res = act_mgr.poll().await;
|
|
417
|
+
if let Err(err) = res.as_ref() {
|
|
418
|
+
if matches!(err, PollActivityError::ShutDown) {
|
|
419
|
+
self.non_local_activities_complete
|
|
420
|
+
.store(true, Ordering::Relaxed);
|
|
421
|
+
return Ok(None);
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
res.map(Some)
|
|
366
425
|
} else {
|
|
367
426
|
// We expect the local activity branch below to produce shutdown when appropriate if
|
|
368
427
|
// there are no activity pollers.
|
|
@@ -370,26 +429,35 @@ impl Worker {
|
|
|
370
429
|
unreachable!()
|
|
371
430
|
}
|
|
372
431
|
};
|
|
432
|
+
let local_activities_poll = async {
|
|
433
|
+
if local_activities_complete {
|
|
434
|
+
future::pending::<()>().await;
|
|
435
|
+
unreachable!()
|
|
436
|
+
}
|
|
437
|
+
match self.local_act_mgr.next_pending().await {
|
|
438
|
+
Some(DispatchOrTimeoutLA::Dispatch(r)) => Ok(Some(r)),
|
|
439
|
+
Some(DispatchOrTimeoutLA::Timeout {
|
|
440
|
+
run_id,
|
|
441
|
+
resolution,
|
|
442
|
+
task,
|
|
443
|
+
}) => {
|
|
444
|
+
self.notify_local_result(&run_id, LocalResolution::LocalActivity(resolution));
|
|
445
|
+
Ok(task)
|
|
446
|
+
}
|
|
447
|
+
None => {
|
|
448
|
+
if self.shutdown_token.is_cancelled() {
|
|
449
|
+
self.local_activities_complete
|
|
450
|
+
.store(true, Ordering::Relaxed);
|
|
451
|
+
}
|
|
452
|
+
Ok(None)
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
};
|
|
373
456
|
|
|
374
457
|
tokio::select! {
|
|
375
458
|
biased;
|
|
376
459
|
|
|
377
|
-
r =
|
|
378
|
-
match r {
|
|
379
|
-
Some(DispatchOrTimeoutLA::Dispatch(r)) => Ok(Some(r)),
|
|
380
|
-
Some(DispatchOrTimeoutLA::Timeout { run_id, resolution, task }) => {
|
|
381
|
-
self.notify_local_result(
|
|
382
|
-
&run_id, LocalResolution::LocalActivity(resolution));
|
|
383
|
-
Ok(task)
|
|
384
|
-
},
|
|
385
|
-
None => {
|
|
386
|
-
if self.shutdown_token.is_cancelled() {
|
|
387
|
-
return Err(PollActivityError::ShutDown);
|
|
388
|
-
}
|
|
389
|
-
Ok(None)
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
},
|
|
460
|
+
r = local_activities_poll => r,
|
|
393
461
|
r = act_mgr_poll => r,
|
|
394
462
|
}
|
|
395
463
|
}
|
|
@@ -453,6 +521,7 @@ impl Worker {
|
|
|
453
521
|
// about to happen anyway. Tell the local activity manager that, so that it can know to
|
|
454
522
|
// cancel any remaining outstanding LAs and shutdown.
|
|
455
523
|
if matches!(r, Err(PollWfError::ShutDown)) {
|
|
524
|
+
// This is covering the situation where WFT pollers dying is the reason for shutdown
|
|
456
525
|
self.initiate_shutdown();
|
|
457
526
|
self.local_act_mgr.workflows_have_shutdown();
|
|
458
527
|
}
|
|
@@ -466,11 +535,15 @@ impl Worker {
|
|
|
466
535
|
&self,
|
|
467
536
|
completion: WorkflowActivationCompletion,
|
|
468
537
|
) -> Result<(), CompleteWfError> {
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
538
|
+
self.workflows
|
|
539
|
+
.activation_completed(
|
|
540
|
+
completion,
|
|
541
|
+
false,
|
|
542
|
+
self.post_activate_hook
|
|
543
|
+
.as_ref()
|
|
544
|
+
.map(|h| |data: PostActivateHookData| h(self, data)),
|
|
545
|
+
)
|
|
546
|
+
.await?;
|
|
474
547
|
Ok(())
|
|
475
548
|
}
|
|
476
549
|
|
|
@@ -487,7 +560,7 @@ impl Worker {
|
|
|
487
560
|
/// Sets a function to be called at the end of each activation completion
|
|
488
561
|
pub(crate) fn set_post_activate_hook(
|
|
489
562
|
&mut self,
|
|
490
|
-
callback: impl Fn(&Self,
|
|
563
|
+
callback: impl Fn(&Self, PostActivateHookData) + Send + Sync + 'static,
|
|
491
564
|
) {
|
|
492
565
|
self.post_activate_hook = Some(Box::new(callback))
|
|
493
566
|
}
|
|
@@ -516,10 +589,17 @@ impl Worker {
|
|
|
516
589
|
}
|
|
517
590
|
}
|
|
518
591
|
|
|
592
|
+
pub struct PostActivateHookData<'a> {
|
|
593
|
+
pub run_id: &'a str,
|
|
594
|
+
pub most_recent_event: usize,
|
|
595
|
+
pub replaying: bool,
|
|
596
|
+
}
|
|
597
|
+
|
|
519
598
|
fn build_wf_basics(
|
|
520
599
|
config: &mut WorkerConfig,
|
|
521
600
|
metrics: MetricsContext,
|
|
522
601
|
shutdown_token: CancellationToken,
|
|
602
|
+
server_capabilities: get_system_info_response::Capabilities,
|
|
523
603
|
) -> WorkflowBasics {
|
|
524
604
|
WorkflowBasics {
|
|
525
605
|
max_cached_workflows: config.max_cached_workflows,
|
|
@@ -530,6 +610,7 @@ fn build_wf_basics(
|
|
|
530
610
|
task_queue: config.task_queue.clone(),
|
|
531
611
|
ignore_evicts_on_shutdown: config.ignore_evicts_on_shutdown,
|
|
532
612
|
fetching_concurrency: config.fetching_concurrency,
|
|
613
|
+
server_capabilities,
|
|
533
614
|
#[cfg(feature = "save_wf_inputs")]
|
|
534
615
|
wf_state_inputs: config.wf_state_inputs.take(),
|
|
535
616
|
}
|
|
@@ -538,11 +619,15 @@ fn build_wf_basics(
|
|
|
538
619
|
#[cfg(test)]
|
|
539
620
|
mod tests {
|
|
540
621
|
use super::*;
|
|
541
|
-
use crate::{
|
|
622
|
+
use crate::{
|
|
623
|
+
advance_fut, test_help::test_worker_cfg, worker::client::mocks::mock_workflow_client,
|
|
624
|
+
};
|
|
625
|
+
use futures::FutureExt;
|
|
626
|
+
|
|
542
627
|
use temporal_sdk_core_protos::temporal::api::workflowservice::v1::PollActivityTaskQueueResponse;
|
|
543
628
|
|
|
544
629
|
#[tokio::test]
|
|
545
|
-
async fn
|
|
630
|
+
async fn activity_timeouts_maintain_permit() {
|
|
546
631
|
let mut mock_client = mock_workflow_client();
|
|
547
632
|
mock_client
|
|
548
633
|
.expect_poll_activity_task()
|
|
@@ -553,8 +638,16 @@ mod tests {
|
|
|
553
638
|
.build()
|
|
554
639
|
.unwrap();
|
|
555
640
|
let worker = Worker::new_test(cfg, mock_client);
|
|
556
|
-
|
|
557
|
-
|
|
641
|
+
let fut = worker.poll_activity_task();
|
|
642
|
+
advance_fut!(fut);
|
|
643
|
+
assert_eq!(
|
|
644
|
+
worker
|
|
645
|
+
.at_task_mgr
|
|
646
|
+
.as_ref()
|
|
647
|
+
.unwrap()
|
|
648
|
+
.remaining_activity_capacity(),
|
|
649
|
+
4
|
|
650
|
+
);
|
|
558
651
|
}
|
|
559
652
|
|
|
560
653
|
#[tokio::test]
|