@temporalio/core-bridge 0.20.2 → 0.22.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 +137 -127
- package/index.d.ts +7 -2
- package/package.json +3 -3
- package/releases/aarch64-apple-darwin/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/docker-compose.yaml +5 -4
- package/sdk-core/client/Cargo.toml +1 -0
- package/sdk-core/client/src/lib.rs +52 -9
- package/sdk-core/client/src/raw.rs +9 -1
- package/sdk-core/client/src/retry.rs +12 -1
- package/sdk-core/client/src/workflow_handle/mod.rs +183 -0
- package/sdk-core/core/src/abstractions.rs +10 -3
- package/sdk-core/core/src/core_tests/child_workflows.rs +7 -9
- package/sdk-core/core/src/core_tests/determinism.rs +8 -19
- package/sdk-core/core/src/core_tests/local_activities.rs +22 -32
- package/sdk-core/core/src/core_tests/queries.rs +272 -5
- package/sdk-core/core/src/core_tests/workers.rs +4 -34
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +197 -41
- package/sdk-core/core/src/pending_activations.rs +11 -0
- package/sdk-core/core/src/telemetry/mod.rs +1 -1
- package/sdk-core/core/src/test_help/mod.rs +57 -7
- package/sdk-core/core/src/worker/mod.rs +64 -15
- package/sdk-core/core/src/workflow/machines/mod.rs +1 -1
- package/sdk-core/core/src/workflow/machines/timer_state_machine.rs +2 -2
- package/sdk-core/core/src/workflow/machines/workflow_machines.rs +14 -3
- package/sdk-core/core/src/workflow/mod.rs +5 -2
- package/sdk-core/core/src/workflow/workflow_tasks/cache_manager.rs +47 -2
- package/sdk-core/core/src/workflow/workflow_tasks/concurrency_manager.rs +16 -2
- package/sdk-core/core/src/workflow/workflow_tasks/mod.rs +252 -125
- package/sdk-core/core-api/src/worker.rs +9 -0
- package/sdk-core/sdk/Cargo.toml +1 -0
- package/sdk-core/sdk/src/activity_context.rs +223 -0
- package/sdk-core/sdk/src/interceptors.rs +8 -2
- package/sdk-core/sdk/src/lib.rs +167 -122
- package/sdk-core/sdk-core-protos/src/history_info.rs +3 -7
- package/sdk-core/test-utils/Cargo.toml +1 -0
- package/sdk-core/test-utils/src/lib.rs +78 -37
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +11 -4
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +0 -1
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +0 -3
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +33 -17
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +10 -1
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +0 -1
- package/sdk-core/tests/integ_tests/workflow_tests.rs +71 -3
- package/sdk-core/tests/load_tests.rs +80 -6
- package/src/errors.rs +9 -2
- package/src/lib.rs +39 -16
- package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
package/index.d.ts
CHANGED
|
@@ -66,9 +66,13 @@ export interface TelemetryOptions {
|
|
|
66
66
|
* Which determines what tracing data is collected in the Core SDK
|
|
67
67
|
*/
|
|
68
68
|
tracingFilter?: string;
|
|
69
|
-
/**
|
|
69
|
+
/**
|
|
70
|
+
* What level, if any, logs should be forwarded from core at
|
|
71
|
+
*
|
|
72
|
+
* @default OFF
|
|
73
|
+
*/
|
|
70
74
|
// These strings should match the log::LevelFilter enum in rust
|
|
71
|
-
logForwardingLevel
|
|
75
|
+
logForwardingLevel?: 'OFF' | LogLevel;
|
|
72
76
|
/** If set, metrics will be exposed on an http server in this process for direct scraping by
|
|
73
77
|
* prometheus. If used in conjunction with the OTel collector, metrics will *not* be exported
|
|
74
78
|
* to the collector, but traces will be.
|
|
@@ -162,6 +166,7 @@ export declare function newReplayWorker(
|
|
|
162
166
|
callback: WorkerCallback
|
|
163
167
|
): void;
|
|
164
168
|
export declare function workerShutdown(worker: Worker, callback: VoidCallback): void;
|
|
169
|
+
export declare function clientClose(client: Client): void;
|
|
165
170
|
export declare function runtimeShutdown(runtime: Runtime, callback: VoidCallback): void;
|
|
166
171
|
export declare function pollLogs(runtime: Runtime, callback: LogsCallback): void;
|
|
167
172
|
export declare function workerPollWorkflowActivation(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@temporalio/core-bridge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"description": "Temporal.io SDK Core<>Node bridge",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@opentelemetry/api": "^1.0.3",
|
|
23
|
-
"@temporalio/internal-non-workflow-common": "^0.
|
|
23
|
+
"@temporalio/internal-non-workflow-common": "^0.22.0",
|
|
24
24
|
"arg": "^5.0.1",
|
|
25
25
|
"cargo-cp-artifact": "^0.1.4",
|
|
26
26
|
"which": "^2.0.2"
|
|
@@ -43,5 +43,5 @@
|
|
|
43
43
|
"publishConfig": {
|
|
44
44
|
"access": "public"
|
|
45
45
|
},
|
|
46
|
-
"gitHead": "
|
|
46
|
+
"gitHead": "3aa1f14982bd170d21b728cbf016dc4f1b595a76"
|
|
47
47
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -9,7 +9,7 @@ services:
|
|
|
9
9
|
# - '9042:9042'
|
|
10
10
|
|
|
11
11
|
temporal:
|
|
12
|
-
image: temporalio/auto-setup:1.
|
|
12
|
+
image: temporalio/auto-setup:1.16.0
|
|
13
13
|
ports:
|
|
14
14
|
- "7233:7233"
|
|
15
15
|
- "7234:7234"
|
|
@@ -26,12 +26,13 @@ services:
|
|
|
26
26
|
- cassandra
|
|
27
27
|
|
|
28
28
|
temporal-web:
|
|
29
|
-
image: temporalio/
|
|
29
|
+
image: temporalio/ui:0.10.2
|
|
30
30
|
logging:
|
|
31
31
|
driver: none
|
|
32
32
|
ports:
|
|
33
|
-
- "
|
|
33
|
+
- "8080:8080"
|
|
34
34
|
environment:
|
|
35
|
-
-
|
|
35
|
+
- TEMPORAL_ADDRESS=temporal:7233
|
|
36
|
+
- TEMPORAL_CORS_ORIGINS=http://localhost:3000
|
|
36
37
|
depends_on:
|
|
37
38
|
- temporal
|
|
@@ -10,13 +10,17 @@ extern crate tracing;
|
|
|
10
10
|
mod metrics;
|
|
11
11
|
mod raw;
|
|
12
12
|
mod retry;
|
|
13
|
+
mod workflow_handle;
|
|
13
14
|
|
|
14
15
|
pub use crate::retry::{CallType, RetryClient};
|
|
15
16
|
pub use raw::WorkflowService;
|
|
17
|
+
pub use workflow_handle::{WorkflowExecutionInfo, WorkflowExecutionResult};
|
|
16
18
|
|
|
17
19
|
use crate::{
|
|
18
20
|
metrics::{GrpcMetricSvc, MetricsContext},
|
|
19
21
|
raw::{sealed::RawClientLike, AttachMetricLabels},
|
|
22
|
+
sealed::{RawClientLikeUser, WfHandleClient},
|
|
23
|
+
workflow_handle::UntypedWorkflowHandle,
|
|
20
24
|
};
|
|
21
25
|
use backoff::{ExponentialBackoff, SystemClock};
|
|
22
26
|
use http::uri::InvalidUri;
|
|
@@ -37,7 +41,7 @@ use temporal_sdk_core_protos::{
|
|
|
37
41
|
enums::v1::{TaskQueueKind, WorkflowTaskFailedCause},
|
|
38
42
|
failure::v1::Failure,
|
|
39
43
|
query::v1::{WorkflowQuery, WorkflowQueryResult},
|
|
40
|
-
taskqueue::v1::{StickyExecutionAttributes, TaskQueue},
|
|
44
|
+
taskqueue::v1::{StickyExecutionAttributes, TaskQueue, TaskQueueMetadata},
|
|
41
45
|
workflowservice::v1::{workflow_service_client::WorkflowServiceClient, *},
|
|
42
46
|
},
|
|
43
47
|
TaskToken,
|
|
@@ -53,8 +57,6 @@ use tower::ServiceBuilder;
|
|
|
53
57
|
use url::Url;
|
|
54
58
|
use uuid::Uuid;
|
|
55
59
|
|
|
56
|
-
use temporal_sdk_core_protos::temporal::api::taskqueue::v1::TaskQueueMetadata;
|
|
57
|
-
|
|
58
60
|
static LONG_POLL_METHOD_NAMES: [&str; 2] = ["PollWorkflowTaskQueue", "PollActivityTaskQueue"];
|
|
59
61
|
/// The server times out polls after 60 seconds. Set our timeout to be slightly beyond that.
|
|
60
62
|
const LONG_POLL_TIMEOUT: Duration = Duration::from_secs(70);
|
|
@@ -431,7 +433,7 @@ pub type WorkflowServiceClientWithMetrics = WorkflowServiceClient<InterceptedMet
|
|
|
431
433
|
type InterceptedMetricsSvc = InterceptedService<GrpcMetricSvc, ServiceCallInterceptor>;
|
|
432
434
|
|
|
433
435
|
/// Contains an instance of a namespace-bound client for interacting with the Temporal server
|
|
434
|
-
#[derive(Debug)]
|
|
436
|
+
#[derive(Debug, Clone)]
|
|
435
437
|
pub struct Client {
|
|
436
438
|
/// Client for interacting with workflow service
|
|
437
439
|
inner: ConfiguredClient<WorkflowServiceClientWithMetrics>,
|
|
@@ -475,11 +477,6 @@ impl Client {
|
|
|
475
477
|
pub fn options(&self) -> &ClientOptions {
|
|
476
478
|
&self.inner.options
|
|
477
479
|
}
|
|
478
|
-
|
|
479
|
-
/// Used to access the client as a [WorkflowService] implementor rather than the raw struct
|
|
480
|
-
fn wf_svc(&self) -> impl RawClientLike<SvcType = InterceptedMetricsSvc> {
|
|
481
|
-
self.raw_client().clone()
|
|
482
|
-
}
|
|
483
480
|
}
|
|
484
481
|
|
|
485
482
|
/// This trait provides higher-level friendlier interaction with the server.
|
|
@@ -1036,3 +1033,49 @@ impl WorkflowClientTrait for Client {
|
|
|
1036
1033
|
&self.namespace
|
|
1037
1034
|
}
|
|
1038
1035
|
}
|
|
1036
|
+
|
|
1037
|
+
mod sealed {
|
|
1038
|
+
use crate::{InterceptedMetricsSvc, RawClientLike, WorkflowClientTrait};
|
|
1039
|
+
|
|
1040
|
+
pub trait RawClientLikeUser {
|
|
1041
|
+
type RawClientT: RawClientLike<SvcType = InterceptedMetricsSvc>;
|
|
1042
|
+
/// Used to access the client as a [WorkflowService] implementor rather than the raw struct
|
|
1043
|
+
fn wf_svc(&self) -> Self::RawClientT;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
pub trait WfHandleClient: WorkflowClientTrait + RawClientLikeUser {}
|
|
1047
|
+
impl<T> WfHandleClient for T where T: WorkflowClientTrait + RawClientLikeUser {}
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
impl RawClientLikeUser for Client {
|
|
1051
|
+
type RawClientT = WorkflowServiceClientWithMetrics;
|
|
1052
|
+
|
|
1053
|
+
fn wf_svc(&self) -> Self::RawClientT {
|
|
1054
|
+
self.raw_client().clone()
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
/// Additional methods for workflow clients
|
|
1059
|
+
pub trait WfClientExt: WfHandleClient + Sized {
|
|
1060
|
+
/// Create an untyped handle for a workflow execution, which can be used to do things like
|
|
1061
|
+
/// wait for that workflow's result. `run_id` may be left blank to target the latest run.
|
|
1062
|
+
fn get_untyped_workflow_handle(
|
|
1063
|
+
&self,
|
|
1064
|
+
workflow_id: impl Into<String>,
|
|
1065
|
+
run_id: impl Into<String>,
|
|
1066
|
+
) -> UntypedWorkflowHandle<Self::RawClientT>
|
|
1067
|
+
where
|
|
1068
|
+
Self::RawClientT: Clone,
|
|
1069
|
+
{
|
|
1070
|
+
let rid = run_id.into();
|
|
1071
|
+
UntypedWorkflowHandle::new(
|
|
1072
|
+
self.wf_svc(),
|
|
1073
|
+
WorkflowExecutionInfo {
|
|
1074
|
+
namespace: self.namespace().to_string(),
|
|
1075
|
+
workflow_id: workflow_id.into(),
|
|
1076
|
+
run_id: if rid.is_empty() { None } else { Some(rid) },
|
|
1077
|
+
},
|
|
1078
|
+
)
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
impl<T> WfClientExt for T where T: WfHandleClient + Sized {}
|
|
@@ -15,7 +15,7 @@ use tonic::{body::BoxBody, client::GrpcService, metadata::KeyAndValueRef};
|
|
|
15
15
|
|
|
16
16
|
pub(super) mod sealed {
|
|
17
17
|
use super::*;
|
|
18
|
-
use crate::{ConfiguredClient, RetryClient};
|
|
18
|
+
use crate::{Client, ConfiguredClient, InterceptedMetricsSvc, RetryClient};
|
|
19
19
|
use futures::TryFutureExt;
|
|
20
20
|
use tonic::{Request, Response, Status};
|
|
21
21
|
|
|
@@ -104,6 +104,14 @@ pub(super) mod sealed {
|
|
|
104
104
|
&mut self.client
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
|
+
|
|
108
|
+
impl RawClientLike for Client {
|
|
109
|
+
type SvcType = InterceptedMetricsSvc;
|
|
110
|
+
|
|
111
|
+
fn client(&mut self) -> &mut WorkflowServiceClient<Self::SvcType> {
|
|
112
|
+
&mut self.inner
|
|
113
|
+
}
|
|
114
|
+
}
|
|
107
115
|
}
|
|
108
116
|
|
|
109
117
|
/// Helper for cloning a tonic request as long as the inner message may be cloned.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
use crate::{
|
|
2
|
-
ClientOptions, Result, RetryConfig, WorkflowClientTrait, WorkflowOptions,
|
|
2
|
+
ClientOptions, RawClientLikeUser, Result, RetryConfig, WorkflowClientTrait, WorkflowOptions,
|
|
3
3
|
WorkflowTaskCompletion,
|
|
4
4
|
};
|
|
5
5
|
use backoff::{backoff::Backoff, ExponentialBackoff};
|
|
@@ -592,3 +592,14 @@ mod tests {
|
|
|
592
592
|
}
|
|
593
593
|
}
|
|
594
594
|
}
|
|
595
|
+
|
|
596
|
+
impl<C> RawClientLikeUser for RetryClient<C>
|
|
597
|
+
where
|
|
598
|
+
C: RawClientLikeUser,
|
|
599
|
+
{
|
|
600
|
+
type RawClientT = C::RawClientT;
|
|
601
|
+
|
|
602
|
+
fn wf_svc(&self) -> Self::RawClientT {
|
|
603
|
+
self.client.wf_svc()
|
|
604
|
+
}
|
|
605
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
use crate::{InterceptedMetricsSvc, RawClientLike};
|
|
2
|
+
use anyhow::{anyhow, bail};
|
|
3
|
+
use std::marker::PhantomData;
|
|
4
|
+
use temporal_sdk_core_protos::{
|
|
5
|
+
coresdk::{common::Payload, FromPayloadsExt},
|
|
6
|
+
temporal::api::{
|
|
7
|
+
common::v1::WorkflowExecution, enums::v1::HistoryEventFilterType, failure::v1::Failure,
|
|
8
|
+
history::v1::history_event::Attributes,
|
|
9
|
+
workflowservice::v1::GetWorkflowExecutionHistoryRequest,
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/// Enumerates terminal states for a particular workflow execution
|
|
14
|
+
// TODO: Add non-proto failure types, flesh out details, etc.
|
|
15
|
+
#[derive(Debug)]
|
|
16
|
+
#[allow(clippy::large_enum_variant)]
|
|
17
|
+
pub enum WorkflowExecutionResult<T> {
|
|
18
|
+
/// The workflow finished successfully
|
|
19
|
+
Succeeded(T),
|
|
20
|
+
/// The workflow finished in failure
|
|
21
|
+
Failed(Failure),
|
|
22
|
+
/// The workflow was cancelled
|
|
23
|
+
Cancelled(Vec<Payload>),
|
|
24
|
+
/// The workflow was terminated
|
|
25
|
+
Terminated(Vec<Payload>),
|
|
26
|
+
/// The workflow timed out
|
|
27
|
+
TimedOut,
|
|
28
|
+
/// The workflow continued as new
|
|
29
|
+
ContinuedAsNew,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/// Options for fetching workflow results
|
|
33
|
+
#[derive(Debug, Clone, Copy)]
|
|
34
|
+
pub struct GetWorkflowResultOpts {
|
|
35
|
+
/// If true (the default), follows to the next workflow run in the execution chain while
|
|
36
|
+
/// retrieving results.
|
|
37
|
+
pub follow_runs: bool,
|
|
38
|
+
}
|
|
39
|
+
impl Default for GetWorkflowResultOpts {
|
|
40
|
+
fn default() -> Self {
|
|
41
|
+
Self { follow_runs: true }
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// A workflow handle which can refer to a specific workflow run, or a chain of workflow runs with
|
|
46
|
+
/// the same workflow id.
|
|
47
|
+
pub struct WorkflowHandle<ClientT, ResultT> {
|
|
48
|
+
client: ClientT,
|
|
49
|
+
info: WorkflowExecutionInfo,
|
|
50
|
+
|
|
51
|
+
_res_type: PhantomData<ResultT>,
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/// Holds needed information to refer to a specific workflow run, or workflow execution chain
|
|
55
|
+
pub struct WorkflowExecutionInfo {
|
|
56
|
+
/// Namespace the workflow lives in
|
|
57
|
+
pub namespace: String,
|
|
58
|
+
/// The workflow's id
|
|
59
|
+
pub workflow_id: String,
|
|
60
|
+
/// If set, target this specific run of the workflow
|
|
61
|
+
pub run_id: Option<String>,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
impl WorkflowExecutionInfo {
|
|
65
|
+
/// Bind the workflow info to a specific client, turning it into a workflow handle
|
|
66
|
+
pub fn bind_untyped<CT>(self, client: CT) -> UntypedWorkflowHandle<CT>
|
|
67
|
+
where
|
|
68
|
+
CT: RawClientLike<SvcType = InterceptedMetricsSvc> + Clone,
|
|
69
|
+
{
|
|
70
|
+
UntypedWorkflowHandle::new(client, self)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/// A workflow handle to a workflow with unknown types. Uses raw payloads.
|
|
75
|
+
pub type UntypedWorkflowHandle<CT> = WorkflowHandle<CT, Vec<Payload>>;
|
|
76
|
+
|
|
77
|
+
impl<CT, RT> WorkflowHandle<CT, RT>
|
|
78
|
+
where
|
|
79
|
+
CT: RawClientLike<SvcType = InterceptedMetricsSvc> + Clone,
|
|
80
|
+
// TODO: Make more generic, capable of (de)serialization w/ serde
|
|
81
|
+
RT: FromPayloadsExt,
|
|
82
|
+
{
|
|
83
|
+
pub(crate) fn new(client: CT, info: WorkflowExecutionInfo) -> Self {
|
|
84
|
+
Self {
|
|
85
|
+
client,
|
|
86
|
+
info,
|
|
87
|
+
_res_type: PhantomData::<RT>,
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
pub async fn get_workflow_result(
|
|
92
|
+
&self,
|
|
93
|
+
opts: GetWorkflowResultOpts,
|
|
94
|
+
) -> Result<WorkflowExecutionResult<RT>, anyhow::Error> {
|
|
95
|
+
let mut next_page_tok = vec![];
|
|
96
|
+
let mut run_id = self.info.run_id.clone().unwrap_or_default();
|
|
97
|
+
loop {
|
|
98
|
+
let server_res = self
|
|
99
|
+
.client
|
|
100
|
+
.clone()
|
|
101
|
+
.client()
|
|
102
|
+
.get_workflow_execution_history(GetWorkflowExecutionHistoryRequest {
|
|
103
|
+
namespace: self.info.namespace.to_string(),
|
|
104
|
+
execution: Some(WorkflowExecution {
|
|
105
|
+
workflow_id: self.info.workflow_id.clone(),
|
|
106
|
+
run_id: run_id.clone(),
|
|
107
|
+
}),
|
|
108
|
+
skip_archival: true,
|
|
109
|
+
wait_new_event: true,
|
|
110
|
+
history_event_filter_type: HistoryEventFilterType::CloseEvent as i32,
|
|
111
|
+
next_page_token: next_page_tok.clone(),
|
|
112
|
+
..Default::default()
|
|
113
|
+
})
|
|
114
|
+
.await?
|
|
115
|
+
.into_inner();
|
|
116
|
+
|
|
117
|
+
let mut history = server_res
|
|
118
|
+
.history
|
|
119
|
+
.ok_or_else(|| anyhow!("Server returned an empty history!"))?;
|
|
120
|
+
|
|
121
|
+
if history.events.is_empty() {
|
|
122
|
+
next_page_tok = server_res.next_page_token;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
// If page token was previously set, clear it.
|
|
126
|
+
next_page_tok = vec![];
|
|
127
|
+
|
|
128
|
+
let event_attrs = history.events.pop().and_then(|ev| ev.attributes);
|
|
129
|
+
|
|
130
|
+
macro_rules! follow {
|
|
131
|
+
($attrs:ident) => {
|
|
132
|
+
if opts.follow_runs && $attrs.new_execution_run_id != "" {
|
|
133
|
+
run_id = $attrs.new_execution_run_id;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
break match event_attrs {
|
|
140
|
+
Some(Attributes::WorkflowExecutionCompletedEventAttributes(attrs)) => {
|
|
141
|
+
follow!(attrs);
|
|
142
|
+
Ok(WorkflowExecutionResult::Succeeded(RT::from_payloads(
|
|
143
|
+
attrs.result,
|
|
144
|
+
)))
|
|
145
|
+
}
|
|
146
|
+
Some(Attributes::WorkflowExecutionFailedEventAttributes(attrs)) => {
|
|
147
|
+
follow!(attrs);
|
|
148
|
+
Ok(WorkflowExecutionResult::Failed(
|
|
149
|
+
attrs.failure.unwrap_or_default(),
|
|
150
|
+
))
|
|
151
|
+
}
|
|
152
|
+
Some(Attributes::WorkflowExecutionCanceledEventAttributes(attrs)) => Ok(
|
|
153
|
+
WorkflowExecutionResult::Cancelled(Vec::from_payloads(attrs.details)),
|
|
154
|
+
),
|
|
155
|
+
Some(Attributes::WorkflowExecutionTimedOutEventAttributes(attrs)) => {
|
|
156
|
+
follow!(attrs);
|
|
157
|
+
Ok(WorkflowExecutionResult::TimedOut)
|
|
158
|
+
}
|
|
159
|
+
Some(Attributes::WorkflowExecutionTerminatedEventAttributes(attrs)) => Ok(
|
|
160
|
+
WorkflowExecutionResult::Terminated(Vec::from_payloads(attrs.details)),
|
|
161
|
+
),
|
|
162
|
+
Some(Attributes::WorkflowExecutionContinuedAsNewEventAttributes(attrs)) => {
|
|
163
|
+
if opts.follow_runs {
|
|
164
|
+
if !attrs.new_execution_run_id.is_empty() {
|
|
165
|
+
run_id = attrs.new_execution_run_id;
|
|
166
|
+
continue;
|
|
167
|
+
} else {
|
|
168
|
+
bail!("New execution run id was empty in continue as new event!");
|
|
169
|
+
}
|
|
170
|
+
} else {
|
|
171
|
+
Ok(WorkflowExecutionResult::ContinuedAsNew)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
o => Err(anyhow!(
|
|
175
|
+
"Server returned an event that didn't match the CloseEvent filter. \
|
|
176
|
+
This is either a server bug or a new event the SDK does not understand. \
|
|
177
|
+
Event details: {:?}",
|
|
178
|
+
o
|
|
179
|
+
)),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
@@ -7,6 +7,7 @@ use tokio::sync::{AcquireError, Semaphore, SemaphorePermit};
|
|
|
7
7
|
/// acquired or restored through the provided methods
|
|
8
8
|
pub(crate) struct MeteredSemaphore {
|
|
9
9
|
pub sem: Semaphore,
|
|
10
|
+
max_permits: usize,
|
|
10
11
|
metrics_ctx: MetricsContext,
|
|
11
12
|
record_fn: fn(&MetricsContext, usize),
|
|
12
13
|
}
|
|
@@ -19,6 +20,7 @@ impl MeteredSemaphore {
|
|
|
19
20
|
) -> Self {
|
|
20
21
|
Self {
|
|
21
22
|
sem: Semaphore::new(inital_permits),
|
|
23
|
+
max_permits: inital_permits,
|
|
22
24
|
metrics_ctx,
|
|
23
25
|
record_fn,
|
|
24
26
|
}
|
|
@@ -30,9 +32,14 @@ impl MeteredSemaphore {
|
|
|
30
32
|
res
|
|
31
33
|
}
|
|
32
34
|
|
|
33
|
-
/// Adds just one permit
|
|
35
|
+
/// Adds just one permit. Will not add if already at the initial/max capacity.
|
|
34
36
|
pub fn add_permit(&self) {
|
|
35
|
-
self.sem.
|
|
36
|
-
|
|
37
|
+
if self.sem.available_permits() < self.max_permits {
|
|
38
|
+
self.sem.add_permits(1);
|
|
39
|
+
(self.record_fn)(&self.metrics_ctx, self.sem.available_permits());
|
|
40
|
+
} else if cfg!(debug_assertions) {
|
|
41
|
+
// Panic only during debug mode if this happens
|
|
42
|
+
panic!("Tried to add permit to a semaphore that already was at capacity!");
|
|
43
|
+
}
|
|
37
44
|
}
|
|
38
45
|
}
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
use crate::{
|
|
2
2
|
replay::DEFAULT_WORKFLOW_TYPE,
|
|
3
|
-
test_help::{
|
|
4
|
-
build_mock_pollers, canned_histories, mock_worker, MockPollCfg, ResponseType, TEST_Q,
|
|
5
|
-
},
|
|
3
|
+
test_help::{canned_histories, mock_sdk, MockPollCfg, ResponseType},
|
|
6
4
|
worker::client::mocks::mock_workflow_client,
|
|
7
5
|
workflow::managed_wf::ManagedWFFunc,
|
|
8
6
|
};
|
|
9
|
-
use std::sync::Arc;
|
|
10
7
|
use temporal_client::WorkflowOptions;
|
|
11
8
|
use temporal_sdk::{ChildWorkflowOptions, Signal, WfContext, WorkflowFunction, WorkflowResult};
|
|
12
9
|
use temporal_sdk_core_protos::coresdk::child_workflow::{
|
|
13
10
|
child_workflow_result, ChildWorkflowCancellationType,
|
|
14
11
|
};
|
|
15
|
-
use temporal_sdk_core_test_utils::TestWorker;
|
|
16
12
|
use tokio::join;
|
|
17
13
|
|
|
18
14
|
const SIGNAME: &str = "SIGNAME";
|
|
@@ -26,10 +22,12 @@ async fn signal_child_workflow(#[case] serial: bool) {
|
|
|
26
22
|
let wf_type = DEFAULT_WORKFLOW_TYPE;
|
|
27
23
|
let t = canned_histories::single_child_workflow_signaled("child-id-1", SIGNAME);
|
|
28
24
|
let mock = mock_workflow_client();
|
|
29
|
-
let
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
let mut worker = mock_sdk(MockPollCfg::from_resp_batches(
|
|
26
|
+
wf_id,
|
|
27
|
+
t,
|
|
28
|
+
[ResponseType::AllHistory],
|
|
29
|
+
mock,
|
|
30
|
+
));
|
|
33
31
|
|
|
34
32
|
let wf = move |ctx: WfContext| async move {
|
|
35
33
|
let child = ctx.child_workflow(ChildWorkflowOptions {
|
|
@@ -1,21 +1,15 @@
|
|
|
1
1
|
use crate::{
|
|
2
2
|
replay::DEFAULT_WORKFLOW_TYPE,
|
|
3
|
-
test_help::{
|
|
4
|
-
build_mock_pollers, canned_histories, mock_worker, MockPollCfg, ResponseType, TEST_Q,
|
|
5
|
-
},
|
|
3
|
+
test_help::{canned_histories, mock_sdk, mock_sdk_cfg, MockPollCfg, ResponseType},
|
|
6
4
|
worker::client::mocks::mock_workflow_client,
|
|
7
5
|
};
|
|
8
6
|
use std::{
|
|
9
|
-
sync::{
|
|
10
|
-
atomic::{AtomicBool, AtomicUsize, Ordering},
|
|
11
|
-
Arc,
|
|
12
|
-
},
|
|
7
|
+
sync::atomic::{AtomicBool, AtomicUsize, Ordering},
|
|
13
8
|
time::Duration,
|
|
14
9
|
};
|
|
15
10
|
use temporal_client::WorkflowOptions;
|
|
16
11
|
use temporal_sdk::{WfContext, WorkflowResult};
|
|
17
12
|
use temporal_sdk_core_protos::temporal::api::enums::v1::WorkflowTaskFailedCause;
|
|
18
|
-
use temporal_sdk_core_test_utils::TestWorker;
|
|
19
13
|
|
|
20
14
|
static DID_FAIL: AtomicBool = AtomicBool::new(false);
|
|
21
15
|
pub async fn timer_wf_fails_once(ctx: WfContext) -> WorkflowResult<()> {
|
|
@@ -32,7 +26,7 @@ pub async fn timer_wf_fails_once(ctx: WfContext) -> WorkflowResult<()> {
|
|
|
32
26
|
/// Verifies that workflow panics (which in this case the Rust SDK turns into workflow activation
|
|
33
27
|
/// failures) are turned into unspecified WFT failures.
|
|
34
28
|
#[tokio::test]
|
|
35
|
-
async fn
|
|
29
|
+
async fn test_panic_wf_task_rejected_properly() {
|
|
36
30
|
let wf_id = "fakeid";
|
|
37
31
|
let wf_type = DEFAULT_WORKFLOW_TYPE;
|
|
38
32
|
let t = canned_histories::workflow_fails_with_failure_after_timer("1");
|
|
@@ -43,9 +37,7 @@ async fn test_wf_task_rejected_properly() {
|
|
|
43
37
|
mh.num_expected_fails = Some(1);
|
|
44
38
|
mh.expect_fail_wft_matcher =
|
|
45
39
|
Box::new(|_, cause, _| matches!(cause, WorkflowTaskFailedCause::Unspecified));
|
|
46
|
-
let
|
|
47
|
-
let core = mock_worker(mock);
|
|
48
|
-
let mut worker = TestWorker::new(Arc::new(core), TEST_Q.to_string());
|
|
40
|
+
let mut worker = mock_sdk(mh);
|
|
49
41
|
|
|
50
42
|
worker.register_wf(wf_type.to_owned(), timer_wf_fails_once);
|
|
51
43
|
worker
|
|
@@ -82,14 +74,11 @@ async fn test_wf_task_rejected_properly_due_to_nondeterminism(#[case] use_cache:
|
|
|
82
74
|
mh.num_expected_fails = Some(1);
|
|
83
75
|
mh.expect_fail_wft_matcher =
|
|
84
76
|
Box::new(|_, cause, _| matches!(cause, WorkflowTaskFailedCause::NonDeterministicError));
|
|
85
|
-
let mut
|
|
86
|
-
|
|
87
|
-
mock.worker_cfg(|cfg| {
|
|
77
|
+
let mut worker = mock_sdk_cfg(mh, |cfg| {
|
|
78
|
+
if use_cache {
|
|
88
79
|
cfg.max_cached_workflows = 2;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
let core = mock_worker(mock);
|
|
92
|
-
let mut worker = TestWorker::new(Arc::new(core), TEST_Q.to_string());
|
|
80
|
+
}
|
|
81
|
+
});
|
|
93
82
|
|
|
94
83
|
let started_count: &'static _ = Box::leak(Box::new(AtomicUsize::new(0)));
|
|
95
84
|
worker.register_wf(wf_type.to_owned(), move |ctx: WfContext| async move {
|