@temporalio/core-bridge 0.15.0 → 0.17.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 +13 -12
- package/index.d.ts +14 -0
- package/index.node +0 -0
- package/package.json +7 -5
- 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/scripts/build.js +70 -33
- package/sdk-core/Cargo.toml +1 -0
- package/sdk-core/fsm/rustfsm_procmacro/Cargo.toml +1 -1
- package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +8 -9
- package/sdk-core/fsm/rustfsm_trait/Cargo.toml +1 -1
- package/sdk-core/fsm/rustfsm_trait/src/lib.rs +1 -1
- package/sdk-core/sdk-core-protos/src/lib.rs +36 -48
- package/sdk-core/src/core_tests/activity_tasks.rs +5 -5
- package/sdk-core/src/core_tests/child_workflows.rs +55 -29
- package/sdk-core/src/core_tests/mod.rs +3 -3
- package/sdk-core/src/core_tests/retry.rs +14 -8
- package/sdk-core/src/core_tests/workflow_tasks.rs +244 -2
- package/sdk-core/src/errors.rs +11 -9
- package/sdk-core/src/lib.rs +12 -2
- package/sdk-core/src/machines/activity_state_machine.rs +44 -5
- package/sdk-core/src/machines/child_workflow_state_machine.rs +31 -11
- package/sdk-core/src/machines/complete_workflow_state_machine.rs +1 -1
- package/sdk-core/src/machines/continue_as_new_workflow_state_machine.rs +1 -1
- package/sdk-core/src/machines/mod.rs +18 -23
- package/sdk-core/src/machines/patch_state_machine.rs +8 -8
- package/sdk-core/src/machines/signal_external_state_machine.rs +22 -1
- package/sdk-core/src/machines/timer_state_machine.rs +21 -3
- package/sdk-core/src/machines/transition_coverage.rs +3 -3
- package/sdk-core/src/machines/workflow_machines.rs +11 -11
- package/sdk-core/src/pending_activations.rs +19 -20
- package/sdk-core/src/pollers/gateway.rs +15 -7
- package/sdk-core/src/pollers/poll_buffer.rs +6 -5
- package/sdk-core/src/pollers/retry.rs +7 -5
- package/sdk-core/src/prototype_rust_sdk/workflow_context.rs +61 -46
- package/sdk-core/src/prototype_rust_sdk/workflow_future.rs +13 -12
- package/sdk-core/src/prototype_rust_sdk.rs +16 -22
- package/sdk-core/src/telemetry/metrics.rs +2 -4
- package/sdk-core/src/telemetry/mod.rs +6 -7
- package/sdk-core/src/test_help/canned_histories.rs +16 -93
- package/sdk-core/src/test_help/history_builder.rs +61 -2
- package/sdk-core/src/test_help/history_info.rs +21 -2
- package/sdk-core/src/test_help/mod.rs +24 -33
- package/sdk-core/src/worker/activities/activity_heartbeat_manager.rs +246 -138
- package/sdk-core/src/worker/activities.rs +46 -45
- package/sdk-core/src/worker/config.rs +11 -0
- package/sdk-core/src/worker/dispatcher.rs +5 -5
- package/sdk-core/src/worker/mod.rs +46 -28
- package/sdk-core/src/workflow/driven_workflow.rs +3 -3
- package/sdk-core/src/workflow/history_update.rs +1 -1
- package/sdk-core/src/workflow/mod.rs +1 -1
- package/sdk-core/src/workflow/workflow_tasks/cache_manager.rs +13 -17
- package/sdk-core/src/workflow/workflow_tasks/concurrency_manager.rs +4 -8
- package/sdk-core/src/workflow/workflow_tasks/mod.rs +14 -19
- package/sdk-core/test_utils/src/lib.rs +2 -2
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +61 -1
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +2 -2
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +2 -2
- package/src/conversions.rs +17 -0
- package/releases/x86_64-pc-windows-gnu/index.node +0 -0
|
@@ -21,7 +21,7 @@ use crate::{
|
|
|
21
21
|
use crossbeam::queue::SegQueue;
|
|
22
22
|
use futures::FutureExt;
|
|
23
23
|
use parking_lot::Mutex;
|
|
24
|
-
use std::{fmt::Debug,
|
|
24
|
+
use std::{fmt::Debug, time::Instant};
|
|
25
25
|
use temporal_sdk_core_protos::coresdk::{
|
|
26
26
|
workflow_activation::{
|
|
27
27
|
create_evict_activation, create_query_activation, wf_activation_job, QueryWorkflow,
|
|
@@ -77,9 +77,9 @@ pub(crate) enum OutstandingActivation {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
impl OutstandingActivation {
|
|
80
|
-
fn has_eviction(
|
|
80
|
+
const fn has_eviction(self) -> bool {
|
|
81
81
|
matches!(
|
|
82
|
-
|
|
82
|
+
self,
|
|
83
83
|
OutstandingActivation::Normal {
|
|
84
84
|
contains_eviction: true
|
|
85
85
|
}
|
|
@@ -303,13 +303,13 @@ impl WorkflowTaskManager {
|
|
|
303
303
|
)
|
|
304
304
|
.expect("Workflow machines must exist, we just created/updated them");
|
|
305
305
|
|
|
306
|
-
if
|
|
306
|
+
if next_activation.jobs.is_empty() {
|
|
307
|
+
NewWfTaskOutcome::Autocomplete
|
|
308
|
+
} else {
|
|
307
309
|
if let Err(wme) = self.insert_outstanding_activation(&next_activation) {
|
|
308
310
|
return NewWfTaskOutcome::Evict(wme.into());
|
|
309
311
|
}
|
|
310
312
|
NewWfTaskOutcome::IssueActivation(next_activation)
|
|
311
|
-
} else {
|
|
312
|
-
NewWfTaskOutcome::Autocomplete
|
|
313
313
|
}
|
|
314
314
|
}
|
|
315
315
|
|
|
@@ -406,7 +406,9 @@ impl WorkflowTaskManager {
|
|
|
406
406
|
query_responses,
|
|
407
407
|
},
|
|
408
408
|
})
|
|
409
|
-
} else if
|
|
409
|
+
} else if query_responses.is_empty() {
|
|
410
|
+
None
|
|
411
|
+
} else {
|
|
410
412
|
Some(ServerCommandsWithWorkflowInfo {
|
|
411
413
|
task_token,
|
|
412
414
|
action: ActivationAction::WftComplete {
|
|
@@ -414,8 +416,6 @@ impl WorkflowTaskManager {
|
|
|
414
416
|
query_responses,
|
|
415
417
|
},
|
|
416
418
|
})
|
|
417
|
-
} else {
|
|
418
|
-
None
|
|
419
419
|
}
|
|
420
420
|
};
|
|
421
421
|
Ok(ret)
|
|
@@ -447,13 +447,9 @@ impl WorkflowTaskManager {
|
|
|
447
447
|
FailedActivationOutcome::ReportLegacyQueryFailure(tt)
|
|
448
448
|
} else {
|
|
449
449
|
// Blow up any cached data associated with the workflow
|
|
450
|
-
let should_report =
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
attempt <= 1
|
|
454
|
-
} else {
|
|
455
|
-
true
|
|
456
|
-
};
|
|
450
|
+
let should_report = self
|
|
451
|
+
.request_eviction(run_id, "Activation failed by lang")
|
|
452
|
+
.map_or(true, |attempt| attempt <= 1);
|
|
457
453
|
if should_report {
|
|
458
454
|
FailedActivationOutcome::Report(tt)
|
|
459
455
|
} else {
|
|
@@ -541,11 +537,10 @@ impl WorkflowTaskManager {
|
|
|
541
537
|
if !just_evicted {
|
|
542
538
|
// Check if there was a legacy query which must be fulfilled, and if there is create
|
|
543
539
|
// a new pending activation for it.
|
|
544
|
-
if let Some(ref mut ot) = self
|
|
540
|
+
if let Some(ref mut ot) = &mut *self
|
|
545
541
|
.workflow_machines
|
|
546
542
|
.get_task_mut(run_id)
|
|
547
543
|
.expect("Machine must exist")
|
|
548
|
-
.deref_mut()
|
|
549
544
|
{
|
|
550
545
|
if let Some(query) = ot.legacy_query.take() {
|
|
551
546
|
let na = create_query_activation(run_id.to_string(), [query]);
|
|
@@ -623,7 +618,7 @@ impl WorkflowTaskManager {
|
|
|
623
618
|
fn activation_has_eviction(&self, run_id: &str) -> bool {
|
|
624
619
|
self.workflow_machines
|
|
625
620
|
.get_activation(run_id)
|
|
626
|
-
.map(
|
|
621
|
+
.map(OutstandingActivation::has_eviction)
|
|
627
622
|
.unwrap_or_default()
|
|
628
623
|
}
|
|
629
624
|
}
|
|
@@ -46,7 +46,7 @@ impl CoreWfStarter {
|
|
|
46
46
|
.unwrap(),
|
|
47
47
|
worker_config: WorkerConfigBuilder::default()
|
|
48
48
|
.task_queue(task_queue)
|
|
49
|
-
.max_cached_workflows(
|
|
49
|
+
.max_cached_workflows(1000_usize)
|
|
50
50
|
.build()
|
|
51
51
|
.unwrap(),
|
|
52
52
|
wft_timeout: None,
|
|
@@ -63,7 +63,7 @@ impl CoreWfStarter {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
pub async fn shutdown(&mut self) {
|
|
66
|
-
self.get_core().await.shutdown().await
|
|
66
|
+
self.get_core().await.shutdown().await;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
pub async fn get_core(&mut self) -> Arc<dyn Core> {
|
|
@@ -8,7 +8,7 @@ use temporal_sdk_core_protos::{
|
|
|
8
8
|
workflow_activation::{wf_activation_job, FireTimer, ResolveActivity, WfActivationJob},
|
|
9
9
|
workflow_commands::{ActivityCancellationType, RequestCancelActivity, StartTimer},
|
|
10
10
|
workflow_completion::WfActivationCompletion,
|
|
11
|
-
ActivityTaskCompletion, IntoCompletion,
|
|
11
|
+
ActivityHeartbeat, ActivityTaskCompletion, IntoCompletion,
|
|
12
12
|
},
|
|
13
13
|
temporal::api::{
|
|
14
14
|
common::v1::{ActivityType, Payloads},
|
|
@@ -647,3 +647,63 @@ async fn async_activity_completion_workflow() {
|
|
|
647
647
|
);
|
|
648
648
|
core.complete_execution(&task_q, &task.run_id).await;
|
|
649
649
|
}
|
|
650
|
+
|
|
651
|
+
#[tokio::test]
|
|
652
|
+
async fn activity_cancelled_after_heartbeat_times_out() {
|
|
653
|
+
let test_name = "activity_cancelled_after_heartbeat_times_out";
|
|
654
|
+
let (core, task_q) = init_core_and_create_wf(test_name).await;
|
|
655
|
+
let activity_id = "act-1";
|
|
656
|
+
let task = core.poll_workflow_activation(&task_q).await.unwrap();
|
|
657
|
+
// Complete workflow task and schedule activity
|
|
658
|
+
core.complete_workflow_activation(
|
|
659
|
+
schedule_activity_cmd(
|
|
660
|
+
0,
|
|
661
|
+
&task_q,
|
|
662
|
+
activity_id,
|
|
663
|
+
ActivityCancellationType::WaitCancellationCompleted,
|
|
664
|
+
Duration::from_secs(60),
|
|
665
|
+
Duration::from_secs(1),
|
|
666
|
+
)
|
|
667
|
+
.into_completion(task_q.clone(), task.run_id),
|
|
668
|
+
)
|
|
669
|
+
.await
|
|
670
|
+
.unwrap();
|
|
671
|
+
// Poll activity and verify that it's been scheduled with correct parameters
|
|
672
|
+
let task = core.poll_activity_task(&task_q).await.unwrap();
|
|
673
|
+
assert_matches!(
|
|
674
|
+
task.variant,
|
|
675
|
+
Some(act_task::Variant::Start(start_activity)) => {
|
|
676
|
+
assert_eq!(start_activity.activity_type, "test_activity".to_string())
|
|
677
|
+
}
|
|
678
|
+
);
|
|
679
|
+
// Delay the heartbeat
|
|
680
|
+
sleep(Duration::from_secs(2)).await;
|
|
681
|
+
core.record_activity_heartbeat(ActivityHeartbeat {
|
|
682
|
+
task_token: task.task_token.clone(),
|
|
683
|
+
task_queue: task_q.to_string(),
|
|
684
|
+
details: vec![],
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
// Verify activity got cancelled
|
|
688
|
+
let cancel_task = core.poll_activity_task(&task_q).await.unwrap();
|
|
689
|
+
assert_eq!(cancel_task.task_token, task.task_token.clone());
|
|
690
|
+
assert_matches!(cancel_task.variant, Some(act_task::Variant::Cancel(_)));
|
|
691
|
+
|
|
692
|
+
// Complete activity with cancelled result
|
|
693
|
+
core.complete_activity_task(ActivityTaskCompletion {
|
|
694
|
+
task_token: task.task_token.clone(),
|
|
695
|
+
task_queue: task_q.to_string(),
|
|
696
|
+
result: Some(ActivityResult::cancel_from_details(None)),
|
|
697
|
+
})
|
|
698
|
+
.await
|
|
699
|
+
.unwrap();
|
|
700
|
+
|
|
701
|
+
// Verify shutdown completes
|
|
702
|
+
core.shutdown_worker(task_q.as_str()).await;
|
|
703
|
+
core.shutdown().await;
|
|
704
|
+
// Cleanup just in case
|
|
705
|
+
core.server_gateway()
|
|
706
|
+
.terminate_workflow_execution(test_name.to_string(), None)
|
|
707
|
+
.await
|
|
708
|
+
.unwrap();
|
|
709
|
+
}
|
|
@@ -20,9 +20,9 @@ async fn parent_wf(mut ctx: WfContext) -> WorkflowResult<()> {
|
|
|
20
20
|
let started = child
|
|
21
21
|
.start(&mut ctx)
|
|
22
22
|
.await
|
|
23
|
-
.
|
|
23
|
+
.into_started()
|
|
24
24
|
.expect("Child chould start OK");
|
|
25
|
-
match started.result(
|
|
25
|
+
match started.result().await.status {
|
|
26
26
|
Some(child_workflow_result::Status::Completed(Success { .. })) => Ok(().into()),
|
|
27
27
|
_ => Err(anyhow!("Unexpected child WF status")),
|
|
28
28
|
}
|
|
@@ -78,13 +78,13 @@ async fn signals_child(mut ctx: WfContext) -> WorkflowResult<()> {
|
|
|
78
78
|
})
|
|
79
79
|
.start(&mut ctx)
|
|
80
80
|
.await
|
|
81
|
-
.
|
|
81
|
+
.into_started()
|
|
82
82
|
.expect("Must start ok");
|
|
83
83
|
started_child
|
|
84
84
|
.signal(&mut ctx, SIGNAME, b"hiya!")
|
|
85
85
|
.await
|
|
86
86
|
.unwrap();
|
|
87
|
-
started_child.result(
|
|
87
|
+
started_child.result().await.status.unwrap();
|
|
88
88
|
Ok(().into())
|
|
89
89
|
}
|
|
90
90
|
|
package/src/conversions.rs
CHANGED
|
@@ -276,6 +276,21 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
276
276
|
) as u64);
|
|
277
277
|
let max_cached_workflows =
|
|
278
278
|
js_value_getter!(cx, self, "maxCachedWorkflows", JsNumber) as usize;
|
|
279
|
+
|
|
280
|
+
let max_heartbeat_throttle_interval = Duration::from_millis(js_value_getter!(
|
|
281
|
+
cx,
|
|
282
|
+
self,
|
|
283
|
+
"maxHeartbeatThrottleIntervalMs",
|
|
284
|
+
JsNumber
|
|
285
|
+
) as u64);
|
|
286
|
+
|
|
287
|
+
let default_heartbeat_throttle_interval = Duration::from_millis(js_value_getter!(
|
|
288
|
+
cx,
|
|
289
|
+
self,
|
|
290
|
+
"defaultHeartbeatThrottleIntervalMs",
|
|
291
|
+
JsNumber
|
|
292
|
+
) as u64);
|
|
293
|
+
|
|
279
294
|
Ok(WorkerConfig {
|
|
280
295
|
no_remote_activities: false, // TODO: make this configurable once Core implements local activities
|
|
281
296
|
max_concurrent_at_polls,
|
|
@@ -286,6 +301,8 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
286
301
|
nonsticky_to_sticky_poll_ratio,
|
|
287
302
|
sticky_queue_schedule_to_start_timeout,
|
|
288
303
|
task_queue,
|
|
304
|
+
max_heartbeat_throttle_interval,
|
|
305
|
+
default_heartbeat_throttle_interval,
|
|
289
306
|
})
|
|
290
307
|
}
|
|
291
308
|
}
|
|
Binary file
|