@temporalio/core-bridge 1.12.2 → 1.12.3
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/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/.cargo/config.toml +1 -1
- package/sdk-core/client/src/callback_based.rs +123 -0
- package/sdk-core/client/src/lib.rs +96 -28
- package/sdk-core/client/src/metrics.rs +33 -5
- package/sdk-core/client/src/raw.rs +40 -1
- package/sdk-core/client/src/retry.rs +12 -3
- package/sdk-core/core/src/lib.rs +4 -2
- package/sdk-core/core/src/pollers/poll_buffer.rs +62 -14
- package/sdk-core/core/src/worker/client.rs +9 -5
- package/sdk-core/core/src/worker/heartbeat.rs +3 -1
- package/sdk-core/core-api/src/worker.rs +2 -2
- package/sdk-core/core-c-bridge/Cargo.toml +2 -0
- package/sdk-core/core-c-bridge/include/temporal-sdk-core-c-bridge.h +105 -0
- package/sdk-core/core-c-bridge/src/client.rs +265 -8
- package/sdk-core/core-c-bridge/src/tests/context.rs +11 -0
- package/sdk-core/core-c-bridge/src/tests/mod.rs +179 -3
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/CODEOWNERS +1 -1
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/README.md +1 -1
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/VERSION +1 -1
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/buf.yaml +1 -0
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/cloudservice/v1/request_response.proto +83 -0
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/cloudservice/v1/service.proto +37 -0
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/connectivityrule/v1/message.proto +64 -0
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/identity/v1/message.proto +3 -1
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/namespace/v1/message.proto +10 -0
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/operation/v1/message.proto +1 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv2.json +644 -9
- package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv3.yaml +635 -21
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/batch/v1/message.proto +60 -2
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/common/v1/message.proto +84 -15
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +3 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +11 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/history/v1/message.proto +5 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +1 -1
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/worker_config.proto +36 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +29 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/worker/v1/message.proto +11 -1
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +122 -4
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +41 -0
- package/sdk-core/sdk-core-protos/src/lib.rs +5 -1
- package/sdk-core/test-utils/Cargo.toml +1 -0
- package/sdk-core/test-utils/src/lib.rs +90 -3
- package/sdk-core/tests/cloud_tests.rs +11 -74
- package/sdk-core/tests/integ_tests/client_tests.rs +14 -10
- package/sdk-core/tests/integ_tests/worker_tests.rs +8 -2
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +13 -0
- package/sdk-core/tests/integ_tests/workflow_tests/priority.rs +2 -108
- package/sdk-core/tests/main.rs +3 -0
- package/sdk-core/tests/shared_tests/mod.rs +43 -0
- package/sdk-core/tests/shared_tests/priority.rs +155 -0
- package/src/client.rs +5 -0
|
@@ -24,6 +24,7 @@ use std::{
|
|
|
24
24
|
future::Future,
|
|
25
25
|
net::SocketAddr,
|
|
26
26
|
path::PathBuf,
|
|
27
|
+
str::FromStr,
|
|
27
28
|
sync::Arc,
|
|
28
29
|
time::{Duration, Instant},
|
|
29
30
|
};
|
|
@@ -69,8 +70,9 @@ use temporal_sdk_core_protos::{
|
|
|
69
70
|
workflow_completion::WorkflowActivationCompletion,
|
|
70
71
|
},
|
|
71
72
|
temporal::api::{
|
|
72
|
-
common::v1::Payload,
|
|
73
|
-
|
|
73
|
+
common::v1::Payload,
|
|
74
|
+
history::v1::History,
|
|
75
|
+
workflowservice::v1::{GetClusterInfoRequest, StartWorkflowExecutionResponse},
|
|
74
76
|
},
|
|
75
77
|
};
|
|
76
78
|
use tokio::{sync::OnceCell, task::AbortHandle};
|
|
@@ -95,6 +97,7 @@ pub const OTEL_URL_ENV_VAR: &str = "TEMPORAL_INTEG_OTEL_URL";
|
|
|
95
97
|
pub const PROM_ENABLE_ENV_VAR: &str = "TEMPORAL_INTEG_PROM_PORT";
|
|
96
98
|
/// This should match the prometheus port exposed in docker-compose-ci.yaml
|
|
97
99
|
pub const PROMETHEUS_QUERY_API: &str = "http://localhost:9090/api/v1/query";
|
|
100
|
+
|
|
98
101
|
#[macro_export]
|
|
99
102
|
macro_rules! prost_dur {
|
|
100
103
|
($dur_call:ident $args:tt) => {
|
|
@@ -192,6 +195,37 @@ pub fn init_integ_telem() -> Option<&'static CoreRuntime> {
|
|
|
192
195
|
}))
|
|
193
196
|
}
|
|
194
197
|
|
|
198
|
+
pub async fn get_cloud_client() -> RetryClient<Client> {
|
|
199
|
+
let cloud_addr = env::var("TEMPORAL_CLOUD_ADDRESS").unwrap();
|
|
200
|
+
let cloud_key = env::var("TEMPORAL_CLIENT_KEY").unwrap();
|
|
201
|
+
|
|
202
|
+
let client_cert = env::var("TEMPORAL_CLIENT_CERT")
|
|
203
|
+
.expect("TEMPORAL_CLIENT_CERT must be set")
|
|
204
|
+
.replace("\\n", "\n")
|
|
205
|
+
.into_bytes();
|
|
206
|
+
let client_private_key = cloud_key.replace("\\n", "\n").into_bytes();
|
|
207
|
+
let sgo = ClientOptionsBuilder::default()
|
|
208
|
+
.target_url(Url::from_str(&cloud_addr).unwrap())
|
|
209
|
+
.client_name("sdk-core-integ-tests")
|
|
210
|
+
.client_version("clientver")
|
|
211
|
+
.identity("sdk-test-client")
|
|
212
|
+
.tls_cfg(TlsConfig {
|
|
213
|
+
client_tls_config: Some(ClientTlsConfig {
|
|
214
|
+
client_cert,
|
|
215
|
+
client_private_key,
|
|
216
|
+
}),
|
|
217
|
+
..Default::default()
|
|
218
|
+
})
|
|
219
|
+
.build()
|
|
220
|
+
.unwrap();
|
|
221
|
+
sgo.connect(
|
|
222
|
+
env::var("TEMPORAL_NAMESPACE").expect("TEMPORAL_NAMESPACE must be set"),
|
|
223
|
+
None,
|
|
224
|
+
)
|
|
225
|
+
.await
|
|
226
|
+
.unwrap()
|
|
227
|
+
}
|
|
228
|
+
|
|
195
229
|
/// Implements a builder pattern to help integ tests initialize core and create workflows
|
|
196
230
|
pub struct CoreWfStarter {
|
|
197
231
|
/// Used for both the task queue and workflow id
|
|
@@ -202,6 +236,7 @@ pub struct CoreWfStarter {
|
|
|
202
236
|
initted_worker: OnceCell<InitializedWorker>,
|
|
203
237
|
runtime_override: Option<Arc<CoreRuntime>>,
|
|
204
238
|
client_override: Option<Arc<RetryClient<Client>>>,
|
|
239
|
+
min_local_server_version: Option<String>,
|
|
205
240
|
}
|
|
206
241
|
struct InitializedWorker {
|
|
207
242
|
worker: Arc<dyn CoreWorker>,
|
|
@@ -223,6 +258,51 @@ impl CoreWfStarter {
|
|
|
223
258
|
Self::_new(test_name, None, Some(client))
|
|
224
259
|
}
|
|
225
260
|
|
|
261
|
+
/// Targets cloud if the required env vars are present. Otherwise, local server (but only if
|
|
262
|
+
/// the minimum version requirement is met). Returns None if the local server is not new enough.
|
|
263
|
+
///
|
|
264
|
+
/// An empty string means to skip the version check.
|
|
265
|
+
pub async fn new_cloud_or_local(test_name: &str, version_req: &str) -> Option<Self> {
|
|
266
|
+
init_integ_telem();
|
|
267
|
+
let mut check_mlsv = false;
|
|
268
|
+
let client = if env::var("TEMPORAL_CLOUD_ADDRESS").is_ok() {
|
|
269
|
+
Some(get_cloud_client().await)
|
|
270
|
+
} else {
|
|
271
|
+
check_mlsv = true;
|
|
272
|
+
None
|
|
273
|
+
};
|
|
274
|
+
let mut s = Self::_new(test_name, None, client);
|
|
275
|
+
|
|
276
|
+
if check_mlsv && !version_req.is_empty() {
|
|
277
|
+
let clustinfo = (*s.get_client().await)
|
|
278
|
+
.get_client()
|
|
279
|
+
.inner()
|
|
280
|
+
.workflow_svc()
|
|
281
|
+
.clone()
|
|
282
|
+
.get_cluster_info(GetClusterInfoRequest::default())
|
|
283
|
+
.await;
|
|
284
|
+
let srv_ver = semver::Version::parse(
|
|
285
|
+
&clustinfo
|
|
286
|
+
.expect("must be able to get cluster info")
|
|
287
|
+
.into_inner()
|
|
288
|
+
.server_version,
|
|
289
|
+
)
|
|
290
|
+
.expect("must be able to parse server version");
|
|
291
|
+
let req = semver::VersionReq::parse(version_req)
|
|
292
|
+
.expect("must be able to parse server version requirement");
|
|
293
|
+
|
|
294
|
+
if !req.matches(&srv_ver) {
|
|
295
|
+
warn!(
|
|
296
|
+
"Server version {} does not meet requirement {} for test {}",
|
|
297
|
+
srv_ver, req, test_name
|
|
298
|
+
);
|
|
299
|
+
return None;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
Some(s)
|
|
304
|
+
}
|
|
305
|
+
|
|
226
306
|
fn _new(
|
|
227
307
|
test_name: &str,
|
|
228
308
|
runtime_override: Option<CoreRuntime>,
|
|
@@ -241,6 +321,7 @@ impl CoreWfStarter {
|
|
|
241
321
|
workflow_options: Default::default(),
|
|
242
322
|
runtime_override: runtime_override.map(Arc::new),
|
|
243
323
|
client_override: client_override.map(Arc::new),
|
|
324
|
+
min_local_server_version: None,
|
|
244
325
|
}
|
|
245
326
|
}
|
|
246
327
|
|
|
@@ -253,6 +334,7 @@ impl CoreWfStarter {
|
|
|
253
334
|
workflow_options: self.workflow_options.clone(),
|
|
254
335
|
runtime_override: self.runtime_override.clone(),
|
|
255
336
|
client_override: self.client_override.clone(),
|
|
337
|
+
min_local_server_version: self.min_local_server_version.clone(),
|
|
256
338
|
initted_worker: Default::default(),
|
|
257
339
|
}
|
|
258
340
|
}
|
|
@@ -475,11 +557,16 @@ impl TestWorker {
|
|
|
475
557
|
workflow_id: impl Into<String>,
|
|
476
558
|
workflow_type: impl Into<String>,
|
|
477
559
|
input: Vec<Payload>,
|
|
478
|
-
options: WorkflowOptions,
|
|
560
|
+
mut options: WorkflowOptions,
|
|
479
561
|
) -> Result<String, anyhow::Error> {
|
|
480
562
|
if self.client.is_none() {
|
|
481
563
|
return Ok("fake_run_id".to_string());
|
|
482
564
|
}
|
|
565
|
+
// Fallback overall execution timeout to avoid leaving open workflows when testing against
|
|
566
|
+
// cloud
|
|
567
|
+
if options.execution_timeout.is_none() {
|
|
568
|
+
options.execution_timeout = Some(Duration::from_secs(60 * 5));
|
|
569
|
+
}
|
|
483
570
|
self.get_submitter_handle()
|
|
484
571
|
.submit_wf(workflow_id, workflow_type, input, options)
|
|
485
572
|
.await
|
|
@@ -1,53 +1,11 @@
|
|
|
1
|
-
use
|
|
2
|
-
|
|
3
|
-
str::FromStr,
|
|
4
|
-
sync::atomic::{AtomicBool, Ordering::Relaxed},
|
|
5
|
-
};
|
|
6
|
-
use temporal_client::{
|
|
7
|
-
Client, ClientOptionsBuilder, ClientTlsConfig, RetryClient, TlsConfig, WorkflowClientTrait,
|
|
8
|
-
};
|
|
9
|
-
use temporal_sdk::WfContext;
|
|
10
|
-
use temporal_sdk_core_protos::temporal::api::{
|
|
11
|
-
enums::v1::{EventType, WorkflowTaskFailedCause::GrpcMessageTooLarge},
|
|
12
|
-
history::v1::history_event::Attributes::WorkflowTaskFailedEventAttributes,
|
|
13
|
-
};
|
|
14
|
-
use temporal_sdk_core_test_utils::CoreWfStarter;
|
|
15
|
-
use url::Url;
|
|
1
|
+
use temporal_client::WorkflowClientTrait;
|
|
2
|
+
use temporal_sdk_core_test_utils::get_cloud_client;
|
|
16
3
|
|
|
17
|
-
|
|
18
|
-
let cloud_addr = env::var("TEMPORAL_CLOUD_ADDRESS").unwrap();
|
|
19
|
-
let cloud_key = env::var("TEMPORAL_CLIENT_KEY").unwrap();
|
|
20
|
-
|
|
21
|
-
let client_cert = env::var("TEMPORAL_CLIENT_CERT")
|
|
22
|
-
.expect("TEMPORAL_CLIENT_CERT must be set")
|
|
23
|
-
.replace("\\n", "\n")
|
|
24
|
-
.into_bytes();
|
|
25
|
-
let client_private_key = cloud_key.replace("\\n", "\n").into_bytes();
|
|
26
|
-
let sgo = ClientOptionsBuilder::default()
|
|
27
|
-
.target_url(Url::from_str(&cloud_addr).unwrap())
|
|
28
|
-
.client_name(client_name)
|
|
29
|
-
.client_version("clientver")
|
|
30
|
-
.identity("sdk-test-client")
|
|
31
|
-
.tls_cfg(TlsConfig {
|
|
32
|
-
client_tls_config: Some(ClientTlsConfig {
|
|
33
|
-
client_cert,
|
|
34
|
-
client_private_key,
|
|
35
|
-
}),
|
|
36
|
-
..Default::default()
|
|
37
|
-
})
|
|
38
|
-
.build()
|
|
39
|
-
.unwrap();
|
|
40
|
-
sgo.connect(
|
|
41
|
-
env::var("TEMPORAL_NAMESPACE").expect("TEMPORAL_NAMESPACE must be set"),
|
|
42
|
-
None,
|
|
43
|
-
)
|
|
44
|
-
.await
|
|
45
|
-
.unwrap()
|
|
46
|
-
}
|
|
4
|
+
mod shared_tests;
|
|
47
5
|
|
|
48
6
|
#[tokio::test]
|
|
49
7
|
async fn tls_test() {
|
|
50
|
-
let con =
|
|
8
|
+
let con = get_cloud_client().await;
|
|
51
9
|
con.list_workflow_executions(100, vec![], "".to_string())
|
|
52
10
|
.await
|
|
53
11
|
.unwrap();
|
|
@@ -55,32 +13,11 @@ async fn tls_test() {
|
|
|
55
13
|
|
|
56
14
|
#[tokio::test]
|
|
57
15
|
async fn grpc_message_too_large_test() {
|
|
58
|
-
|
|
59
|
-
let mut starter =
|
|
60
|
-
CoreWfStarter::new_with_client(wf_name, get_client("grpc_message_too_large").await);
|
|
61
|
-
starter.worker_config.no_remote_activities(true);
|
|
62
|
-
let mut core = starter.worker().await;
|
|
63
|
-
|
|
64
|
-
static OVERSIZE_GRPC_MESSAGE_RUN: AtomicBool = AtomicBool::new(false);
|
|
65
|
-
core.register_wf(wf_name.to_owned(), |_ctx: WfContext| async move {
|
|
66
|
-
if OVERSIZE_GRPC_MESSAGE_RUN.load(Relaxed) {
|
|
67
|
-
Ok(vec![].into())
|
|
68
|
-
} else {
|
|
69
|
-
OVERSIZE_GRPC_MESSAGE_RUN.store(true, Relaxed);
|
|
70
|
-
let result: Vec<u8> = vec![0; 5000000];
|
|
71
|
-
Ok(result.into())
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
starter.start_with_worker(wf_name, &mut core).await;
|
|
75
|
-
core.run_until_done().await.unwrap();
|
|
76
|
-
|
|
77
|
-
assert!(starter.get_history().await.events.iter().any(|e| {
|
|
78
|
-
e.event_type == EventType::WorkflowTaskFailed as i32
|
|
79
|
-
&& if let WorkflowTaskFailedEventAttributes(attr) = e.attributes.as_ref().unwrap() {
|
|
80
|
-
attr.cause == GrpcMessageTooLarge as i32
|
|
81
|
-
&& attr.failure.as_ref().unwrap().message == "GRPC Message too large"
|
|
82
|
-
} else {
|
|
83
|
-
false
|
|
84
|
-
}
|
|
85
|
-
}))
|
|
16
|
+
shared_tests::grpc_message_too_large().await
|
|
86
17
|
}
|
|
18
|
+
|
|
19
|
+
// Needs https://github.com/temporalio/temporal/pull/8143 to be rolled out in cloud to pass
|
|
20
|
+
// #[tokio::test]
|
|
21
|
+
// async fn priority_values_sent_to_server() {
|
|
22
|
+
// shared_tests::priority::priority_values_sent_to_server().await
|
|
23
|
+
// }
|
|
@@ -110,7 +110,7 @@ struct GenericService<F> {
|
|
|
110
110
|
}
|
|
111
111
|
impl<F> Service<tonic::codegen::http::Request<Body>> for GenericService<F>
|
|
112
112
|
where
|
|
113
|
-
F: FnMut() -> Response<Body
|
|
113
|
+
F: FnMut() -> BoxFuture<'static, Response<Body>>,
|
|
114
114
|
{
|
|
115
115
|
type Response = Response<Body>;
|
|
116
116
|
type Error = Infallible;
|
|
@@ -133,7 +133,7 @@ where
|
|
|
133
133
|
)
|
|
134
134
|
.unwrap();
|
|
135
135
|
let r = (self.response_maker)();
|
|
136
|
-
async move { Ok(r) }.boxed()
|
|
136
|
+
async move { Ok(r.await) }.boxed()
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
impl<F> NamedService for GenericService<F> {
|
|
@@ -144,12 +144,12 @@ struct FakeServer {
|
|
|
144
144
|
addr: std::net::SocketAddr,
|
|
145
145
|
shutdown_tx: oneshot::Sender<()>,
|
|
146
146
|
header_rx: tokio::sync::mpsc::UnboundedReceiver<String>,
|
|
147
|
-
server_handle: tokio::task::JoinHandle<()>,
|
|
147
|
+
pub server_handle: tokio::task::JoinHandle<()>,
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
async fn fake_server<F>(response_maker: F) -> FakeServer
|
|
151
151
|
where
|
|
152
|
-
F: FnMut() -> Response<Body
|
|
152
|
+
F: FnMut() -> BoxFuture<'static, Response<Body>> + Clone + Send + Sync + 'static,
|
|
153
153
|
{
|
|
154
154
|
let (shutdown_tx, shutdown_rx) = oneshot::channel::<()>();
|
|
155
155
|
let (header_tx, header_rx) = tokio::sync::mpsc::unbounded_channel();
|
|
@@ -191,7 +191,7 @@ impl FakeServer {
|
|
|
191
191
|
|
|
192
192
|
#[tokio::test]
|
|
193
193
|
async fn timeouts_respected_one_call_fake_server() {
|
|
194
|
-
let mut fs = fake_server(|| Response::new(Body::empty())).await;
|
|
194
|
+
let mut fs = fake_server(|| async { Response::new(Body::empty()) }.boxed()).await;
|
|
195
195
|
let header_rx = &mut fs.header_rx;
|
|
196
196
|
|
|
197
197
|
let mut opts = get_integ_server_options();
|
|
@@ -260,7 +260,11 @@ async fn non_retryable_errors() {
|
|
|
260
260
|
Code::Unauthenticated,
|
|
261
261
|
Code::Unimplemented,
|
|
262
262
|
] {
|
|
263
|
-
let mut fs = fake_server(move ||
|
|
263
|
+
let mut fs = fake_server(move || {
|
|
264
|
+
let s = Status::new(code, "bla").into_http();
|
|
265
|
+
async { s }.boxed()
|
|
266
|
+
})
|
|
267
|
+
.await;
|
|
264
268
|
|
|
265
269
|
let mut opts = get_integ_server_options();
|
|
266
270
|
let uri = format!("http://localhost:{}", fs.addr.port())
|
|
@@ -292,13 +296,13 @@ async fn retryable_errors() {
|
|
|
292
296
|
{
|
|
293
297
|
let count = Arc::new(AtomicUsize::new(0));
|
|
294
298
|
let mut fs = fake_server(move || {
|
|
295
|
-
dbg!("Making resp");
|
|
296
299
|
let prev = count.fetch_add(1, Ordering::Relaxed);
|
|
297
|
-
if prev < 3 {
|
|
300
|
+
let r = if prev < 3 {
|
|
298
301
|
Status::new(code, "bla").into_http()
|
|
299
302
|
} else {
|
|
300
303
|
make_ok_response(RespondActivityTaskCanceledResponse::default())
|
|
301
|
-
}
|
|
304
|
+
};
|
|
305
|
+
async { r }.boxed()
|
|
302
306
|
})
|
|
303
307
|
.await;
|
|
304
308
|
|
|
@@ -335,7 +339,7 @@ async fn namespace_header_attached_to_relevant_calls() {
|
|
|
335
339
|
.add_service(GenericService {
|
|
336
340
|
header_to_parse: "Temporal-Namespace",
|
|
337
341
|
header_tx,
|
|
338
|
-
response_maker: || Response::new(Body::empty()),
|
|
342
|
+
response_maker: || async { Response::new(Body::empty()) }.boxed(),
|
|
339
343
|
})
|
|
340
344
|
.serve_with_incoming_shutdown(
|
|
341
345
|
tokio_stream::wrappers::TcpListenerStream::new(listener),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
use crate::shared_tests;
|
|
1
2
|
use assert_matches::assert_matches;
|
|
2
3
|
use std::{
|
|
3
4
|
cell::Cell,
|
|
@@ -15,13 +16,13 @@ use temporal_sdk_core_api::{
|
|
|
15
16
|
errors::WorkerValidationError,
|
|
16
17
|
worker::{PollerBehavior, WorkerConfigBuilder, WorkerVersioningStrategy},
|
|
17
18
|
};
|
|
18
|
-
use temporal_sdk_core_protos::temporal::api::enums::v1::WorkflowTaskFailedCause::GrpcMessageTooLarge;
|
|
19
19
|
use temporal_sdk_core_protos::{
|
|
20
20
|
coresdk::workflow_completion::{
|
|
21
21
|
Failure, WorkflowActivationCompletion, workflow_activation_completion::Status,
|
|
22
22
|
},
|
|
23
23
|
temporal::api::{
|
|
24
|
-
enums::v1::EventType,
|
|
24
|
+
enums::v1::{EventType, WorkflowTaskFailedCause::GrpcMessageTooLarge},
|
|
25
|
+
failure::v1::Failure as InnerFailure,
|
|
25
26
|
history::v1::history_event::Attributes::WorkflowTaskFailedEventAttributes,
|
|
26
27
|
},
|
|
27
28
|
};
|
|
@@ -195,3 +196,8 @@ async fn oversize_grpc_message() {
|
|
|
195
196
|
}
|
|
196
197
|
}))
|
|
197
198
|
}
|
|
199
|
+
|
|
200
|
+
#[tokio::test]
|
|
201
|
+
async fn grpc_message_too_large_test() {
|
|
202
|
+
shared_tests::grpc_message_too_large().await
|
|
203
|
+
}
|
|
@@ -11,6 +11,7 @@ use temporal_sdk::{
|
|
|
11
11
|
ActContext, ActExitValue, ActivityError, ActivityOptions, CancellableFuture, WfContext,
|
|
12
12
|
WfExitValue, WorkflowResult,
|
|
13
13
|
};
|
|
14
|
+
use temporal_sdk_core_api::worker::PollerBehavior;
|
|
14
15
|
use temporal_sdk_core_protos::{
|
|
15
16
|
DEFAULT_ACTIVITY_TYPE, TaskToken,
|
|
16
17
|
coresdk::{
|
|
@@ -1066,11 +1067,23 @@ async fn activity_can_be_cancelled_by_local_timeout() {
|
|
|
1066
1067
|
|
|
1067
1068
|
#[tokio::test]
|
|
1068
1069
|
#[ignore] // Runs forever, used to manually attempt to repro spurious activity completion rpc errs
|
|
1070
|
+
// Unfortunately there is no way to unit test this as tonic doesn't publicly expose the necessary
|
|
1071
|
+
// machinery to construct the right kind of error.
|
|
1069
1072
|
async fn long_activity_timeout_repro() {
|
|
1070
1073
|
let wf_name = "long_activity_timeout_repro";
|
|
1071
1074
|
let mut starter = CoreWfStarter::new(wf_name);
|
|
1072
1075
|
starter
|
|
1073
1076
|
.worker_config
|
|
1077
|
+
.workflow_task_poller_behavior(PollerBehavior::Autoscaling {
|
|
1078
|
+
minimum: 1,
|
|
1079
|
+
maximum: 10,
|
|
1080
|
+
initial: 5,
|
|
1081
|
+
})
|
|
1082
|
+
.activity_task_poller_behavior(PollerBehavior::Autoscaling {
|
|
1083
|
+
minimum: 1,
|
|
1084
|
+
maximum: 10,
|
|
1085
|
+
initial: 5,
|
|
1086
|
+
})
|
|
1074
1087
|
.local_timeout_buffer_for_activities(Duration::from_secs(0));
|
|
1075
1088
|
let mut worker = starter.worker().await;
|
|
1076
1089
|
worker.register_wf(wf_name.to_owned(), |ctx: WfContext| async move {
|
|
@@ -1,112 +1,6 @@
|
|
|
1
|
-
use
|
|
2
|
-
use temporal_client::{Priority, WorkflowClientTrait, WorkflowOptions};
|
|
3
|
-
use temporal_sdk::{ActContext, ActivityOptions, ChildWorkflowOptions, WfContext};
|
|
4
|
-
use temporal_sdk_core_protos::{
|
|
5
|
-
coresdk::AsJsonPayloadExt,
|
|
6
|
-
temporal::api::{common, history::v1::history_event::Attributes},
|
|
7
|
-
};
|
|
8
|
-
use temporal_sdk_core_test_utils::CoreWfStarter;
|
|
1
|
+
use crate::shared_tests;
|
|
9
2
|
|
|
10
3
|
#[tokio::test]
|
|
11
4
|
async fn priority_values_sent_to_server() {
|
|
12
|
-
|
|
13
|
-
starter.workflow_options.priority = Some(Priority { priority_key: 1 });
|
|
14
|
-
let mut worker = starter.worker().await;
|
|
15
|
-
let child_type = "child-wf";
|
|
16
|
-
|
|
17
|
-
worker.register_wf(starter.get_task_queue(), move |ctx: WfContext| async move {
|
|
18
|
-
let child = ctx.child_workflow(ChildWorkflowOptions {
|
|
19
|
-
workflow_id: format!("{}-child", ctx.task_queue()),
|
|
20
|
-
workflow_type: child_type.to_owned(),
|
|
21
|
-
options: WorkflowOptions {
|
|
22
|
-
priority: Some(Priority { priority_key: 4 }),
|
|
23
|
-
..Default::default()
|
|
24
|
-
},
|
|
25
|
-
..Default::default()
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
let started = child
|
|
29
|
-
.start(&ctx)
|
|
30
|
-
.await
|
|
31
|
-
.into_started()
|
|
32
|
-
.expect("Child should start OK");
|
|
33
|
-
let activity = ctx.activity(ActivityOptions {
|
|
34
|
-
activity_type: "echo".to_owned(),
|
|
35
|
-
input: "hello".as_json_payload().unwrap(),
|
|
36
|
-
start_to_close_timeout: Some(Duration::from_secs(5)),
|
|
37
|
-
priority: Some(Priority { priority_key: 5 }),
|
|
38
|
-
// Currently no priority info attached to eagerly run activities
|
|
39
|
-
do_not_eagerly_execute: true,
|
|
40
|
-
..Default::default()
|
|
41
|
-
});
|
|
42
|
-
started.result().await;
|
|
43
|
-
activity.await.unwrap_ok_payload();
|
|
44
|
-
Ok(().into())
|
|
45
|
-
});
|
|
46
|
-
worker.register_wf(child_type.to_owned(), |ctx: WfContext| async move {
|
|
47
|
-
assert_eq!(
|
|
48
|
-
ctx.workflow_initial_info().priority,
|
|
49
|
-
Some(common::v1::Priority { priority_key: 4 })
|
|
50
|
-
);
|
|
51
|
-
Ok(().into())
|
|
52
|
-
});
|
|
53
|
-
worker.register_activity("echo", |ctx: ActContext, echo_me: String| async move {
|
|
54
|
-
assert_eq!(ctx.get_info().priority, Priority { priority_key: 5 });
|
|
55
|
-
Ok(echo_me)
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
starter
|
|
59
|
-
.start_with_worker(starter.get_task_queue(), &mut worker)
|
|
60
|
-
.await;
|
|
61
|
-
worker.run_until_done().await.unwrap();
|
|
62
|
-
|
|
63
|
-
let client = starter.get_client().await;
|
|
64
|
-
let history = client
|
|
65
|
-
.get_workflow_execution_history(starter.get_task_queue().to_owned(), None, vec![])
|
|
66
|
-
.await
|
|
67
|
-
.unwrap()
|
|
68
|
-
.history
|
|
69
|
-
.unwrap();
|
|
70
|
-
let workflow_init_event = history
|
|
71
|
-
.events
|
|
72
|
-
.iter()
|
|
73
|
-
.find_map(|e| {
|
|
74
|
-
if let Attributes::WorkflowExecutionStartedEventAttributes(e) =
|
|
75
|
-
e.attributes.as_ref().unwrap()
|
|
76
|
-
{
|
|
77
|
-
Some(e)
|
|
78
|
-
} else {
|
|
79
|
-
None
|
|
80
|
-
}
|
|
81
|
-
})
|
|
82
|
-
.unwrap();
|
|
83
|
-
assert_eq!(workflow_init_event.priority.unwrap().priority_key, 1);
|
|
84
|
-
let child_init_event = history
|
|
85
|
-
.events
|
|
86
|
-
.iter()
|
|
87
|
-
.find_map(|e| {
|
|
88
|
-
if let Attributes::StartChildWorkflowExecutionInitiatedEventAttributes(e) =
|
|
89
|
-
e.attributes.as_ref().unwrap()
|
|
90
|
-
{
|
|
91
|
-
Some(e)
|
|
92
|
-
} else {
|
|
93
|
-
None
|
|
94
|
-
}
|
|
95
|
-
})
|
|
96
|
-
.unwrap();
|
|
97
|
-
assert_eq!(child_init_event.priority.unwrap().priority_key, 4);
|
|
98
|
-
let activity_sched_event = history
|
|
99
|
-
.events
|
|
100
|
-
.iter()
|
|
101
|
-
.find_map(|e| {
|
|
102
|
-
if let Attributes::ActivityTaskScheduledEventAttributes(e) =
|
|
103
|
-
e.attributes.as_ref().unwrap()
|
|
104
|
-
{
|
|
105
|
-
Some(e)
|
|
106
|
-
} else {
|
|
107
|
-
None
|
|
108
|
-
}
|
|
109
|
-
})
|
|
110
|
-
.unwrap();
|
|
111
|
-
assert_eq!(activity_sched_event.priority.unwrap().priority_key, 5);
|
|
5
|
+
shared_tests::priority::priority_values_sent_to_server().await
|
|
112
6
|
}
|
package/sdk-core/tests/main.rs
CHANGED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
//! Shared tests that are meant to be run against both local dev server and cloud
|
|
2
|
+
|
|
3
|
+
use std::sync::atomic::{AtomicBool, Ordering::Relaxed};
|
|
4
|
+
use temporal_sdk::WfContext;
|
|
5
|
+
use temporal_sdk_core_protos::temporal::api::{
|
|
6
|
+
enums::v1::{EventType, WorkflowTaskFailedCause::GrpcMessageTooLarge},
|
|
7
|
+
history::v1::history_event::Attributes::WorkflowTaskFailedEventAttributes,
|
|
8
|
+
};
|
|
9
|
+
use temporal_sdk_core_test_utils::CoreWfStarter;
|
|
10
|
+
|
|
11
|
+
pub(crate) mod priority;
|
|
12
|
+
|
|
13
|
+
pub(crate) async fn grpc_message_too_large() {
|
|
14
|
+
let wf_name = "oversize_grpc_message";
|
|
15
|
+
let mut starter = CoreWfStarter::new_cloud_or_local(wf_name, "")
|
|
16
|
+
.await
|
|
17
|
+
.unwrap();
|
|
18
|
+
starter.worker_config.no_remote_activities(true);
|
|
19
|
+
let mut core = starter.worker().await;
|
|
20
|
+
|
|
21
|
+
static OVERSIZE_GRPC_MESSAGE_RUN: AtomicBool = AtomicBool::new(false);
|
|
22
|
+
core.register_wf(wf_name.to_owned(), |_ctx: WfContext| async move {
|
|
23
|
+
if OVERSIZE_GRPC_MESSAGE_RUN.load(Relaxed) {
|
|
24
|
+
Ok(vec![].into())
|
|
25
|
+
} else {
|
|
26
|
+
OVERSIZE_GRPC_MESSAGE_RUN.store(true, Relaxed);
|
|
27
|
+
let result: Vec<u8> = vec![0; 5000000];
|
|
28
|
+
Ok(result.into())
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
starter.start_with_worker(wf_name, &mut core).await;
|
|
32
|
+
core.run_until_done().await.unwrap();
|
|
33
|
+
|
|
34
|
+
assert!(starter.get_history().await.events.iter().any(|e| {
|
|
35
|
+
e.event_type == EventType::WorkflowTaskFailed as i32
|
|
36
|
+
&& if let WorkflowTaskFailedEventAttributes(attr) = e.attributes.as_ref().unwrap() {
|
|
37
|
+
attr.cause == GrpcMessageTooLarge as i32
|
|
38
|
+
&& attr.failure.as_ref().unwrap().message == "GRPC Message too large"
|
|
39
|
+
} else {
|
|
40
|
+
false
|
|
41
|
+
}
|
|
42
|
+
}))
|
|
43
|
+
}
|