@temporalio/core-bridge 0.23.0 → 1.0.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 +118 -15
- package/Cargo.toml +2 -1
- package/LICENSE.md +1 -1
- package/README.md +1 -1
- package/index.d.ts +47 -18
- package/package.json +7 -7
- 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/docker-compose.yaml +4 -2
- package/sdk-core/ARCHITECTURE.md +9 -7
- package/sdk-core/README.md +5 -1
- package/sdk-core/arch_docs/diagrams/workflow_internals.svg +1 -0
- package/sdk-core/bridge-ffi/src/wrappers.rs +0 -3
- package/sdk-core/client/src/lib.rs +26 -8
- package/sdk-core/client/src/raw.rs +166 -54
- package/sdk-core/client/src/retry.rs +9 -4
- package/sdk-core/client/src/workflow_handle/mod.rs +4 -2
- package/sdk-core/core/Cargo.toml +2 -0
- package/sdk-core/core/src/abstractions.rs +137 -16
- package/sdk-core/core/src/core_tests/activity_tasks.rs +258 -63
- package/sdk-core/core/src/core_tests/child_workflows.rs +1 -2
- package/sdk-core/core/src/core_tests/determinism.rs +2 -2
- package/sdk-core/core/src/core_tests/local_activities.rs +8 -7
- package/sdk-core/core/src/core_tests/queries.rs +146 -60
- package/sdk-core/core/src/core_tests/replay_flag.rs +1 -1
- package/sdk-core/core/src/core_tests/workers.rs +39 -23
- package/sdk-core/core/src/core_tests/workflow_cancels.rs +1 -1
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +387 -280
- package/sdk-core/core/src/lib.rs +6 -4
- package/sdk-core/core/src/pollers/poll_buffer.rs +16 -10
- package/sdk-core/core/src/protosext/mod.rs +6 -6
- package/sdk-core/core/src/retry_logic.rs +1 -1
- package/sdk-core/core/src/telemetry/metrics.rs +21 -7
- package/sdk-core/core/src/telemetry/mod.rs +18 -4
- package/sdk-core/core/src/test_help/mod.rs +341 -109
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +18 -9
- package/sdk-core/core/src/worker/activities/local_activities.rs +19 -16
- package/sdk-core/core/src/worker/activities.rs +156 -29
- package/sdk-core/core/src/worker/client.rs +1 -0
- package/sdk-core/core/src/worker/mod.rs +132 -659
- package/sdk-core/core/src/{workflow → worker/workflow}/bridge.rs +1 -1
- package/sdk-core/core/src/{workflow → worker/workflow}/driven_workflow.rs +1 -1
- package/sdk-core/core/src/{workflow → worker/workflow}/history_update.rs +16 -2
- package/sdk-core/core/src/{workflow → worker/workflow}/machines/activity_state_machine.rs +39 -4
- package/sdk-core/core/src/{workflow → worker/workflow}/machines/cancel_external_state_machine.rs +5 -2
- package/sdk-core/core/src/{workflow → worker/workflow}/machines/cancel_workflow_state_machine.rs +1 -1
- package/sdk-core/core/src/{workflow → worker/workflow}/machines/child_workflow_state_machine.rs +2 -4
- package/sdk-core/core/src/{workflow → worker/workflow}/machines/complete_workflow_state_machine.rs +0 -0
- package/sdk-core/core/src/{workflow → worker/workflow}/machines/continue_as_new_workflow_state_machine.rs +1 -1
- package/sdk-core/core/src/{workflow → worker/workflow}/machines/fail_workflow_state_machine.rs +0 -0
- package/sdk-core/core/src/{workflow → worker/workflow}/machines/local_activity_state_machine.rs +2 -5
- package/sdk-core/core/src/{workflow → worker/workflow}/machines/mod.rs +1 -1
- package/sdk-core/core/src/{workflow → worker/workflow}/machines/mutable_side_effect_state_machine.rs +0 -0
- package/sdk-core/core/src/{workflow → worker/workflow}/machines/patch_state_machine.rs +1 -1
- package/sdk-core/core/src/{workflow → worker/workflow}/machines/side_effect_state_machine.rs +0 -0
- package/sdk-core/core/src/{workflow → worker/workflow}/machines/signal_external_state_machine.rs +4 -2
- package/sdk-core/core/src/{workflow → worker/workflow}/machines/timer_state_machine.rs +1 -2
- package/sdk-core/core/src/{workflow → worker/workflow}/machines/transition_coverage.rs +1 -1
- package/sdk-core/core/src/{workflow → worker/workflow}/machines/upsert_search_attributes_state_machine.rs +5 -7
- package/sdk-core/core/src/{workflow → worker/workflow}/machines/workflow_machines/local_acts.rs +2 -2
- package/sdk-core/core/src/{workflow → worker/workflow}/machines/workflow_machines.rs +40 -16
- package/sdk-core/core/src/{workflow → worker/workflow}/machines/workflow_task_state_machine.rs +0 -0
- package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +198 -0
- package/sdk-core/core/src/worker/workflow/managed_run.rs +627 -0
- package/sdk-core/core/src/worker/workflow/mod.rs +1115 -0
- package/sdk-core/core/src/worker/workflow/run_cache.rs +143 -0
- package/sdk-core/core/src/worker/workflow/wft_poller.rs +88 -0
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +936 -0
- package/sdk-core/core-api/src/errors.rs +3 -10
- package/sdk-core/core-api/src/lib.rs +2 -1
- package/sdk-core/core-api/src/worker.rs +26 -2
- package/sdk-core/etc/dynamic-config.yaml +2 -0
- package/sdk-core/integ-with-otel.sh +1 -1
- package/sdk-core/protos/api_upstream/Makefile +4 -4
- package/sdk-core/protos/api_upstream/api-linter.yaml +2 -0
- package/sdk-core/protos/api_upstream/buf.yaml +8 -9
- package/sdk-core/protos/api_upstream/temporal/api/cluster/v1/message.proto +83 -0
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +7 -1
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/cluster.proto +40 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +3 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +3 -1
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +60 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +3 -0
- package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +32 -4
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +69 -19
- package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +13 -0
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +163 -0
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +97 -0
- package/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +300 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +25 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +180 -3
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +53 -3
- package/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +2 -2
- package/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +6 -5
- package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +0 -1
- package/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +2 -1
- package/sdk-core/protos/local/temporal/sdk/core/common/common.proto +0 -64
- package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +2 -1
- package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +11 -8
- package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +30 -25
- package/sdk-core/sdk/src/activity_context.rs +12 -5
- package/sdk-core/sdk/src/app_data.rs +37 -0
- package/sdk-core/sdk/src/lib.rs +76 -43
- package/sdk-core/sdk/src/workflow_context/options.rs +8 -6
- package/sdk-core/sdk/src/workflow_context.rs +14 -19
- package/sdk-core/sdk/src/workflow_future.rs +11 -6
- package/sdk-core/sdk-core-protos/src/history_builder.rs +19 -5
- package/sdk-core/sdk-core-protos/src/history_info.rs +11 -6
- package/sdk-core/sdk-core-protos/src/lib.rs +74 -176
- package/sdk-core/test-utils/src/lib.rs +85 -72
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +11 -9
- package/sdk-core/tests/integ_tests/polling_tests.rs +12 -0
- package/sdk-core/tests/integ_tests/queries_tests.rs +39 -22
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +49 -4
- package/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +61 -0
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +74 -13
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +19 -0
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +6 -3
- package/sdk-core/tests/integ_tests/workflow_tests.rs +10 -23
- package/sdk-core/tests/load_tests.rs +8 -3
- package/sdk-core/tests/main.rs +2 -1
- package/src/conversions.rs +47 -39
- package/src/errors.rs +10 -21
- package/src/lib.rs +342 -325
- package/sdk-core/core/src/pending_activations.rs +0 -173
- package/sdk-core/core/src/worker/wft_delivery.rs +0 -81
- package/sdk-core/core/src/workflow/mod.rs +0 -478
- package/sdk-core/core/src/workflow/workflow_tasks/cache_manager.rs +0 -194
- package/sdk-core/core/src/workflow/workflow_tasks/concurrency_manager.rs +0 -418
- package/sdk-core/core/src/workflow/workflow_tasks/mod.rs +0 -989
|
@@ -7,20 +7,12 @@ extern crate tracing;
|
|
|
7
7
|
pub mod canned_histories;
|
|
8
8
|
|
|
9
9
|
use crate::stream::TryStreamExt;
|
|
10
|
-
use futures::{stream, stream::FuturesUnordered, StreamExt};
|
|
10
|
+
use futures::{future, stream, stream::FuturesUnordered, StreamExt};
|
|
11
11
|
use parking_lot::Mutex;
|
|
12
12
|
use prost::Message;
|
|
13
13
|
use rand::{distributions::Standard, Rng};
|
|
14
14
|
use std::{
|
|
15
|
-
convert::TryFrom,
|
|
16
|
-
env,
|
|
17
|
-
future::Future,
|
|
18
|
-
net::SocketAddr,
|
|
19
|
-
path::PathBuf,
|
|
20
|
-
sync::{
|
|
21
|
-
atomic::{AtomicUsize, Ordering},
|
|
22
|
-
Arc,
|
|
23
|
-
},
|
|
15
|
+
convert::TryFrom, env, future::Future, net::SocketAddr, path::PathBuf, sync::Arc,
|
|
24
16
|
time::Duration,
|
|
25
17
|
};
|
|
26
18
|
use temporal_client::{
|
|
@@ -35,14 +27,13 @@ use temporal_sdk_core::{
|
|
|
35
27
|
use temporal_sdk_core_api::Worker as CoreWorker;
|
|
36
28
|
use temporal_sdk_core_protos::{
|
|
37
29
|
coresdk::{
|
|
38
|
-
common::Payload,
|
|
39
30
|
workflow_commands::{
|
|
40
31
|
workflow_command, ActivityCancellationType, CompleteWorkflowExecution,
|
|
41
32
|
ScheduleActivity, StartTimer,
|
|
42
33
|
},
|
|
43
34
|
workflow_completion::WorkflowActivationCompletion,
|
|
44
35
|
},
|
|
45
|
-
temporal::api::history::v1::History,
|
|
36
|
+
temporal::api::{common::v1::Payload, history::v1::History},
|
|
46
37
|
};
|
|
47
38
|
use tokio::sync::OnceCell;
|
|
48
39
|
use url::Url;
|
|
@@ -69,9 +60,11 @@ pub fn init_core_replay_preloaded(
|
|
|
69
60
|
test_name: &str,
|
|
70
61
|
history: &History,
|
|
71
62
|
) -> (Arc<dyn CoreWorker>, String) {
|
|
63
|
+
telemetry_init(&get_integ_telem_options()).expect("Telemetry inits cleanly");
|
|
72
64
|
let worker_cfg = WorkerConfigBuilder::default()
|
|
73
65
|
.namespace(NAMESPACE)
|
|
74
66
|
.task_queue(test_name)
|
|
67
|
+
.worker_build_id("test_bin_id")
|
|
75
68
|
.build()
|
|
76
69
|
.expect("Configuration options construct properly");
|
|
77
70
|
let worker = init_replay_worker(worker_cfg, history).expect("Replay worker must init properly");
|
|
@@ -92,7 +85,7 @@ pub struct CoreWfStarter {
|
|
|
92
85
|
/// Used for both the task queue and workflow id
|
|
93
86
|
task_queue_name: String,
|
|
94
87
|
telemetry_options: TelemetryOptions,
|
|
95
|
-
worker_config: WorkerConfig,
|
|
88
|
+
pub worker_config: WorkerConfig,
|
|
96
89
|
wft_timeout: Option<Duration>,
|
|
97
90
|
initted_worker: OnceCell<InitializedWorker>,
|
|
98
91
|
}
|
|
@@ -116,6 +109,7 @@ impl CoreWfStarter {
|
|
|
116
109
|
worker_config: WorkerConfigBuilder::default()
|
|
117
110
|
.namespace(NAMESPACE)
|
|
118
111
|
.task_queue(task_queue)
|
|
112
|
+
.worker_build_id("test_build_id")
|
|
119
113
|
.max_cached_workflows(1000_usize)
|
|
120
114
|
.build()
|
|
121
115
|
.unwrap(),
|
|
@@ -257,28 +251,29 @@ impl CoreWfStarter {
|
|
|
257
251
|
/// Provides conveniences for running integ tests with the SDK (against real server or mocks)
|
|
258
252
|
pub struct TestWorker {
|
|
259
253
|
inner: Worker,
|
|
260
|
-
pub
|
|
254
|
+
pub core_worker: Arc<dyn CoreWorker>,
|
|
261
255
|
client: Option<Arc<RetryClient<Client>>>,
|
|
262
|
-
|
|
263
|
-
///
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
/// annoying to make work.
|
|
268
|
-
incomplete_workflows: Arc<AtomicUsize>,
|
|
256
|
+
pub started_workflows: Mutex<Vec<WorkflowExecutionInfo>>,
|
|
257
|
+
/// If set true (default), and a client is available, we will fetch workflow results to
|
|
258
|
+
/// determine when they have all completed.
|
|
259
|
+
pub fetch_results: bool,
|
|
260
|
+
iceptor: Option<TestWorkerCompletionIceptor>,
|
|
269
261
|
}
|
|
270
262
|
impl TestWorker {
|
|
271
263
|
/// Create a new test worker
|
|
272
264
|
pub fn new(core_worker: Arc<dyn CoreWorker>, task_queue: impl Into<String>) -> Self {
|
|
273
|
-
let ct = Arc::new(AtomicUsize::new(0));
|
|
274
265
|
let inner = Worker::new_from_core(core_worker.clone(), task_queue);
|
|
266
|
+
let iceptor = TestWorkerCompletionIceptor::new(
|
|
267
|
+
TestWorkerShutdownCond::NoAutoShutdown,
|
|
268
|
+
Arc::new(inner.shutdown_handle()),
|
|
269
|
+
);
|
|
275
270
|
Self {
|
|
276
271
|
inner,
|
|
277
|
-
|
|
272
|
+
core_worker,
|
|
278
273
|
client: None,
|
|
279
|
-
auto_shutdown: true,
|
|
280
274
|
started_workflows: Mutex::new(vec![]),
|
|
281
|
-
|
|
275
|
+
fetch_results: true,
|
|
276
|
+
iceptor: Some(iceptor),
|
|
282
277
|
}
|
|
283
278
|
}
|
|
284
279
|
|
|
@@ -340,70 +335,87 @@ impl TestWorker {
|
|
|
340
335
|
|
|
341
336
|
/// Runs until all expected workflows have completed
|
|
342
337
|
pub async fn run_until_done(&mut self) -> Result<(), anyhow::Error> {
|
|
343
|
-
self.run_until_done_intercepted(Option::<
|
|
338
|
+
self.run_until_done_intercepted(Option::<TestWorkerCompletionIceptor>::None)
|
|
344
339
|
.await
|
|
345
340
|
}
|
|
346
341
|
|
|
347
|
-
/// See [Self::run_until_done],
|
|
348
|
-
/// shutdown.
|
|
342
|
+
/// See [Self::run_until_done], but allows configuration of some low-level interception.
|
|
349
343
|
pub async fn run_until_done_intercepted(
|
|
350
344
|
&mut self,
|
|
351
345
|
interceptor: Option<impl WorkerInterceptor + 'static>,
|
|
352
346
|
) -> Result<(), anyhow::Error> {
|
|
353
|
-
let iceptor =
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
next: interceptor.map(|i| Box::new(i) as Box<dyn WorkerInterceptor>),
|
|
362
|
-
};
|
|
363
|
-
self.inner.set_worker_interceptor(Box::new(iceptor));
|
|
364
|
-
let workflows_complete_fut = async {
|
|
365
|
-
if self.auto_shutdown && self.client.is_some() {
|
|
366
|
-
let wfs = std::mem::take(self.started_workflows.get_mut());
|
|
367
|
-
let client = self.client.clone().expect("Client must exist when running");
|
|
368
|
-
stream::iter(
|
|
369
|
-
wfs.into_iter()
|
|
370
|
-
.map(|info| info.bind_untyped((*client).clone())),
|
|
371
|
-
)
|
|
372
|
-
.map(Ok)
|
|
373
|
-
.try_for_each_concurrent(None, |wh| async move {
|
|
374
|
-
wh.get_workflow_result(Default::default()).await?;
|
|
375
|
-
Ok::<_, anyhow::Error>(())
|
|
376
|
-
})
|
|
377
|
-
.await?;
|
|
378
|
-
self.orig_core_worker.initiate_shutdown();
|
|
347
|
+
let mut iceptor = self.iceptor.take().unwrap();
|
|
348
|
+
// Automatically use results-based complete detection if we have a client
|
|
349
|
+
if self.fetch_results {
|
|
350
|
+
if let Some(c) = self.client.clone() {
|
|
351
|
+
iceptor.condition = TestWorkerShutdownCond::GetResults(
|
|
352
|
+
std::mem::take(&mut self.started_workflows.lock()),
|
|
353
|
+
c,
|
|
354
|
+
);
|
|
379
355
|
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
356
|
+
}
|
|
357
|
+
iceptor.next = interceptor.map(|i| Box::new(i) as Box<dyn WorkerInterceptor>);
|
|
358
|
+
let get_results_waiter = iceptor.wait_all_wfs();
|
|
359
|
+
self.inner.set_worker_interceptor(Box::new(iceptor));
|
|
360
|
+
tokio::try_join!(self.inner.run(), get_results_waiter)?;
|
|
383
361
|
Ok(())
|
|
384
362
|
}
|
|
385
363
|
}
|
|
386
364
|
|
|
365
|
+
pub enum TestWorkerShutdownCond {
|
|
366
|
+
GetResults(Vec<WorkflowExecutionInfo>, Arc<RetryClient<Client>>),
|
|
367
|
+
NoAutoShutdown,
|
|
368
|
+
}
|
|
387
369
|
/// Implements calling the shutdown handle when the expected number of test workflows has completed
|
|
388
|
-
struct
|
|
389
|
-
|
|
390
|
-
shutdown_handle:
|
|
370
|
+
pub struct TestWorkerCompletionIceptor {
|
|
371
|
+
condition: TestWorkerShutdownCond,
|
|
372
|
+
shutdown_handle: Arc<dyn Fn()>,
|
|
373
|
+
every_activation: Option<Box<dyn Fn(&WorkflowActivationCompletion)>>,
|
|
391
374
|
next: Option<Box<dyn WorkerInterceptor>>,
|
|
392
375
|
}
|
|
376
|
+
impl TestWorkerCompletionIceptor {
|
|
377
|
+
pub fn new(condition: TestWorkerShutdownCond, shutdown_handle: Arc<dyn Fn()>) -> Self {
|
|
378
|
+
Self {
|
|
379
|
+
condition,
|
|
380
|
+
shutdown_handle,
|
|
381
|
+
every_activation: None,
|
|
382
|
+
next: None,
|
|
383
|
+
}
|
|
384
|
+
}
|
|
393
385
|
|
|
386
|
+
fn wait_all_wfs(&mut self) -> impl Future<Output = Result<(), anyhow::Error>> + 'static {
|
|
387
|
+
if let TestWorkerShutdownCond::GetResults(ref mut wfs, ref client) = self.condition {
|
|
388
|
+
let wfs = std::mem::take(wfs);
|
|
389
|
+
let shutdown_h = self.shutdown_handle.clone();
|
|
390
|
+
let client = (**client).clone();
|
|
391
|
+
let stream = stream::iter(
|
|
392
|
+
wfs.into_iter()
|
|
393
|
+
.map(move |info| info.bind_untyped(client.clone())),
|
|
394
|
+
)
|
|
395
|
+
.map(Ok);
|
|
396
|
+
future::Either::Left(async move {
|
|
397
|
+
stream
|
|
398
|
+
.try_for_each_concurrent(None, |wh| async move {
|
|
399
|
+
wh.get_workflow_result(Default::default()).await?;
|
|
400
|
+
Ok::<_, anyhow::Error>(())
|
|
401
|
+
})
|
|
402
|
+
.await?;
|
|
403
|
+
shutdown_h();
|
|
404
|
+
Ok(())
|
|
405
|
+
})
|
|
406
|
+
} else {
|
|
407
|
+
future::Either::Right(future::ready(Ok(())))
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
394
411
|
#[async_trait::async_trait(?Send)]
|
|
395
|
-
impl WorkerInterceptor for
|
|
412
|
+
impl WorkerInterceptor for TestWorkerCompletionIceptor {
|
|
396
413
|
async fn on_workflow_activation_completion(&self, completion: &WorkflowActivationCompletion) {
|
|
414
|
+
if let Some(func) = self.every_activation.as_ref() {
|
|
415
|
+
func(completion);
|
|
416
|
+
}
|
|
397
417
|
if completion.has_execution_ending() {
|
|
398
418
|
info!("Workflow {} says it's finishing", &completion.run_id);
|
|
399
|
-
let prev = self.incomplete_workflows.fetch_sub(1, Ordering::SeqCst);
|
|
400
|
-
if prev <= 1 {
|
|
401
|
-
if let Some(sh) = self.shutdown_handle.as_ref() {
|
|
402
|
-
info!("Test worker calling shutdown");
|
|
403
|
-
// There are now zero, we just subtracted one
|
|
404
|
-
sh()
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
419
|
}
|
|
408
420
|
if let Some(n) = self.next.as_ref() {
|
|
409
421
|
n.on_workflow_activation_completion(completion).await;
|
|
@@ -425,7 +437,6 @@ pub fn get_integ_server_options() -> ClientOptions {
|
|
|
425
437
|
let url = Url::try_from(&*temporal_server_address).unwrap();
|
|
426
438
|
ClientOptionsBuilder::default()
|
|
427
439
|
.identity("integ_tester".to_string())
|
|
428
|
-
.worker_binary_id("fakebinaryid".to_string())
|
|
429
440
|
.target_url(url)
|
|
430
441
|
.client_name("temporal-core".to_string())
|
|
431
442
|
.client_version("0.1.0".to_string())
|
|
@@ -439,10 +450,12 @@ pub fn get_integ_telem_options() -> TelemetryOptions {
|
|
|
439
450
|
.ok()
|
|
440
451
|
.map(|x| x.parse::<Url>().unwrap())
|
|
441
452
|
{
|
|
442
|
-
|
|
453
|
+
let opts = OtelCollectorOptions {
|
|
443
454
|
url,
|
|
444
455
|
headers: Default::default(),
|
|
445
|
-
}
|
|
456
|
+
};
|
|
457
|
+
ob.tracing(TraceExporter::Otel(opts.clone()));
|
|
458
|
+
ob.metrics(MetricsExporter::Otel(opts));
|
|
446
459
|
}
|
|
447
460
|
if let Some(addr) = env::var(PROM_ENABLE_ENV_VAR)
|
|
448
461
|
.ok()
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
use assert_matches::assert_matches;
|
|
2
2
|
use std::time::Duration;
|
|
3
|
-
use temporal_sdk_core_protos::
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
use temporal_sdk_core_protos::{
|
|
4
|
+
coresdk::{
|
|
5
|
+
activity_result::{
|
|
6
|
+
self, activity_resolution as act_res, ActivityExecutionResult, ActivityResolution,
|
|
7
|
+
},
|
|
8
|
+
activity_task::activity_task,
|
|
9
|
+
workflow_activation::{workflow_activation_job, ResolveActivity, WorkflowActivationJob},
|
|
10
|
+
workflow_commands::{ActivityCancellationType, ScheduleActivity},
|
|
11
|
+
workflow_completion::WorkflowActivationCompletion,
|
|
12
|
+
ActivityHeartbeat, ActivityTaskCompletion, IntoCompletion,
|
|
6
13
|
},
|
|
7
|
-
|
|
8
|
-
common::{Payload, RetryPolicy},
|
|
9
|
-
workflow_activation::{workflow_activation_job, ResolveActivity, WorkflowActivationJob},
|
|
10
|
-
workflow_commands::{ActivityCancellationType, ScheduleActivity},
|
|
11
|
-
workflow_completion::WorkflowActivationCompletion,
|
|
12
|
-
ActivityHeartbeat, ActivityTaskCompletion, IntoCompletion,
|
|
14
|
+
temporal::api::common::v1::{Payload, RetryPolicy},
|
|
13
15
|
};
|
|
14
16
|
use temporal_sdk_core_test_utils::{
|
|
15
17
|
init_core_and_create_wf, schedule_activity_cmd, WorkerTestHelpers,
|
|
@@ -3,6 +3,7 @@ use futures::future::join_all;
|
|
|
3
3
|
use std::time::Duration;
|
|
4
4
|
use temporal_client::WorkflowOptions;
|
|
5
5
|
use temporal_sdk::{WfContext, WorkflowResult};
|
|
6
|
+
use temporal_sdk_core_api::errors::PollWfError;
|
|
6
7
|
use temporal_sdk_core_protos::coresdk::{
|
|
7
8
|
activity_task::activity_task as act_task,
|
|
8
9
|
workflow_activation::{workflow_activation_job, FireTimer, WorkflowActivationJob},
|
|
@@ -131,3 +132,14 @@ async fn can_paginate_long_history() {
|
|
|
131
132
|
.unwrap();
|
|
132
133
|
worker.run_until_done().await.unwrap();
|
|
133
134
|
}
|
|
135
|
+
|
|
136
|
+
#[tokio::test]
|
|
137
|
+
async fn poll_of_nonexistent_namespace_is_fatal() {
|
|
138
|
+
let mut starter = CoreWfStarter::new("whatever_yo");
|
|
139
|
+
starter.worker_config.namespace = "I do not exist".to_string();
|
|
140
|
+
let worker = starter.get_worker().await;
|
|
141
|
+
assert_matches!(
|
|
142
|
+
worker.poll_workflow_activation().await,
|
|
143
|
+
Err(PollWfError::TonicError(_))
|
|
144
|
+
);
|
|
145
|
+
}
|
|
@@ -112,7 +112,7 @@ async fn simple_query_legacy() {
|
|
|
112
112
|
async fn query_after_execution_complete(#[case] do_evict: bool) {
|
|
113
113
|
let query_resp = b"response";
|
|
114
114
|
let mut starter =
|
|
115
|
-
init_core_and_create_wf(&format!("
|
|
115
|
+
init_core_and_create_wf(&format!("query_after_execution_complete-{}", do_evict)).await;
|
|
116
116
|
let core = &starter.get_worker().await;
|
|
117
117
|
let workflow_id = &starter.get_task_queue().to_string();
|
|
118
118
|
|
|
@@ -156,19 +156,19 @@ async fn query_after_execution_complete(#[case] do_evict: bool) {
|
|
|
156
156
|
.unwrap();
|
|
157
157
|
continue;
|
|
158
158
|
}
|
|
159
|
-
|
|
159
|
+
if matches!(
|
|
160
160
|
task.jobs.as_slice(),
|
|
161
161
|
[WorkflowActivationJob {
|
|
162
162
|
variant: Some(workflow_activation_job::Variant::StartWorkflow(_)),
|
|
163
163
|
}]
|
|
164
|
-
)
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
164
|
+
) {
|
|
165
|
+
core.complete_timer(&task.run_id, 1, Duration::from_millis(500))
|
|
166
|
+
.await;
|
|
167
|
+
} else {
|
|
168
|
+
core.complete_execution(&task.run_id).await;
|
|
169
|
+
}
|
|
170
170
|
if !go_until_query {
|
|
171
|
-
break run_id;
|
|
171
|
+
break task.run_id;
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
174
|
};
|
|
@@ -205,6 +205,7 @@ async fn query_after_execution_complete(#[case] do_evict: bool) {
|
|
|
205
205
|
query_futs.push(do_workflow(true).map(|_| ()).boxed());
|
|
206
206
|
}
|
|
207
207
|
while query_futs.next().await.is_some() {}
|
|
208
|
+
core.shutdown().await;
|
|
208
209
|
}
|
|
209
210
|
|
|
210
211
|
#[ignore]
|
|
@@ -339,20 +340,21 @@ async fn fail_legacy_query() {
|
|
|
339
340
|
let core = starter.get_worker().await;
|
|
340
341
|
let workflow_id = starter.get_task_queue().to_string();
|
|
341
342
|
let task = core.poll_workflow_activation().await.unwrap();
|
|
343
|
+
let t1_resp = vec![
|
|
344
|
+
StartTimer {
|
|
345
|
+
seq: 1,
|
|
346
|
+
start_to_fire_timeout: Some(Duration::from_millis(500).into()),
|
|
347
|
+
}
|
|
348
|
+
.into(),
|
|
349
|
+
StartTimer {
|
|
350
|
+
seq: 2,
|
|
351
|
+
start_to_fire_timeout: Some(Duration::from_secs(3).into()),
|
|
352
|
+
}
|
|
353
|
+
.into(),
|
|
354
|
+
];
|
|
342
355
|
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
|
|
343
356
|
task.run_id.clone(),
|
|
344
|
-
|
|
345
|
-
StartTimer {
|
|
346
|
-
seq: 1,
|
|
347
|
-
start_to_fire_timeout: Some(Duration::from_millis(500).into()),
|
|
348
|
-
}
|
|
349
|
-
.into(),
|
|
350
|
-
StartTimer {
|
|
351
|
-
seq: 2,
|
|
352
|
-
start_to_fire_timeout: Some(Duration::from_secs(3).into()),
|
|
353
|
-
}
|
|
354
|
-
.into(),
|
|
355
|
-
],
|
|
357
|
+
t1_resp.clone(),
|
|
356
358
|
))
|
|
357
359
|
.await
|
|
358
360
|
.unwrap();
|
|
@@ -410,7 +412,22 @@ async fn fail_legacy_query() {
|
|
|
410
412
|
))
|
|
411
413
|
.await
|
|
412
414
|
.unwrap();
|
|
413
|
-
// Finish the workflow
|
|
415
|
+
// Finish the workflow (handling cache removal)
|
|
416
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
417
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::empty(task.run_id))
|
|
418
|
+
.await
|
|
419
|
+
.unwrap();
|
|
420
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
421
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
|
|
422
|
+
task.run_id,
|
|
423
|
+
t1_resp.clone(),
|
|
424
|
+
))
|
|
425
|
+
.await
|
|
426
|
+
.unwrap();
|
|
427
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
428
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::empty(task.run_id))
|
|
429
|
+
.await
|
|
430
|
+
.unwrap();
|
|
414
431
|
let task = core.poll_workflow_activation().await.unwrap();
|
|
415
432
|
core.complete_execution(&task.run_id).await;
|
|
416
433
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
use assert_matches::assert_matches;
|
|
2
2
|
use std::time::Duration;
|
|
3
3
|
use temporal_client::{WfClientExt, WorkflowClientTrait, WorkflowExecutionResult, WorkflowOptions};
|
|
4
|
-
use temporal_sdk::{ActContext, ActivityOptions, WfContext, WorkflowResult};
|
|
4
|
+
use temporal_sdk::{ActContext, ActivityOptions, CancellableFuture, WfContext, WorkflowResult};
|
|
5
5
|
use temporal_sdk_core_protos::{
|
|
6
6
|
coresdk::{
|
|
7
7
|
activity_result::{
|
|
@@ -9,7 +9,6 @@ use temporal_sdk_core_protos::{
|
|
|
9
9
|
ActivityResolution,
|
|
10
10
|
},
|
|
11
11
|
activity_task::activity_task as act_task,
|
|
12
|
-
common::Payload,
|
|
13
12
|
workflow_activation::{
|
|
14
13
|
workflow_activation_job, FireTimer, ResolveActivity, WorkflowActivationJob,
|
|
15
14
|
},
|
|
@@ -18,7 +17,7 @@ use temporal_sdk_core_protos::{
|
|
|
18
17
|
ActivityHeartbeat, ActivityTaskCompletion, AsJsonPayloadExt, IntoCompletion,
|
|
19
18
|
},
|
|
20
19
|
temporal::api::{
|
|
21
|
-
common::v1::{ActivityType, Payloads},
|
|
20
|
+
common::v1::{ActivityType, Payload, Payloads},
|
|
22
21
|
enums::v1::RetryState,
|
|
23
22
|
failure::v1::{failure::FailureInfo, ActivityFailureInfo, Failure},
|
|
24
23
|
},
|
|
@@ -663,7 +662,7 @@ async fn async_activity_completion_workflow() {
|
|
|
663
662
|
.complete_activity_task(
|
|
664
663
|
task.task_token.into(),
|
|
665
664
|
Some(Payloads {
|
|
666
|
-
payloads: vec![response_payload.clone()
|
|
665
|
+
payloads: vec![response_payload.clone()],
|
|
667
666
|
}),
|
|
668
667
|
)
|
|
669
668
|
.await
|
|
@@ -748,3 +747,49 @@ async fn activity_cancelled_after_heartbeat_times_out() {
|
|
|
748
747
|
.await
|
|
749
748
|
.unwrap();
|
|
750
749
|
}
|
|
750
|
+
|
|
751
|
+
#[tokio::test]
|
|
752
|
+
async fn one_activity_abandon_cancelled_after_complete() {
|
|
753
|
+
let wf_name = "one_activity_abandon_cancelled_after_complete";
|
|
754
|
+
let mut starter = CoreWfStarter::new(wf_name);
|
|
755
|
+
let mut worker = starter.worker().await;
|
|
756
|
+
let client = starter.get_client().await;
|
|
757
|
+
worker.register_wf(wf_name.to_owned(), |ctx: WfContext| async move {
|
|
758
|
+
let act_fut = ctx.activity(ActivityOptions {
|
|
759
|
+
activity_type: "echo_activity".to_string(),
|
|
760
|
+
start_to_close_timeout: Some(Duration::from_secs(5)),
|
|
761
|
+
input: "hi!".as_json_payload().expect("serializes fine"),
|
|
762
|
+
cancellation_type: ActivityCancellationType::Abandon,
|
|
763
|
+
..Default::default()
|
|
764
|
+
});
|
|
765
|
+
ctx.timer(Duration::from_secs(1)).await;
|
|
766
|
+
act_fut.cancel(&ctx);
|
|
767
|
+
ctx.timer(Duration::from_secs(3)).await;
|
|
768
|
+
act_fut.await;
|
|
769
|
+
Ok(().into())
|
|
770
|
+
});
|
|
771
|
+
worker.register_activity(
|
|
772
|
+
"echo_activity",
|
|
773
|
+
|_ctx: ActContext, echo_me: String| async move {
|
|
774
|
+
sleep(Duration::from_secs(2)).await;
|
|
775
|
+
Ok(echo_me)
|
|
776
|
+
},
|
|
777
|
+
);
|
|
778
|
+
|
|
779
|
+
let run_id = worker
|
|
780
|
+
.submit_wf(
|
|
781
|
+
wf_name.to_owned(),
|
|
782
|
+
wf_name.to_owned(),
|
|
783
|
+
vec![],
|
|
784
|
+
WorkflowOptions::default(),
|
|
785
|
+
)
|
|
786
|
+
.await
|
|
787
|
+
.unwrap();
|
|
788
|
+
worker.run_until_done().await.unwrap();
|
|
789
|
+
let handle = client.get_untyped_workflow_handle(wf_name, run_id);
|
|
790
|
+
let res = handle
|
|
791
|
+
.get_workflow_result(Default::default())
|
|
792
|
+
.await
|
|
793
|
+
.unwrap();
|
|
794
|
+
assert_matches!(res, WorkflowExecutionResult::Succeeded(_));
|
|
795
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
use assert_matches::assert_matches;
|
|
2
|
+
use std::time::Duration;
|
|
3
|
+
use temporal_client::{WfClientExt, WorkflowExecutionResult, WorkflowOptions};
|
|
4
|
+
use temporal_sdk::{ActContext, ActivityOptions, WfContext, WorkflowResult};
|
|
5
|
+
use temporal_sdk_core_protos::coresdk::AsJsonPayloadExt;
|
|
6
|
+
use temporal_sdk_core_test_utils::CoreWfStarter;
|
|
7
|
+
|
|
8
|
+
const TEST_APPDATA_MESSAGE: &str = "custom app data, yay";
|
|
9
|
+
|
|
10
|
+
struct Data {
|
|
11
|
+
message: String,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
pub async fn appdata_activity_wf(ctx: WfContext) -> WorkflowResult<()> {
|
|
15
|
+
ctx.activity(ActivityOptions {
|
|
16
|
+
activity_type: "echo_activity".to_string(),
|
|
17
|
+
start_to_close_timeout: Some(Duration::from_secs(5)),
|
|
18
|
+
input: "hi!".as_json_payload().expect("serializes fine"),
|
|
19
|
+
..Default::default()
|
|
20
|
+
})
|
|
21
|
+
.await;
|
|
22
|
+
Ok(().into())
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#[tokio::test]
|
|
26
|
+
async fn appdata_access_in_activities_and_workflows() {
|
|
27
|
+
let wf_name = "appdata_activity";
|
|
28
|
+
let mut starter = CoreWfStarter::new(wf_name);
|
|
29
|
+
let mut worker = starter.worker().await;
|
|
30
|
+
worker.inner_mut().insert_app_data(Data {
|
|
31
|
+
message: TEST_APPDATA_MESSAGE.to_owned(),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
let client = starter.get_client().await;
|
|
35
|
+
worker.register_wf(wf_name.to_owned(), appdata_activity_wf);
|
|
36
|
+
worker.register_activity(
|
|
37
|
+
"echo_activity",
|
|
38
|
+
|ctx: ActContext, echo_me: String| async move {
|
|
39
|
+
let data = ctx.app_data::<Data>().expect("appdata exists. qed");
|
|
40
|
+
assert_eq!(data.message, TEST_APPDATA_MESSAGE.to_owned());
|
|
41
|
+
Ok(echo_me)
|
|
42
|
+
},
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
let run_id = worker
|
|
46
|
+
.submit_wf(
|
|
47
|
+
wf_name.to_owned(),
|
|
48
|
+
wf_name.to_owned(),
|
|
49
|
+
vec![],
|
|
50
|
+
WorkflowOptions::default(),
|
|
51
|
+
)
|
|
52
|
+
.await
|
|
53
|
+
.unwrap();
|
|
54
|
+
worker.run_until_done().await.unwrap();
|
|
55
|
+
let handle = client.get_untyped_workflow_handle(wf_name, run_id);
|
|
56
|
+
let res = handle
|
|
57
|
+
.get_workflow_result(Default::default())
|
|
58
|
+
.await
|
|
59
|
+
.unwrap();
|
|
60
|
+
assert_matches!(res, WorkflowExecutionResult::Succeeded(_));
|
|
61
|
+
}
|
|
@@ -39,7 +39,7 @@ async fn cancel_during_timer() {
|
|
|
39
39
|
tokio::time::sleep(Duration::from_millis(500)).await;
|
|
40
40
|
// Cancel the workflow externally
|
|
41
41
|
client
|
|
42
|
-
.cancel_workflow_execution(wf_name.to_string(), None)
|
|
42
|
+
.cancel_workflow_execution(wf_name.to_string(), None, "Dieee".to_string())
|
|
43
43
|
.await
|
|
44
44
|
.unwrap();
|
|
45
45
|
};
|
|
@@ -6,9 +6,12 @@ use temporal_sdk::{
|
|
|
6
6
|
interceptors::WorkerInterceptor, ActContext, ActivityCancelledError, CancellableFuture,
|
|
7
7
|
LocalActivityOptions, WfContext, WorkflowResult,
|
|
8
8
|
};
|
|
9
|
-
use temporal_sdk_core_protos::
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
use temporal_sdk_core_protos::{
|
|
10
|
+
coresdk::{
|
|
11
|
+
workflow_commands::ActivityCancellationType,
|
|
12
|
+
workflow_completion::WorkflowActivationCompletion, AsJsonPayloadExt,
|
|
13
|
+
},
|
|
14
|
+
temporal::api::common::v1::RetryPolicy,
|
|
12
15
|
};
|
|
13
16
|
use temporal_sdk_core_test_utils::CoreWfStarter;
|
|
14
17
|
use tokio_util::sync::CancellationToken;
|
|
@@ -494,12 +497,15 @@ async fn schedule_to_close_timeout_across_timer_backoff(#[case] cached: bool) {
|
|
|
494
497
|
worker.run_until_done().await.unwrap();
|
|
495
498
|
}
|
|
496
499
|
|
|
500
|
+
#[rstest::rstest]
|
|
497
501
|
#[tokio::test]
|
|
498
|
-
async fn eviction_wont_make_local_act_get_dropped() {
|
|
499
|
-
let wf_name =
|
|
500
|
-
|
|
502
|
+
async fn eviction_wont_make_local_act_get_dropped(#[values(true, false)] short_wft_timeout: bool) {
|
|
503
|
+
let wf_name = format!(
|
|
504
|
+
"eviction_wont_make_local_act_get_dropped_{}",
|
|
505
|
+
short_wft_timeout
|
|
506
|
+
);
|
|
507
|
+
let mut starter = CoreWfStarter::new(&wf_name);
|
|
501
508
|
starter.max_cached_workflows(0);
|
|
502
|
-
starter.wft_timeout(Duration::from_secs(1));
|
|
503
509
|
let mut worker = starter.worker().await;
|
|
504
510
|
worker.register_wf(wf_name.to_owned(), local_act_then_timer_then_wait);
|
|
505
511
|
worker.register_activity("echo_activity", |_ctx: ActContext, str: String| async {
|
|
@@ -507,13 +513,16 @@ async fn eviction_wont_make_local_act_get_dropped() {
|
|
|
507
513
|
Ok(str)
|
|
508
514
|
});
|
|
509
515
|
|
|
516
|
+
let opts = if short_wft_timeout {
|
|
517
|
+
WorkflowOptions {
|
|
518
|
+
task_timeout: Some(Duration::from_secs(1)),
|
|
519
|
+
..Default::default()
|
|
520
|
+
}
|
|
521
|
+
} else {
|
|
522
|
+
Default::default()
|
|
523
|
+
};
|
|
510
524
|
worker
|
|
511
|
-
.submit_wf(
|
|
512
|
-
wf_name.to_owned(),
|
|
513
|
-
wf_name.to_owned(),
|
|
514
|
-
vec![],
|
|
515
|
-
WorkflowOptions::default(),
|
|
516
|
-
)
|
|
525
|
+
.submit_wf(wf_name.to_owned(), wf_name.to_owned(), vec![], opts)
|
|
517
526
|
.await
|
|
518
527
|
.unwrap();
|
|
519
528
|
worker.run_until_done().await.unwrap();
|
|
@@ -571,3 +580,55 @@ async fn timer_backoff_concurrent_with_non_timer_backoff() {
|
|
|
571
580
|
.unwrap();
|
|
572
581
|
worker.run_until_done().await.unwrap();
|
|
573
582
|
}
|
|
583
|
+
|
|
584
|
+
#[tokio::test]
|
|
585
|
+
async fn repro_nondeterminism_with_timer_bug() {
|
|
586
|
+
let wf_name = "repro_nondeterminism_with_timer_bug";
|
|
587
|
+
let mut starter = CoreWfStarter::new(wf_name);
|
|
588
|
+
let mut worker = starter.worker().await;
|
|
589
|
+
|
|
590
|
+
worker.register_wf(wf_name.to_owned(), |ctx: WfContext| async move {
|
|
591
|
+
let t1 = ctx.timer(Duration::from_secs(30));
|
|
592
|
+
let r1 = ctx.local_activity(LocalActivityOptions {
|
|
593
|
+
activity_type: "delay".to_string(),
|
|
594
|
+
input: "hi".as_json_payload().expect("serializes fine"),
|
|
595
|
+
retry_policy: RetryPolicy {
|
|
596
|
+
initial_interval: Some(Duration::from_micros(15).into()),
|
|
597
|
+
backoff_coefficient: 1_000.,
|
|
598
|
+
maximum_interval: Some(Duration::from_millis(1500).into()),
|
|
599
|
+
maximum_attempts: 4,
|
|
600
|
+
non_retryable_error_types: vec![],
|
|
601
|
+
},
|
|
602
|
+
timer_backoff_threshold: Some(Duration::from_secs(1)),
|
|
603
|
+
..Default::default()
|
|
604
|
+
});
|
|
605
|
+
tokio::pin!(t1);
|
|
606
|
+
tokio::select! {
|
|
607
|
+
_ = &mut t1 => {},
|
|
608
|
+
_ = r1 => {
|
|
609
|
+
t1.cancel(&ctx);
|
|
610
|
+
},
|
|
611
|
+
};
|
|
612
|
+
ctx.timer(Duration::from_secs(1)).await;
|
|
613
|
+
Ok(().into())
|
|
614
|
+
});
|
|
615
|
+
worker.register_activity("delay", |_: ActContext, _: String| async {
|
|
616
|
+
tokio::time::sleep(Duration::from_secs(2)).await;
|
|
617
|
+
Ok(())
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
let run_id = worker
|
|
621
|
+
.submit_wf(
|
|
622
|
+
wf_name.to_owned(),
|
|
623
|
+
wf_name.to_owned(),
|
|
624
|
+
vec![],
|
|
625
|
+
WorkflowOptions::default(),
|
|
626
|
+
)
|
|
627
|
+
.await
|
|
628
|
+
.unwrap();
|
|
629
|
+
worker.run_until_done().await.unwrap();
|
|
630
|
+
starter
|
|
631
|
+
.fetch_history_and_replay(wf_name, run_id, worker.inner_mut())
|
|
632
|
+
.await
|
|
633
|
+
.unwrap();
|
|
634
|
+
}
|