@temporalio/core-bridge 0.19.2 → 0.20.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 +90 -157
- package/Cargo.toml +1 -0
- package/index.d.ts +11 -27
- package/package.json +3 -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 +1 -1
- package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
- package/sdk-core/.cargo/config.toml +1 -0
- package/sdk-core/CODEOWNERS +1 -1
- package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +119 -86
- package/sdk-core/bridge-ffi/src/lib.rs +311 -315
- package/sdk-core/bridge-ffi/src/wrappers.rs +108 -113
- package/sdk-core/client/Cargo.toml +13 -9
- package/sdk-core/client/LICENSE.txt +23 -0
- package/sdk-core/client/src/lib.rs +286 -174
- package/sdk-core/client/src/metrics.rs +86 -12
- package/sdk-core/client/src/raw.rs +566 -0
- package/sdk-core/client/src/retry.rs +137 -99
- package/sdk-core/core/Cargo.toml +15 -10
- package/sdk-core/core/LICENSE.txt +23 -0
- package/sdk-core/core/benches/workflow_replay.rs +79 -0
- package/sdk-core/core/src/abstractions.rs +38 -0
- package/sdk-core/core/src/core_tests/activity_tasks.rs +108 -182
- package/sdk-core/core/src/core_tests/child_workflows.rs +16 -11
- package/sdk-core/core/src/core_tests/determinism.rs +24 -12
- package/sdk-core/core/src/core_tests/local_activities.rs +53 -27
- package/sdk-core/core/src/core_tests/mod.rs +30 -43
- package/sdk-core/core/src/core_tests/queries.rs +82 -81
- package/sdk-core/core/src/core_tests/workers.rs +111 -296
- package/sdk-core/core/src/core_tests/workflow_cancels.rs +4 -4
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +213 -241
- package/sdk-core/core/src/lib.rs +73 -318
- package/sdk-core/core/src/pollers/mod.rs +4 -6
- package/sdk-core/core/src/pollers/poll_buffer.rs +20 -14
- package/sdk-core/core/src/protosext/mod.rs +7 -10
- package/sdk-core/core/src/replay/mod.rs +11 -150
- package/sdk-core/core/src/telemetry/metrics.rs +35 -2
- package/sdk-core/core/src/telemetry/mod.rs +49 -16
- package/sdk-core/core/src/telemetry/prometheus_server.rs +14 -35
- package/sdk-core/core/src/test_help/mod.rs +104 -170
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +57 -34
- package/sdk-core/core/src/worker/activities/local_activities.rs +37 -17
- package/sdk-core/core/src/worker/activities.rs +23 -16
- package/sdk-core/core/src/worker/client/mocks.rs +86 -0
- package/sdk-core/core/src/worker/client.rs +209 -0
- package/sdk-core/core/src/worker/mod.rs +193 -105
- package/sdk-core/core/src/workflow/driven_workflow.rs +21 -6
- package/sdk-core/core/src/workflow/history_update.rs +107 -24
- package/sdk-core/core/src/workflow/machines/activity_state_machine.rs +2 -3
- package/sdk-core/core/src/workflow/machines/child_workflow_state_machine.rs +2 -3
- package/sdk-core/core/src/workflow/machines/mod.rs +20 -17
- package/sdk-core/core/src/workflow/machines/signal_external_state_machine.rs +56 -19
- package/sdk-core/core/src/workflow/machines/transition_coverage.rs +5 -0
- package/sdk-core/core/src/workflow/machines/upsert_search_attributes_state_machine.rs +230 -22
- package/sdk-core/core/src/workflow/machines/workflow_machines.rs +81 -115
- package/sdk-core/core/src/workflow/machines/workflow_task_state_machine.rs +4 -4
- package/sdk-core/core/src/workflow/mod.rs +13 -1
- package/sdk-core/core/src/workflow/workflow_tasks/mod.rs +43 -33
- package/sdk-core/core-api/Cargo.toml +9 -1
- package/sdk-core/core-api/LICENSE.txt +23 -0
- package/sdk-core/core-api/src/errors.rs +7 -38
- package/sdk-core/core-api/src/lib.rs +44 -52
- package/sdk-core/core-api/src/worker.rs +10 -2
- package/sdk-core/etc/deps.svg +127 -96
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +11 -7
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +10 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +6 -1
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +6 -0
- package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +6 -0
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +2 -1
- package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +3 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +12 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +25 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +4 -0
- package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +19 -35
- package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +2 -6
- package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +53 -11
- package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +14 -7
- package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +3 -5
- package/sdk-core/sdk/Cargo.toml +16 -2
- package/sdk-core/sdk/LICENSE.txt +23 -0
- package/sdk-core/sdk/src/interceptors.rs +11 -0
- package/sdk-core/sdk/src/lib.rs +138 -150
- package/sdk-core/sdk/src/workflow_context/options.rs +86 -1
- package/sdk-core/sdk/src/workflow_context.rs +36 -17
- package/sdk-core/sdk/src/workflow_future.rs +19 -25
- package/sdk-core/sdk-core-protos/Cargo.toml +1 -1
- package/sdk-core/sdk-core-protos/build.rs +1 -0
- package/sdk-core/sdk-core-protos/src/history_info.rs +17 -4
- package/sdk-core/sdk-core-protos/src/lib.rs +251 -47
- package/sdk-core/test-utils/Cargo.toml +3 -1
- package/sdk-core/test-utils/src/canned_histories.rs +27 -0
- package/sdk-core/test-utils/src/histfetch.rs +3 -3
- package/sdk-core/test-utils/src/lib.rs +223 -68
- package/sdk-core/tests/integ_tests/client_tests.rs +27 -4
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +93 -14
- package/sdk-core/tests/integ_tests/polling_tests.rs +18 -12
- package/sdk-core/tests/integ_tests/queries_tests.rs +50 -53
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +117 -103
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +8 -1
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +10 -5
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +7 -1
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +8 -3
- package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +7 -1
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +76 -15
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +19 -3
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +39 -42
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +84 -0
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +30 -8
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +21 -6
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +26 -16
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +66 -0
- package/sdk-core/tests/integ_tests/workflow_tests.rs +78 -74
- package/sdk-core/tests/load_tests.rs +9 -6
- package/sdk-core/tests/main.rs +43 -10
- package/src/conversions.rs +7 -12
- package/src/lib.rs +322 -357
- package/sdk-core/client/src/mocks.rs +0 -167
- package/sdk-core/core/src/worker/dispatcher.rs +0 -171
- package/sdk-core/protos/local/temporal/sdk/core/bridge/service.proto +0 -61
|
@@ -15,7 +15,7 @@ use crate::{
|
|
|
15
15
|
worker::{LocalActRequest, LocalActivityResolution},
|
|
16
16
|
};
|
|
17
17
|
use machines::WorkflowMachines;
|
|
18
|
-
use std::{result, sync::mpsc::Sender};
|
|
18
|
+
use std::{result, sync::mpsc::Sender, time::Duration};
|
|
19
19
|
use temporal_sdk_core_protos::{
|
|
20
20
|
coresdk::{workflow_activation::WorkflowActivation, workflow_commands::*},
|
|
21
21
|
temporal::api::command::v1::Command as ProtoCommand,
|
|
@@ -213,6 +213,7 @@ pub enum WFCommand {
|
|
|
213
213
|
RequestCancelExternalWorkflow(RequestCancelExternalWorkflowExecution),
|
|
214
214
|
SignalExternalWorkflow(SignalExternalWorkflowExecution),
|
|
215
215
|
CancelSignalWorkflow(CancelSignalWorkflow),
|
|
216
|
+
UpsertSearchAttributes(UpsertWorkflowSearchAttributes),
|
|
216
217
|
}
|
|
217
218
|
|
|
218
219
|
impl TryFrom<WorkflowCommand> for WFCommand {
|
|
@@ -253,6 +254,9 @@ impl TryFrom<WorkflowCommand> for WFCommand {
|
|
|
253
254
|
workflow_command::Variant::RequestCancelLocalActivity(s) => {
|
|
254
255
|
Ok(Self::RequestCancelLocalActivity(s))
|
|
255
256
|
}
|
|
257
|
+
workflow_command::Variant::UpsertWorkflowSearchAttributesCommandAttributes(s) => {
|
|
258
|
+
Ok(Self::UpsertSearchAttributes(s))
|
|
259
|
+
}
|
|
256
260
|
}
|
|
257
261
|
}
|
|
258
262
|
}
|
|
@@ -267,6 +271,14 @@ enum CommandID {
|
|
|
267
271
|
CancelExternal(u32),
|
|
268
272
|
}
|
|
269
273
|
|
|
274
|
+
/// Details remembered from the workflow execution started event that we may need to recall later.
|
|
275
|
+
/// Is a subset of `WorkflowExecutionStartedEventAttributes`, but avoids holding on to huge fields.
|
|
276
|
+
#[derive(Debug, Clone)]
|
|
277
|
+
pub struct WorkflowStartedInfo {
|
|
278
|
+
workflow_task_timeout: Option<Duration>,
|
|
279
|
+
workflow_execution_timeout: Option<Duration>,
|
|
280
|
+
}
|
|
281
|
+
|
|
270
282
|
#[cfg(test)]
|
|
271
283
|
pub mod managed_wf {
|
|
272
284
|
use super::*;
|
|
@@ -7,8 +7,9 @@ use crate::{
|
|
|
7
7
|
pending_activations::PendingActivations,
|
|
8
8
|
protosext::{ValidPollWFTQResponse, WorkflowActivationExt},
|
|
9
9
|
telemetry::metrics::MetricsContext,
|
|
10
|
-
worker::{LocalActRequest, LocalActivityResolution},
|
|
10
|
+
worker::{client::WorkerClientBag, LocalActRequest, LocalActivityResolution},
|
|
11
11
|
workflow::{
|
|
12
|
+
history_update::NextPageToken,
|
|
12
13
|
machines::WFMachinesError,
|
|
13
14
|
workflow_tasks::{
|
|
14
15
|
cache_manager::WorkflowCacheManager, concurrency_manager::WorkflowConcurrencyManager,
|
|
@@ -26,15 +27,13 @@ use std::{
|
|
|
26
27
|
sync::Arc,
|
|
27
28
|
time::{Duration, Instant},
|
|
28
29
|
};
|
|
29
|
-
use temporal_client::ServerGatewayApis;
|
|
30
30
|
use temporal_sdk_core_protos::{
|
|
31
31
|
coresdk::{
|
|
32
32
|
workflow_activation::{
|
|
33
|
-
create_query_activation, remove_from_cache::EvictionReason,
|
|
34
|
-
QueryWorkflow, WorkflowActivation,
|
|
33
|
+
create_query_activation, query_to_job, remove_from_cache::EvictionReason,
|
|
34
|
+
workflow_activation_job, QueryWorkflow, WorkflowActivation,
|
|
35
35
|
},
|
|
36
36
|
workflow_commands::QueryResult,
|
|
37
|
-
FromPayloadsExt,
|
|
38
37
|
},
|
|
39
38
|
temporal::api::command::v1::Command as ProtoCommand,
|
|
40
39
|
TaskToken,
|
|
@@ -120,8 +119,6 @@ pub(crate) enum NewWfTaskOutcome {
|
|
|
120
119
|
/// The workflow task should be auto-completed with an empty command list, as it must be replied
|
|
121
120
|
/// to but there is no meaningful work for lang to do.
|
|
122
121
|
Autocomplete,
|
|
123
|
-
/// Workflow task had partial history and workflow was not present in the cache.
|
|
124
|
-
CacheMiss,
|
|
125
122
|
/// The workflow task ran into problems while being applied and we must now evict the workflow
|
|
126
123
|
Evict(WorkflowUpdateError),
|
|
127
124
|
/// No action should be taken. Possibly we are waiting for local activities to complete
|
|
@@ -298,7 +295,7 @@ impl WorkflowTaskManager {
|
|
|
298
295
|
pub(crate) async fn apply_new_poll_resp(
|
|
299
296
|
&self,
|
|
300
297
|
work: ValidPollWFTQResponse,
|
|
301
|
-
|
|
298
|
+
client: Arc<WorkerClientBag>,
|
|
302
299
|
) -> NewWfTaskOutcome {
|
|
303
300
|
let mut work = if let Some(w) = self.workflow_machines.buffer_resp_if_outstanding_work(work)
|
|
304
301
|
{
|
|
@@ -311,25 +308,22 @@ impl WorkflowTaskManager {
|
|
|
311
308
|
task_token = %&work.task_token,
|
|
312
309
|
history_length = %work.history.events.len(),
|
|
313
310
|
attempt = %work.attempt,
|
|
311
|
+
run_id = %work.workflow_execution.run_id,
|
|
314
312
|
"Applying new workflow task from server"
|
|
315
313
|
);
|
|
316
314
|
let task_start_time = Instant::now();
|
|
317
315
|
|
|
318
316
|
// Check if there is a legacy query we either need to immediately issue an activation for
|
|
319
317
|
// (if there is no more replay work to do) or we need to store for later answering.
|
|
320
|
-
let legacy_query = work
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
});
|
|
318
|
+
let legacy_query = work
|
|
319
|
+
.legacy_query
|
|
320
|
+
.take()
|
|
321
|
+
.map(|q| query_to_job(LEGACY_QUERY_ID.to_string(), q));
|
|
325
322
|
|
|
326
323
|
let (info, mut next_activation) =
|
|
327
|
-
match self.instantiate_or_update_workflow(work,
|
|
324
|
+
match self.instantiate_or_update_workflow(work, client).await {
|
|
328
325
|
Ok((info, next_activation)) => (info, next_activation),
|
|
329
326
|
Err(e) => {
|
|
330
|
-
if let WFMachinesError::CacheMiss = e.source {
|
|
331
|
-
return NewWfTaskOutcome::CacheMiss;
|
|
332
|
-
}
|
|
333
327
|
return NewWfTaskOutcome::Evict(e);
|
|
334
328
|
}
|
|
335
329
|
};
|
|
@@ -337,7 +331,7 @@ impl WorkflowTaskManager {
|
|
|
337
331
|
// Immediately dispatch query activation if no other jobs
|
|
338
332
|
let legacy_query = if next_activation.jobs.is_empty() {
|
|
339
333
|
if let Some(lq) = legacy_query {
|
|
340
|
-
debug!("Dispatching legacy query {
|
|
334
|
+
debug!("Dispatching legacy query {}", &lq);
|
|
341
335
|
next_activation
|
|
342
336
|
.jobs
|
|
343
337
|
.push(workflow_activation_job::Variant::QueryWorkflow(lq).into());
|
|
@@ -467,9 +461,8 @@ impl WorkflowTaskManager {
|
|
|
467
461
|
|
|
468
462
|
let wft_timeout: Duration = wfm
|
|
469
463
|
.machines
|
|
470
|
-
.
|
|
471
|
-
.and_then(|attrs| attrs.workflow_task_timeout
|
|
472
|
-
.and_then(|tt| tt.try_into().ok())
|
|
464
|
+
.get_started_info()
|
|
465
|
+
.and_then(|attrs| attrs.workflow_task_timeout)
|
|
473
466
|
.ok_or_else(|| {
|
|
474
467
|
WFMachinesError::Fatal(
|
|
475
468
|
"Workflow's start attribs were missing a well formed task timeout"
|
|
@@ -584,7 +577,7 @@ impl WorkflowTaskManager {
|
|
|
584
577
|
async fn instantiate_or_update_workflow(
|
|
585
578
|
&self,
|
|
586
579
|
poll_wf_resp: ValidPollWFTQResponse,
|
|
587
|
-
|
|
580
|
+
client: Arc<WorkerClientBag>,
|
|
588
581
|
) -> Result<(WorkflowTaskInfo, WorkflowActivation), WorkflowUpdateError> {
|
|
589
582
|
let run_id = poll_wf_resp.workflow_execution.run_id.clone();
|
|
590
583
|
|
|
@@ -593,22 +586,39 @@ impl WorkflowTaskManager {
|
|
|
593
586
|
task_token: poll_wf_resp.task_token,
|
|
594
587
|
};
|
|
595
588
|
|
|
589
|
+
let poll_resp_is_incremental = poll_wf_resp
|
|
590
|
+
.history
|
|
591
|
+
.events
|
|
592
|
+
.get(0)
|
|
593
|
+
.map(|ev| ev.event_id > 1)
|
|
594
|
+
.unwrap_or_default();
|
|
595
|
+
|
|
596
|
+
let page_token = if !self.workflow_machines.exists(&run_id) && poll_resp_is_incremental {
|
|
597
|
+
debug!(run_id=?run_id, "Workflow task has partial history, but workflow is not in \
|
|
598
|
+
cache. Will fetch history");
|
|
599
|
+
self.metrics.sticky_cache_miss();
|
|
600
|
+
NextPageToken::FetchFromStart
|
|
601
|
+
} else {
|
|
602
|
+
poll_wf_resp.next_page_token.into()
|
|
603
|
+
};
|
|
604
|
+
let history_update = HistoryUpdate::new(
|
|
605
|
+
HistoryPaginator::new(
|
|
606
|
+
poll_wf_resp.history,
|
|
607
|
+
poll_wf_resp.workflow_execution.workflow_id.clone(),
|
|
608
|
+
poll_wf_resp.workflow_execution.run_id,
|
|
609
|
+
page_token,
|
|
610
|
+
client.clone(),
|
|
611
|
+
),
|
|
612
|
+
poll_wf_resp.previous_started_event_id,
|
|
613
|
+
);
|
|
614
|
+
|
|
596
615
|
match self
|
|
597
616
|
.workflow_machines
|
|
598
617
|
.create_or_update(
|
|
599
618
|
&run_id,
|
|
600
|
-
|
|
601
|
-
HistoryPaginator::new(
|
|
602
|
-
poll_wf_resp.history,
|
|
603
|
-
poll_wf_resp.workflow_execution.workflow_id.clone(),
|
|
604
|
-
poll_wf_resp.workflow_execution.run_id.clone(),
|
|
605
|
-
poll_wf_resp.next_page_token,
|
|
606
|
-
gateway.clone(),
|
|
607
|
-
),
|
|
608
|
-
poll_wf_resp.previous_started_event_id,
|
|
609
|
-
),
|
|
619
|
+
history_update,
|
|
610
620
|
&poll_wf_resp.workflow_execution.workflow_id,
|
|
611
|
-
|
|
621
|
+
client.namespace(),
|
|
612
622
|
&poll_wf_resp.workflow_type,
|
|
613
623
|
&self.metrics,
|
|
614
624
|
)
|
|
@@ -2,14 +2,22 @@
|
|
|
2
2
|
name = "temporal-sdk-core-api"
|
|
3
3
|
version = "0.1.0"
|
|
4
4
|
edition = "2021"
|
|
5
|
+
authors = ["Spencer Judge <spencer@temporal.io>"]
|
|
6
|
+
license-file = "LICENSE.txt"
|
|
7
|
+
description = "Interface definitions for the Temporal Core SDK"
|
|
8
|
+
homepage = "https://temporal.io/"
|
|
9
|
+
repository = "https://github.com/temporalio/sdk-core"
|
|
10
|
+
keywords = ["temporal", "workflow"]
|
|
11
|
+
categories = ["development-tools"]
|
|
5
12
|
|
|
6
13
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
7
14
|
|
|
8
15
|
[dependencies]
|
|
9
16
|
anyhow = "1.0"
|
|
10
17
|
async-trait = "0.1"
|
|
11
|
-
derive_builder = "0.
|
|
18
|
+
derive_builder = "0.11"
|
|
12
19
|
log = "0.4"
|
|
20
|
+
opentelemetry = "0.17"
|
|
13
21
|
prost-types = "0.9"
|
|
14
22
|
thiserror = "1.0"
|
|
15
23
|
tonic = "0.6"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Temporal Core SDK
|
|
2
|
+
|
|
3
|
+
The MIT License
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2021 Temporal Technologies, Inc. All Rights Reserved
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
in the Software without restriction, including without limitation the rights
|
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
furnished to do so, subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
SOFTWARE.
|
|
@@ -1,29 +1,17 @@
|
|
|
1
1
|
//! Error types exposed by public APIs
|
|
2
2
|
|
|
3
3
|
use prost_types::TimestampOutOfSystemRangeError;
|
|
4
|
-
use temporal_client::GatewayInitError;
|
|
5
4
|
use temporal_sdk_core_protos::coresdk::{
|
|
6
5
|
activity_result::ActivityExecutionResult,
|
|
7
6
|
workflow_activation::remove_from_cache::EvictionReason,
|
|
8
7
|
workflow_completion::WorkflowActivationCompletion,
|
|
9
8
|
};
|
|
10
9
|
|
|
11
|
-
/// Errors thrown
|
|
12
|
-
#[derive(thiserror::Error, Debug)]
|
|
13
|
-
pub enum CoreInitError {
|
|
14
|
-
/// Server connection error. Crashing and restarting the worker is likely best.
|
|
15
|
-
#[error("Server connection error: {0:?}")]
|
|
16
|
-
GatewayInitError(#[from] GatewayInitError),
|
|
17
|
-
/// There was a problem initializing telemetry
|
|
18
|
-
#[error("Telemetry initialization error: {0:?}")]
|
|
19
|
-
TelemetryInitError(anyhow::Error),
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/// Errors thrown by [crate::Core::poll_workflow_activation]
|
|
10
|
+
/// Errors thrown by [crate::Worker::poll_workflow_activation]
|
|
23
11
|
#[derive(thiserror::Error, Debug)]
|
|
24
12
|
pub enum PollWfError {
|
|
25
|
-
/// [crate::
|
|
26
|
-
/// must call [crate::
|
|
13
|
+
/// [crate::Worker::shutdown] was called, and there are no more replay tasks to be handled. Lang
|
|
14
|
+
/// must call [crate::Worker::complete_workflow_activation] for any remaining tasks, and then may
|
|
27
15
|
/// exit.
|
|
28
16
|
#[error("Core is shut down and there are no more workflow replay tasks")]
|
|
29
17
|
ShutDown,
|
|
@@ -36,15 +24,12 @@ pub enum PollWfError {
|
|
|
36
24
|
/// even though we already cancelled it)
|
|
37
25
|
#[error("Unhandled error when auto-completing workflow task: {0:?}")]
|
|
38
26
|
AutocompleteError(#[from] CompleteWfError),
|
|
39
|
-
/// There is no worker registered for the queue being polled
|
|
40
|
-
#[error("No worker registered for queue: {0}")]
|
|
41
|
-
NoWorkerForQueue(String),
|
|
42
27
|
}
|
|
43
28
|
|
|
44
|
-
/// Errors thrown by [crate::
|
|
29
|
+
/// Errors thrown by [crate::Worker::poll_activity_task]
|
|
45
30
|
#[derive(thiserror::Error, Debug)]
|
|
46
31
|
pub enum PollActivityError {
|
|
47
|
-
/// [crate::
|
|
32
|
+
/// [crate::Worker::shutdown] was called, we will no longer fetch new activity tasks. Lang must
|
|
48
33
|
/// ensure it is finished with any workflow replay, see [PollWfError::ShutDown]
|
|
49
34
|
#[error("Core is shut down")]
|
|
50
35
|
ShutDown,
|
|
@@ -52,12 +37,9 @@ pub enum PollActivityError {
|
|
|
52
37
|
/// errors, so lang should consider this fatal.
|
|
53
38
|
#[error("Unhandled grpc error when activity polling: {0:?}")]
|
|
54
39
|
TonicError(#[from] tonic::Status),
|
|
55
|
-
/// There is no worker registered for the queue being polled
|
|
56
|
-
#[error("No worker registered for queue: {0}")]
|
|
57
|
-
NoWorkerForQueue(String),
|
|
58
40
|
}
|
|
59
41
|
|
|
60
|
-
/// Errors thrown by [crate::
|
|
42
|
+
/// Errors thrown by [crate::Worker::complete_workflow_activation]
|
|
61
43
|
#[derive(thiserror::Error, Debug)]
|
|
62
44
|
#[allow(clippy::large_enum_variant)]
|
|
63
45
|
pub enum CompleteWfError {
|
|
@@ -78,7 +60,7 @@ pub enum CompleteWfError {
|
|
|
78
60
|
TonicError(#[from] tonic::Status),
|
|
79
61
|
}
|
|
80
62
|
|
|
81
|
-
/// Errors thrown by [crate::
|
|
63
|
+
/// Errors thrown by [crate::Worker::complete_activity_task]
|
|
82
64
|
#[derive(thiserror::Error, Debug)]
|
|
83
65
|
pub enum CompleteActivityError {
|
|
84
66
|
/// Lang SDK sent us a malformed activity completion. This likely means a bug in the lang sdk.
|
|
@@ -98,14 +80,6 @@ pub enum CompleteActivityError {
|
|
|
98
80
|
NoWorkerForQueue(String),
|
|
99
81
|
}
|
|
100
82
|
|
|
101
|
-
/// Errors thrown by [crate::Core::register_worker]
|
|
102
|
-
#[derive(thiserror::Error, Debug)]
|
|
103
|
-
pub enum WorkerRegistrationError {
|
|
104
|
-
/// A worker has already been registered on this queue
|
|
105
|
-
#[error("Worker already registered for queue: {0}")]
|
|
106
|
-
WorkerAlreadyRegisteredForQueue(String),
|
|
107
|
-
}
|
|
108
|
-
|
|
109
83
|
/// Errors thrown inside of workflow machines
|
|
110
84
|
#[derive(thiserror::Error, Debug)]
|
|
111
85
|
pub enum WFMachinesError {
|
|
@@ -116,10 +90,6 @@ pub enum WFMachinesError {
|
|
|
116
90
|
|
|
117
91
|
#[error("Unrecoverable network error while fetching history: {0}")]
|
|
118
92
|
HistoryFetchingError(tonic::Status),
|
|
119
|
-
|
|
120
|
-
/// Should always be caught internally and turned into a workflow task failure
|
|
121
|
-
#[error("Unable to process partial event history because workflow is no longer cached.")]
|
|
122
|
-
CacheMiss,
|
|
123
93
|
}
|
|
124
94
|
|
|
125
95
|
impl WFMachinesError {
|
|
@@ -129,7 +99,6 @@ impl WFMachinesError {
|
|
|
129
99
|
WFMachinesError::Fatal(_) | WFMachinesError::HistoryFetchingError(_) => {
|
|
130
100
|
EvictionReason::Fatal
|
|
131
101
|
}
|
|
132
|
-
WFMachinesError::CacheMiss => EvictionReason::CacheMiss,
|
|
133
102
|
}
|
|
134
103
|
}
|
|
135
104
|
}
|
|
@@ -2,39 +2,25 @@ pub mod errors;
|
|
|
2
2
|
pub mod worker;
|
|
3
3
|
|
|
4
4
|
use crate::{
|
|
5
|
-
errors::{
|
|
6
|
-
CompleteActivityError, CompleteWfError, PollActivityError, PollWfError,
|
|
7
|
-
WorkerRegistrationError,
|
|
8
|
-
},
|
|
5
|
+
errors::{CompleteActivityError, CompleteWfError, PollActivityError, PollWfError},
|
|
9
6
|
worker::WorkerConfig,
|
|
10
7
|
};
|
|
11
8
|
use log::Level;
|
|
12
|
-
use
|
|
13
|
-
|
|
14
|
-
time::{Duration, SystemTime, UNIX_EPOCH},
|
|
15
|
-
};
|
|
16
|
-
use temporal_client::ServerGatewayApis;
|
|
9
|
+
use opentelemetry::metrics::Meter;
|
|
10
|
+
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
|
17
11
|
use temporal_sdk_core_protos::coresdk::{
|
|
18
12
|
activity_task::ActivityTask, workflow_activation::WorkflowActivation,
|
|
19
13
|
workflow_completion::WorkflowActivationCompletion, ActivityHeartbeat, ActivityTaskCompletion,
|
|
20
14
|
};
|
|
21
15
|
|
|
22
|
-
/// This trait is the primary way by which language specific SDKs interact with the core SDK.
|
|
23
|
-
///
|
|
24
|
-
///
|
|
16
|
+
/// This trait is the primary way by which language specific SDKs interact with the core SDK.
|
|
17
|
+
/// It represents one worker, which has a (potentially shared) client for connecting to the service
|
|
18
|
+
/// and is bound to a specific task queue.
|
|
25
19
|
#[async_trait::async_trait]
|
|
26
|
-
pub trait
|
|
27
|
-
///
|
|
28
|
-
///
|
|
29
|
-
///
|
|
30
|
-
fn register_worker(&self, config: WorkerConfig) -> Result<(), WorkerRegistrationError>;
|
|
31
|
-
|
|
32
|
-
/// Ask the core for some work, returning a [WorkflowActivation]. It is then the language SDK's
|
|
33
|
-
/// responsibility to call the appropriate workflow code with the provided inputs. Blocks
|
|
34
|
-
/// indefinitely until such work is available or [Core::shutdown] is called.
|
|
35
|
-
///
|
|
36
|
-
/// The returned activation is guaranteed to be for the same task queue / worker which was
|
|
37
|
-
/// provided as the `task_queue` argument.
|
|
20
|
+
pub trait Worker: Send + Sync {
|
|
21
|
+
/// Ask the worker for some work, returning a [WorkflowActivation]. It is then the language
|
|
22
|
+
/// SDK's responsibility to call the appropriate workflow code with the provided inputs. Blocks
|
|
23
|
+
/// indefinitely until such work is available or [Worker::shutdown] is called.
|
|
38
24
|
///
|
|
39
25
|
/// It is important to understand that all activations must be responded to. There can only
|
|
40
26
|
/// be one outstanding activation for a particular run of a workflow at any time. If an
|
|
@@ -48,49 +34,41 @@ pub trait Core: Send + Sync {
|
|
|
48
34
|
///
|
|
49
35
|
/// It is rarely a good idea to call poll concurrently. It handles polling the server
|
|
50
36
|
/// concurrently internally.
|
|
51
|
-
|
|
52
|
-
/// TODO: Examples
|
|
53
|
-
async fn poll_workflow_activation(
|
|
54
|
-
&self,
|
|
55
|
-
task_queue: &str,
|
|
56
|
-
) -> Result<WorkflowActivation, PollWfError>;
|
|
37
|
+
async fn poll_workflow_activation(&self) -> Result<WorkflowActivation, PollWfError>;
|
|
57
38
|
|
|
58
|
-
/// Ask the
|
|
39
|
+
/// Ask the worker for some work, returning an [ActivityTask]. It is then the language SDK's
|
|
59
40
|
/// responsibility to call the appropriate activity code with the provided inputs. Blocks
|
|
60
|
-
/// indefinitely until such work is available or [
|
|
41
|
+
/// indefinitely until such work is available or [Worker::shutdown] is called.
|
|
61
42
|
///
|
|
62
43
|
/// The returned activation is guaranteed to be for the same task queue / worker which was
|
|
63
44
|
/// provided as the `task_queue` argument.
|
|
64
45
|
///
|
|
65
46
|
/// It is rarely a good idea to call poll concurrently. It handles polling the server
|
|
66
47
|
/// concurrently internally.
|
|
67
|
-
|
|
68
|
-
/// TODO: Examples
|
|
69
|
-
async fn poll_activity_task(&self, task_queue: &str)
|
|
70
|
-
-> Result<ActivityTask, PollActivityError>;
|
|
48
|
+
async fn poll_activity_task(&self) -> Result<ActivityTask, PollActivityError>;
|
|
71
49
|
|
|
72
|
-
/// Tell the
|
|
50
|
+
/// Tell the worker that a workflow activation has completed. May be freely called concurrently.
|
|
73
51
|
async fn complete_workflow_activation(
|
|
74
52
|
&self,
|
|
75
53
|
completion: WorkflowActivationCompletion,
|
|
76
54
|
) -> Result<(), CompleteWfError>;
|
|
77
55
|
|
|
78
|
-
/// Tell the
|
|
56
|
+
/// Tell the worker that an activity has finished executing. May be freely called concurrently.
|
|
79
57
|
async fn complete_activity_task(
|
|
80
58
|
&self,
|
|
81
59
|
completion: ActivityTaskCompletion,
|
|
82
60
|
) -> Result<(), CompleteActivityError>;
|
|
83
61
|
|
|
84
|
-
/// Notify
|
|
85
|
-
/// than `activity_heartbeat_timeout` to finish must call this function in order to
|
|
86
|
-
/// progress, otherwise the activity will timeout and a new attempt will be scheduled.
|
|
62
|
+
/// Notify the Temporal service that an activity is still alive. Long running activities that
|
|
63
|
+
/// take longer than `activity_heartbeat_timeout` to finish must call this function in order to
|
|
64
|
+
/// report progress, otherwise the activity will timeout and a new attempt will be scheduled.
|
|
87
65
|
///
|
|
88
66
|
/// The first heartbeat request will be sent immediately, subsequent rapid calls to this
|
|
89
67
|
/// function will result in heartbeat requests being aggregated and the last one received during
|
|
90
68
|
/// the aggregation period will be sent to the server, where that period is defined as half the
|
|
91
69
|
/// heartbeat timeout.
|
|
92
70
|
///
|
|
93
|
-
/// Unlike
|
|
71
|
+
/// Unlike Java/Go SDKs we do not return cancellation status as part of heartbeat response and
|
|
94
72
|
/// instead send it as a separate activity task to the lang, decoupling heartbeat and
|
|
95
73
|
/// cancellation processing.
|
|
96
74
|
///
|
|
@@ -104,27 +82,36 @@ pub trait Core: Send + Sync {
|
|
|
104
82
|
|
|
105
83
|
/// Request that a workflow be evicted by its run id. This will generate a workflow activation
|
|
106
84
|
/// with the eviction job inside it to be eventually returned by
|
|
107
|
-
/// [
|
|
85
|
+
/// [Worker::poll_workflow_activation]. If the workflow had any existing outstanding activations,
|
|
108
86
|
/// such activations are invalidated and subsequent completions of them will do nothing and log
|
|
109
87
|
/// a warning.
|
|
110
|
-
fn request_workflow_eviction(&self,
|
|
88
|
+
fn request_workflow_eviction(&self, run_id: &str);
|
|
89
|
+
|
|
90
|
+
/// Return this worker's config
|
|
91
|
+
fn get_config(&self) -> &WorkerConfig;
|
|
111
92
|
|
|
112
|
-
///
|
|
113
|
-
fn
|
|
93
|
+
/// TODO: Will be replaced/fixed/whatever by shutdown refactoring
|
|
94
|
+
fn initiate_shutdown(&self);
|
|
114
95
|
|
|
115
96
|
/// Initiates async shutdown procedure, eventually ceases all polling of the server and shuts
|
|
116
|
-
/// down
|
|
97
|
+
/// down this worker. [Worker::poll_workflow_activation] should be called until it
|
|
117
98
|
/// returns [PollWfError::ShutDown] to ensure that any workflows which are still undergoing
|
|
118
99
|
/// replay have an opportunity to finish. This means that the lang sdk will need to call
|
|
119
|
-
/// [
|
|
120
|
-
/// the lang SDK can end the process, or drop the [
|
|
100
|
+
/// [Worker::complete_workflow_activation] for those workflows until they are done. At that point,
|
|
101
|
+
/// the lang SDK can end the process, or drop the [Worker] instance, which will close the
|
|
121
102
|
/// connection.
|
|
122
103
|
async fn shutdown(&self);
|
|
123
104
|
|
|
124
|
-
///
|
|
125
|
-
/// to
|
|
126
|
-
|
|
105
|
+
/// Completes shutdown and frees all resources. You should avoid simply dropping workers, as
|
|
106
|
+
/// this does not allow async tasks to report any panics that may have occurred cleanly.
|
|
107
|
+
///
|
|
108
|
+
/// This should be called only after [Worker::shutdown] has resolved.
|
|
109
|
+
async fn finalize_shutdown(self);
|
|
110
|
+
}
|
|
127
111
|
|
|
112
|
+
/// Should be backed by a process-wide singleton who is responsible for telemetry and logging
|
|
113
|
+
/// management.
|
|
114
|
+
pub trait CoreTelemetry {
|
|
128
115
|
/// Core buffers logs that should be shuttled over to lang so that they may be rendered with
|
|
129
116
|
/// the user's desired logging library. Use this function to grab the most recent buffered logs
|
|
130
117
|
/// since the last time it was called. A fixed number of such logs are retained at maximum, with
|
|
@@ -133,6 +120,11 @@ pub trait Core: Send + Sync {
|
|
|
133
120
|
/// Returns the list of logs from oldest to newest. Returns an empty vec if the feature is not
|
|
134
121
|
/// configured.
|
|
135
122
|
fn fetch_buffered_logs(&self) -> Vec<CoreLog>;
|
|
123
|
+
|
|
124
|
+
/// If metrics gathering is enabled, returns the OTel meter for core telemetry, which can be
|
|
125
|
+
/// used to create metrics instruments, or passed to things that create/record metrics (ex:
|
|
126
|
+
/// clients).
|
|
127
|
+
fn get_metric_meter(&self) -> Option<&Meter>;
|
|
136
128
|
}
|
|
137
129
|
|
|
138
130
|
/// A log line (which ultimately came from a tracing event) exported from Core->Lang
|
|
@@ -4,8 +4,9 @@ use std::time::Duration;
|
|
|
4
4
|
#[derive(Debug, Clone, derive_builder::Builder)]
|
|
5
5
|
#[builder(setter(into), build_fn(validate = "Self::validate"))]
|
|
6
6
|
#[non_exhaustive]
|
|
7
|
-
// TODO: per-second queue limits
|
|
8
7
|
pub struct WorkerConfig {
|
|
8
|
+
/// The Temporal service namespace this worker is bound to
|
|
9
|
+
pub namespace: String,
|
|
9
10
|
/// What task queue will this worker poll from? This task queue name will be used for both
|
|
10
11
|
/// workflow and activity polling.
|
|
11
12
|
pub task_queue: String,
|
|
@@ -45,7 +46,7 @@ pub struct WorkerConfig {
|
|
|
45
46
|
#[builder(default = "5")]
|
|
46
47
|
pub max_concurrent_at_polls: usize,
|
|
47
48
|
/// If set to true this worker will only handle workflow tasks and local activities, it will not
|
|
48
|
-
/// poll for activity tasks.
|
|
49
|
+
/// poll for activity tasks.
|
|
49
50
|
#[builder(default = "false")]
|
|
50
51
|
pub no_remote_activities: bool,
|
|
51
52
|
/// How long a workflow task is allowed to sit on the sticky queue before it is timed out
|
|
@@ -63,6 +64,13 @@ pub struct WorkerConfig {
|
|
|
63
64
|
/// `heartbeat_timeout * 0.8`.
|
|
64
65
|
#[builder(default = "Duration::from_secs(30)")]
|
|
65
66
|
pub default_heartbeat_throttle_interval: Duration,
|
|
67
|
+
|
|
68
|
+
/// Sets the maximum number of activities per second the task queue will dispatch, controlled
|
|
69
|
+
/// server-side. Note that this only takes effect upon an activity poll request. If multiple
|
|
70
|
+
/// workers on the same queue have different values set, they will thrash with the last poller
|
|
71
|
+
/// winning.
|
|
72
|
+
#[builder(setter(strip_option), default)]
|
|
73
|
+
pub max_task_queue_activities_per_second: Option<f64>,
|
|
66
74
|
}
|
|
67
75
|
|
|
68
76
|
impl WorkerConfig {
|