@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
|
@@ -54,6 +54,12 @@ fsm! {
|
|
|
54
54
|
Started --(ChildWorkflowExecutionTimedOut(i32), shared on_child_workflow_execution_timed_out) --> TimedOut;
|
|
55
55
|
Started --(ChildWorkflowExecutionCancelled, shared on_child_workflow_execution_cancelled) --> Cancelled;
|
|
56
56
|
Started --(ChildWorkflowExecutionTerminated, shared on_child_workflow_execution_terminated) --> Terminated;
|
|
57
|
+
|
|
58
|
+
// Ignore any spurious cancellations after resolution
|
|
59
|
+
Cancelled --(Cancel) --> Cancelled;
|
|
60
|
+
Failed --(Cancel) --> Failed;
|
|
61
|
+
TimedOut --(Cancel) --> TimedOut;
|
|
62
|
+
Completed --(Cancel) --> Completed;
|
|
57
63
|
}
|
|
58
64
|
|
|
59
65
|
pub struct ChildWorkflowExecutionStartedEvent {
|
|
@@ -288,7 +294,7 @@ pub(super) struct Terminated {}
|
|
|
288
294
|
#[derive(Default, Clone)]
|
|
289
295
|
pub(super) struct TimedOut {}
|
|
290
296
|
|
|
291
|
-
#[derive(Default, Clone)]
|
|
297
|
+
#[derive(Default, Clone, Debug)]
|
|
292
298
|
pub(super) struct SharedState {
|
|
293
299
|
initiated_event_id: i64,
|
|
294
300
|
started_event_id: i64,
|
|
@@ -630,6 +636,7 @@ mod test {
|
|
|
630
636
|
};
|
|
631
637
|
use anyhow::anyhow;
|
|
632
638
|
use rstest::{fixture, rstest};
|
|
639
|
+
use std::mem::discriminant;
|
|
633
640
|
use temporal_sdk_core_protos::coresdk::{
|
|
634
641
|
child_workflow::child_workflow_result,
|
|
635
642
|
workflow_activation::resolve_child_workflow_execution_start::Status as StartStatus,
|
|
@@ -643,11 +650,11 @@ mod test {
|
|
|
643
650
|
}
|
|
644
651
|
|
|
645
652
|
impl Expectation {
|
|
646
|
-
fn try_from_u8(x: u8) -> Option<Self> {
|
|
653
|
+
const fn try_from_u8(x: u8) -> Option<Self> {
|
|
647
654
|
Some(match x {
|
|
648
|
-
0 =>
|
|
649
|
-
1 =>
|
|
650
|
-
2 =>
|
|
655
|
+
0 => Self::Success,
|
|
656
|
+
1 => Self::Failure,
|
|
657
|
+
2 => Self::StartFailure,
|
|
651
658
|
_ => return None,
|
|
652
659
|
})
|
|
653
660
|
}
|
|
@@ -693,12 +700,7 @@ mod test {
|
|
|
693
700
|
};
|
|
694
701
|
match (
|
|
695
702
|
expectation,
|
|
696
|
-
start_res
|
|
697
|
-
.as_started()
|
|
698
|
-
.unwrap()
|
|
699
|
-
.result(&mut ctx)
|
|
700
|
-
.await
|
|
701
|
-
.status,
|
|
703
|
+
start_res.into_started().unwrap().result().await.status,
|
|
702
704
|
) {
|
|
703
705
|
(Expectation::Success, Some(child_workflow_result::Status::Completed(_))) => {
|
|
704
706
|
Ok(().into())
|
|
@@ -803,4 +805,22 @@ mod test {
|
|
|
803
805
|
);
|
|
804
806
|
wfm.shutdown().await.unwrap();
|
|
805
807
|
}
|
|
808
|
+
|
|
809
|
+
#[test]
|
|
810
|
+
fn cancels_ignored_terminal() {
|
|
811
|
+
for state in [
|
|
812
|
+
ChildWorkflowMachineState::Cancelled(Cancelled {}),
|
|
813
|
+
Failed {}.into(),
|
|
814
|
+
TimedOut {}.into(),
|
|
815
|
+
Completed {}.into(),
|
|
816
|
+
] {
|
|
817
|
+
let mut s = ChildWorkflowMachine {
|
|
818
|
+
state: state.clone(),
|
|
819
|
+
shared_state: Default::default(),
|
|
820
|
+
};
|
|
821
|
+
let cmds = s.cancel().unwrap();
|
|
822
|
+
assert_eq!(cmds.len(), 0);
|
|
823
|
+
assert_eq!(discriminant(&state), discriminant(&s.state));
|
|
824
|
+
}
|
|
825
|
+
}
|
|
806
826
|
}
|
|
@@ -117,7 +117,7 @@ pub(super) struct CompleteWorkflowCommandRecorded {}
|
|
|
117
117
|
|
|
118
118
|
impl From<CompleteWorkflowCommandCreated> for CompleteWorkflowCommandRecorded {
|
|
119
119
|
fn from(_: CompleteWorkflowCommandCreated) -> Self {
|
|
120
|
-
|
|
120
|
+
Self::default()
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
|
|
@@ -77,38 +77,34 @@ impl TryFrom<WorkflowCommand> for WFCommand {
|
|
|
77
77
|
|
|
78
78
|
fn try_from(c: WorkflowCommand) -> Result<Self, Self::Error> {
|
|
79
79
|
match c.variant.ok_or(EmptyWorkflowCommandErr)? {
|
|
80
|
-
workflow_command::Variant::StartTimer(s) => Ok(
|
|
81
|
-
workflow_command::Variant::CancelTimer(s) => Ok(
|
|
82
|
-
workflow_command::Variant::ScheduleActivity(s) => Ok(
|
|
80
|
+
workflow_command::Variant::StartTimer(s) => Ok(Self::AddTimer(s)),
|
|
81
|
+
workflow_command::Variant::CancelTimer(s) => Ok(Self::CancelTimer(s)),
|
|
82
|
+
workflow_command::Variant::ScheduleActivity(s) => Ok(Self::AddActivity(s)),
|
|
83
83
|
workflow_command::Variant::RequestCancelActivity(s) => {
|
|
84
|
-
Ok(
|
|
84
|
+
Ok(Self::RequestCancelActivity(s))
|
|
85
85
|
}
|
|
86
86
|
workflow_command::Variant::CompleteWorkflowExecution(c) => {
|
|
87
|
-
Ok(
|
|
87
|
+
Ok(Self::CompleteWorkflow(c))
|
|
88
88
|
}
|
|
89
|
-
workflow_command::Variant::FailWorkflowExecution(s) => Ok(
|
|
90
|
-
workflow_command::Variant::RespondToQuery(s) => Ok(
|
|
89
|
+
workflow_command::Variant::FailWorkflowExecution(s) => Ok(Self::FailWorkflow(s)),
|
|
90
|
+
workflow_command::Variant::RespondToQuery(s) => Ok(Self::QueryResponse(s)),
|
|
91
91
|
workflow_command::Variant::ContinueAsNewWorkflowExecution(s) => {
|
|
92
|
-
Ok(
|
|
92
|
+
Ok(Self::ContinueAsNew(s))
|
|
93
93
|
}
|
|
94
|
-
workflow_command::Variant::CancelWorkflowExecution(s) =>
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
workflow_command::Variant::SetPatchMarker(s) => Ok(WFCommand::SetPatchMarker(s)),
|
|
94
|
+
workflow_command::Variant::CancelWorkflowExecution(s) => Ok(Self::CancelWorkflow(s)),
|
|
95
|
+
workflow_command::Variant::SetPatchMarker(s) => Ok(Self::SetPatchMarker(s)),
|
|
98
96
|
workflow_command::Variant::StartChildWorkflowExecution(s) => {
|
|
99
|
-
Ok(
|
|
97
|
+
Ok(Self::AddChildWorkflow(s))
|
|
100
98
|
}
|
|
101
99
|
workflow_command::Variant::RequestCancelExternalWorkflowExecution(s) => {
|
|
102
|
-
Ok(
|
|
100
|
+
Ok(Self::RequestCancelExternalWorkflow(s))
|
|
103
101
|
}
|
|
104
102
|
workflow_command::Variant::SignalExternalWorkflowExecution(s) => {
|
|
105
|
-
Ok(
|
|
106
|
-
}
|
|
107
|
-
workflow_command::Variant::CancelSignalWorkflow(s) => {
|
|
108
|
-
Ok(WFCommand::CancelSignalWorkflow(s))
|
|
103
|
+
Ok(Self::SignalExternalWorkflow(s))
|
|
109
104
|
}
|
|
105
|
+
workflow_command::Variant::CancelSignalWorkflow(s) => Ok(Self::CancelSignalWorkflow(s)),
|
|
110
106
|
workflow_command::Variant::CancelUnstartedChildWorkflowExecution(s) => {
|
|
111
|
-
Ok(
|
|
107
|
+
Ok(Self::CancelUnstartedChild(s))
|
|
112
108
|
}
|
|
113
109
|
}
|
|
114
110
|
}
|
|
@@ -170,9 +166,7 @@ where
|
|
|
170
166
|
+ Clone
|
|
171
167
|
+ Send
|
|
172
168
|
+ 'static,
|
|
173
|
-
<SM as StateMachine>::Event: TryFrom<HistoryEvent
|
|
174
|
-
<SM as StateMachine>::Event: TryFrom<CommandType>,
|
|
175
|
-
<SM as StateMachine>::Event: Display,
|
|
169
|
+
<SM as StateMachine>::Event: TryFrom<HistoryEvent> + TryFrom<CommandType> + Display,
|
|
176
170
|
WFMachinesError: From<<<SM as StateMachine>::Event as TryFrom<HistoryEvent>>::Error>,
|
|
177
171
|
<SM as StateMachine>::Command: Debug + Display,
|
|
178
172
|
<SM as StateMachine>::State: Display,
|
|
@@ -248,7 +242,8 @@ where
|
|
|
248
242
|
let res = self.cancel();
|
|
249
243
|
res.map_err(|e| match e {
|
|
250
244
|
MachineError::InvalidTransition => WFMachinesError::Fatal(format!(
|
|
251
|
-
"Invalid transition while attempting to cancel in {}",
|
|
245
|
+
"Invalid transition while attempting to cancel {} in {}",
|
|
246
|
+
self.name(),
|
|
252
247
|
self.state(),
|
|
253
248
|
)),
|
|
254
249
|
MachineError::Underlying(e) => e.into(),
|
|
@@ -107,7 +107,7 @@ impl PatchMachine {
|
|
|
107
107
|
.into(),
|
|
108
108
|
),
|
|
109
109
|
};
|
|
110
|
-
let mut machine =
|
|
110
|
+
let mut machine = Self {
|
|
111
111
|
state: initial_state,
|
|
112
112
|
shared_state: state,
|
|
113
113
|
};
|
|
@@ -210,7 +210,7 @@ impl TryFrom<HistoryEvent> for PatchMachineEvents {
|
|
|
210
210
|
|
|
211
211
|
fn try_from(e: HistoryEvent) -> Result<Self, Self::Error> {
|
|
212
212
|
match e.get_changed_marker_details() {
|
|
213
|
-
Some((id, _)) => Ok(
|
|
213
|
+
Some((id, _)) => Ok(Self::MarkerRecorded(id)),
|
|
214
214
|
_ => Err(WFMachinesError::Nondeterminism(format!(
|
|
215
215
|
"Change machine cannot handle this event: {}",
|
|
216
216
|
e
|
|
@@ -422,7 +422,9 @@ mod tests {
|
|
|
422
422
|
commands[0].command_type,
|
|
423
423
|
CommandType::ScheduleActivityTask as i32
|
|
424
424
|
);
|
|
425
|
-
let act = if
|
|
425
|
+
let act = if replaying {
|
|
426
|
+
wfm.get_next_activation().await
|
|
427
|
+
} else {
|
|
426
428
|
// Feed more history
|
|
427
429
|
wfm.new_history(
|
|
428
430
|
patch_marker_single_activity(marker_type)
|
|
@@ -431,8 +433,6 @@ mod tests {
|
|
|
431
433
|
.into(),
|
|
432
434
|
)
|
|
433
435
|
.await
|
|
434
|
-
} else {
|
|
435
|
-
wfm.get_next_activation().await
|
|
436
436
|
};
|
|
437
437
|
|
|
438
438
|
if marker_type == MarkerType::Deprecated {
|
|
@@ -514,7 +514,9 @@ mod tests {
|
|
|
514
514
|
if activity_id == expected_activity_id
|
|
515
515
|
);
|
|
516
516
|
|
|
517
|
-
let act = if
|
|
517
|
+
let act = if replaying {
|
|
518
|
+
wfm.get_next_activation().await
|
|
519
|
+
} else {
|
|
518
520
|
// Feed more history. Since we are *not* replaying, we *always* "have" the change
|
|
519
521
|
// and the history should have the has-change timer. v3 of course always has the change
|
|
520
522
|
// regardless.
|
|
@@ -525,8 +527,6 @@ mod tests {
|
|
|
525
527
|
.into(),
|
|
526
528
|
)
|
|
527
529
|
.await
|
|
528
|
-
} else {
|
|
529
|
-
wfm.get_next_activation().await
|
|
530
530
|
};
|
|
531
531
|
|
|
532
532
|
let act = act.unwrap();
|
|
@@ -42,6 +42,10 @@ fsm! {
|
|
|
42
42
|
SignalExternalCommandRecorded
|
|
43
43
|
--(SignalExternalWorkflowExecutionFailed(SignalExternalWorkflowExecutionFailedCause),
|
|
44
44
|
on_signal_external_workflow_execution_failed) --> Failed;
|
|
45
|
+
|
|
46
|
+
// Ignore any spurious cancellations after resolution
|
|
47
|
+
Cancelled --(Cancel) --> Cancelled;
|
|
48
|
+
Signaled --(Cancel) --> Signaled;
|
|
45
49
|
}
|
|
46
50
|
|
|
47
51
|
#[derive(Default, Clone)]
|
|
@@ -262,7 +266,7 @@ impl Cancellable for SignalExternalMachine {
|
|
|
262
266
|
..Default::default()
|
|
263
267
|
}),
|
|
264
268
|
}
|
|
265
|
-
.into()]
|
|
269
|
+
.into()];
|
|
266
270
|
}
|
|
267
271
|
Some(_) => panic!("Signal external machine cancel produced unexpected result"),
|
|
268
272
|
None => (),
|
|
@@ -285,6 +289,7 @@ mod tests {
|
|
|
285
289
|
test_help::TestHistoryBuilder,
|
|
286
290
|
workflow::managed_wf::ManagedWFFunc,
|
|
287
291
|
};
|
|
292
|
+
use std::mem::discriminant;
|
|
288
293
|
use temporal_sdk_core_protos::coresdk::workflow_activation::{
|
|
289
294
|
wf_activation_job, WfActivationJob,
|
|
290
295
|
};
|
|
@@ -382,4 +387,20 @@ mod tests {
|
|
|
382
387
|
);
|
|
383
388
|
wfm.shutdown().await.unwrap();
|
|
384
389
|
}
|
|
390
|
+
|
|
391
|
+
#[test]
|
|
392
|
+
fn cancels_ignored_terminal() {
|
|
393
|
+
for state in [
|
|
394
|
+
SignalExternalMachineState::Cancelled(Cancelled {}),
|
|
395
|
+
Signaled {}.into(),
|
|
396
|
+
] {
|
|
397
|
+
let mut s = SignalExternalMachine {
|
|
398
|
+
state: state.clone(),
|
|
399
|
+
shared_state: Default::default(),
|
|
400
|
+
};
|
|
401
|
+
let cmds = s.cancel().unwrap();
|
|
402
|
+
assert_eq!(cmds.len(), 0);
|
|
403
|
+
assert_eq!(discriminant(&state), discriminant(&s.state));
|
|
404
|
+
}
|
|
405
|
+
}
|
|
385
406
|
}
|
|
@@ -39,6 +39,10 @@ fsm! {
|
|
|
39
39
|
--(CommandCancelTimer, on_command_cancel_timer) --> CancelTimerCommandSent;
|
|
40
40
|
|
|
41
41
|
CancelTimerCommandSent --(TimerCanceled) --> Canceled;
|
|
42
|
+
|
|
43
|
+
// Ignore any spurious cancellations after resolution
|
|
44
|
+
Canceled --(Cancel) --> Canceled;
|
|
45
|
+
Fired --(Cancel) --> Fired;
|
|
42
46
|
}
|
|
43
47
|
|
|
44
48
|
#[derive(Debug, derive_more::Display)]
|
|
@@ -195,13 +199,13 @@ impl StartCommandRecorded {
|
|
|
195
199
|
dat: SharedState,
|
|
196
200
|
attrs: TimerFiredEventAttributes,
|
|
197
201
|
) -> TimerMachineTransition<Fired> {
|
|
198
|
-
if dat.attrs.seq.to_string()
|
|
202
|
+
if dat.attrs.seq.to_string() == attrs.timer_id {
|
|
203
|
+
TransitionResult::ok(vec![TimerMachineCommand::Complete], Fired::default())
|
|
204
|
+
} else {
|
|
199
205
|
TransitionResult::Err(WFMachinesError::Fatal(format!(
|
|
200
206
|
"Timer fired event did not have expected timer id {}, it was {}!",
|
|
201
207
|
dat.attrs.seq, attrs.timer_id
|
|
202
208
|
)))
|
|
203
|
-
} else {
|
|
204
|
-
TransitionResult::ok(vec![TimerMachineCommand::Complete], Fired::default())
|
|
205
209
|
}
|
|
206
210
|
}
|
|
207
211
|
|
|
@@ -275,6 +279,7 @@ mod test {
|
|
|
275
279
|
workflow::managed_wf::ManagedWFFunc,
|
|
276
280
|
};
|
|
277
281
|
use rstest::{fixture, rstest};
|
|
282
|
+
use std::mem::discriminant;
|
|
278
283
|
use std::time::Duration;
|
|
279
284
|
|
|
280
285
|
#[fixture]
|
|
@@ -420,4 +425,17 @@ mod test {
|
|
|
420
425
|
assert_eq!(commands.len(), 0);
|
|
421
426
|
wfm.shutdown().await.unwrap();
|
|
422
427
|
}
|
|
428
|
+
|
|
429
|
+
#[test]
|
|
430
|
+
fn cancels_ignored_terminal() {
|
|
431
|
+
for state in [TimerMachineState::Canceled(Canceled {}), Fired {}.into()] {
|
|
432
|
+
let mut s = TimerMachine {
|
|
433
|
+
state: state.clone(),
|
|
434
|
+
shared_state: Default::default(),
|
|
435
|
+
};
|
|
436
|
+
let cmds = s.cancel().unwrap();
|
|
437
|
+
assert_eq!(cmds.len(), 0);
|
|
438
|
+
assert_eq!(discriminant(&state), discriminant(&s.state));
|
|
439
|
+
}
|
|
440
|
+
}
|
|
423
441
|
}
|
|
@@ -79,7 +79,7 @@ mod machine_coverage_report {
|
|
|
79
79
|
workflow_task_state_machine::WorkflowTaskMachine,
|
|
80
80
|
};
|
|
81
81
|
use rustfsm::StateMachine;
|
|
82
|
-
use std::{fs::File, io::Write
|
|
82
|
+
use std::{fs::File, io::Write};
|
|
83
83
|
|
|
84
84
|
// This "test" needs to exist so that we have a way to join the spawned thread. Otherwise
|
|
85
85
|
// it'll just get abandoned.
|
|
@@ -89,7 +89,7 @@ mod machine_coverage_report {
|
|
|
89
89
|
#[ignore]
|
|
90
90
|
fn reporter() {
|
|
91
91
|
// Make sure thread handle exists
|
|
92
|
-
let _ = COVERAGE_SENDER
|
|
92
|
+
let _ = &*COVERAGE_SENDER;
|
|
93
93
|
// Join it
|
|
94
94
|
THREAD_HANDLE
|
|
95
95
|
.lock()
|
|
@@ -124,7 +124,7 @@ mod machine_coverage_report {
|
|
|
124
124
|
m @ "WorkflowTaskMachine" => cover_transitions(m, &mut wf_task, coverage),
|
|
125
125
|
m @ "FailWorkflowMachine" => cover_transitions(m, &mut fail_wf, coverage),
|
|
126
126
|
m @ "ContinueAsNewWorkflowMachine" => {
|
|
127
|
-
cover_transitions(m, &mut cont_as_new, coverage)
|
|
127
|
+
cover_transitions(m, &mut cont_as_new, coverage);
|
|
128
128
|
}
|
|
129
129
|
m @ "CancelWorkflowMachine" => cover_transitions(m, &mut cancel_wf, coverage),
|
|
130
130
|
m @ "PatchMachine" => cover_transitions(m, &mut version, coverage),
|
|
@@ -150,7 +150,7 @@ where
|
|
|
150
150
|
T: Into<wf_activation_job::Variant>,
|
|
151
151
|
{
|
|
152
152
|
fn from(v: T) -> Self {
|
|
153
|
-
|
|
153
|
+
Self::PushWFJob(v.into())
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
|
|
@@ -171,7 +171,7 @@ pub(crate) enum WFMachinesError {
|
|
|
171
171
|
|
|
172
172
|
impl From<TimestampOutOfSystemRangeError> for WFMachinesError {
|
|
173
173
|
fn from(_: TimestampOutOfSystemRangeError) -> Self {
|
|
174
|
-
|
|
174
|
+
Self::Fatal("Could not decode timestamp".to_string())
|
|
175
175
|
}
|
|
176
176
|
}
|
|
177
177
|
|
|
@@ -210,7 +210,7 @@ impl WorkflowMachines {
|
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
/// Returns true if workflow has seen a terminal command
|
|
213
|
-
pub(crate) fn workflow_is_finished(&self) -> bool {
|
|
213
|
+
pub(crate) const fn workflow_is_finished(&self) -> bool {
|
|
214
214
|
self.workflow_end_time.is_some()
|
|
215
215
|
}
|
|
216
216
|
|
|
@@ -486,7 +486,7 @@ impl WorkflowMachines {
|
|
|
486
486
|
}
|
|
487
487
|
|
|
488
488
|
fn set_current_time(&mut self, time: SystemTime) -> SystemTime {
|
|
489
|
-
if self.current_wf_time.
|
|
489
|
+
if self.current_wf_time.map_or(true, |t| t < time) {
|
|
490
490
|
self.current_wf_time = Some(time);
|
|
491
491
|
}
|
|
492
492
|
self.current_wf_time
|
|
@@ -503,7 +503,7 @@ impl WorkflowMachines {
|
|
|
503
503
|
let results = self.drive_me.fetch_workflow_iteration_output().await;
|
|
504
504
|
let jobs = self.handle_driven_results(results)?;
|
|
505
505
|
let has_new_lang_jobs = !jobs.is_empty();
|
|
506
|
-
for job in jobs
|
|
506
|
+
for job in jobs {
|
|
507
507
|
self.drive_me.send_job(job);
|
|
508
508
|
}
|
|
509
509
|
self.prepare_commands()?;
|
|
@@ -626,15 +626,15 @@ impl WorkflowMachines {
|
|
|
626
626
|
.machine_mut(c.machine)
|
|
627
627
|
.handle_command(c.command.command_type())?;
|
|
628
628
|
self.process_machine_responses(c.machine, machine_responses)?;
|
|
629
|
+
self.commands.push_back(c);
|
|
629
630
|
}
|
|
630
|
-
self.commands.push_back(c);
|
|
631
631
|
}
|
|
632
632
|
debug!(commands = %self.commands.display(), "prepared commands");
|
|
633
633
|
Ok(())
|
|
634
634
|
}
|
|
635
635
|
|
|
636
636
|
/// After a machine handles either an event or a command, it produces [MachineResponses] which
|
|
637
|
-
/// this function uses to drive sending jobs to lang,
|
|
637
|
+
/// this function uses to drive sending jobs to lang, triggering new workflow tasks, etc.
|
|
638
638
|
fn process_machine_responses(
|
|
639
639
|
&mut self,
|
|
640
640
|
sm: MachineKey,
|
|
@@ -695,7 +695,7 @@ impl WorkflowMachines {
|
|
|
695
695
|
self.current_wf_task_commands.push_back(timer);
|
|
696
696
|
}
|
|
697
697
|
WFCommand::CancelTimer(attrs) => {
|
|
698
|
-
jobs.extend(self.process_cancellation(CommandID::Timer(attrs.seq))?)
|
|
698
|
+
jobs.extend(self.process_cancellation(CommandID::Timer(attrs.seq))?);
|
|
699
699
|
}
|
|
700
700
|
WFCommand::AddActivity(attrs) => {
|
|
701
701
|
let seq = attrs.seq;
|
|
@@ -705,7 +705,7 @@ impl WorkflowMachines {
|
|
|
705
705
|
self.current_wf_task_commands.push_back(activity);
|
|
706
706
|
}
|
|
707
707
|
WFCommand::RequestCancelActivity(attrs) => {
|
|
708
|
-
jobs.extend(self.process_cancellation(CommandID::Activity(attrs.seq))?)
|
|
708
|
+
jobs.extend(self.process_cancellation(CommandID::Activity(attrs.seq))?);
|
|
709
709
|
}
|
|
710
710
|
WFCommand::CompleteWorkflow(attrs) => {
|
|
711
711
|
self.metrics.wf_completed();
|
|
@@ -815,7 +815,7 @@ impl WorkflowMachines {
|
|
|
815
815
|
self.current_wf_task_commands.push_back(sigm);
|
|
816
816
|
}
|
|
817
817
|
WFCommand::CancelSignalWorkflow(attrs) => {
|
|
818
|
-
jobs.extend(self.process_cancellation(CommandID::SignalExternal(attrs.seq))?)
|
|
818
|
+
jobs.extend(self.process_cancellation(CommandID::SignalExternal(attrs.seq))?);
|
|
819
819
|
}
|
|
820
820
|
WFCommand::QueryResponse(_) => {
|
|
821
821
|
// Nothing to do here, queries are handled above the machine level
|
|
@@ -840,7 +840,7 @@ impl WorkflowMachines {
|
|
|
840
840
|
self.current_wf_task_commands.push_back(CommandAndMachine {
|
|
841
841
|
command: c,
|
|
842
842
|
machine: m_key,
|
|
843
|
-
})
|
|
843
|
+
});
|
|
844
844
|
}
|
|
845
845
|
MachineResponse::PushWFJob(j) => {
|
|
846
846
|
jobs.push(j);
|
|
@@ -68,15 +68,14 @@ impl PendingActivations {
|
|
|
68
68
|
let mut inner = self.inner.write();
|
|
69
69
|
let mut key_queue = inner.queue.iter().copied();
|
|
70
70
|
let maybe_key = key_queue.position(|k| {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
false
|
|
75
|
-
}
|
|
71
|
+
inner
|
|
72
|
+
.activations
|
|
73
|
+
.get(k)
|
|
74
|
+
.map_or(false, |activation| predicate(&activation.run_id))
|
|
76
75
|
});
|
|
77
76
|
|
|
78
77
|
let maybe_key = maybe_key.map(|pos| inner.queue.remove(pos).unwrap());
|
|
79
|
-
|
|
78
|
+
maybe_key.and_then(|key| {
|
|
80
79
|
if let Some(pa) = inner.activations.remove(key) {
|
|
81
80
|
inner.by_run_id.remove(&pa.run_id);
|
|
82
81
|
Some(pa)
|
|
@@ -87,9 +86,7 @@ impl PendingActivations {
|
|
|
87
86
|
drop(inner); // Will deadlock when we recurse w/o this
|
|
88
87
|
self.pop()
|
|
89
88
|
}
|
|
90
|
-
}
|
|
91
|
-
None
|
|
92
|
-
}
|
|
89
|
+
})
|
|
93
90
|
}
|
|
94
91
|
|
|
95
92
|
pub fn pop(&self) -> Option<WfActivation> {
|
|
@@ -119,17 +116,19 @@ fn merge_joblists(
|
|
|
119
116
|
.as_mut_slice()
|
|
120
117
|
.sort_by(evictions_always_last_compare);
|
|
121
118
|
// Drop any duplicate evictions
|
|
122
|
-
let truncate_len =
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
119
|
+
let truncate_len = existing_list
|
|
120
|
+
.iter()
|
|
121
|
+
.rev()
|
|
122
|
+
.position(|j| {
|
|
123
|
+
!matches!(
|
|
124
|
+
j.variant,
|
|
125
|
+
Some(wf_activation_job::Variant::RemoveFromCache(_))
|
|
126
|
+
)
|
|
127
|
+
})
|
|
128
|
+
.map_or(1, |last_non_evict_job| {
|
|
129
|
+
existing_list.len() - last_non_evict_job + 1
|
|
130
|
+
});
|
|
131
|
+
existing_list.truncate(truncate_len);
|
|
133
132
|
}
|
|
134
133
|
|
|
135
134
|
fn evictions_always_last_compare(a: &WfActivationJob, b: &WfActivationJob) -> Ordering {
|
|
@@ -165,7 +165,7 @@ impl Default for RetryConfig {
|
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
impl RetryConfig {
|
|
168
|
-
pub(crate) fn poll_retry_policy() -> Self {
|
|
168
|
+
pub(crate) const fn poll_retry_policy() -> Self {
|
|
169
169
|
Self {
|
|
170
170
|
initial_interval: Duration::from_millis(200),
|
|
171
171
|
randomization_factor: 0.2,
|
|
@@ -179,7 +179,7 @@ impl RetryConfig {
|
|
|
179
179
|
|
|
180
180
|
impl From<RetryConfig> for ExponentialBackoff {
|
|
181
181
|
fn from(c: RetryConfig) -> Self {
|
|
182
|
-
|
|
182
|
+
Self {
|
|
183
183
|
current_interval: c.initial_interval,
|
|
184
184
|
initial_interval: c.initial_interval,
|
|
185
185
|
randomization_factor: c.randomization_factor,
|
|
@@ -269,7 +269,7 @@ impl Interceptor for ServiceCallInterceptor {
|
|
|
269
269
|
.parse()
|
|
270
270
|
.unwrap_or_else(|_| MetadataValue::from_static("")),
|
|
271
271
|
);
|
|
272
|
-
for (k, v) in self.opts.static_headers
|
|
272
|
+
for (k, v) in &self.opts.static_headers {
|
|
273
273
|
if let (Ok(k), Ok(v)) = (MetadataKey::from_str(k), MetadataValue::from_str(v)) {
|
|
274
274
|
metadata.insert(k, v);
|
|
275
275
|
}
|
|
@@ -355,8 +355,11 @@ pub trait ServerGatewayApis {
|
|
|
355
355
|
|
|
356
356
|
/// Fetch new workflow tasks from the provided queue. Should block indefinitely if there is no
|
|
357
357
|
/// work.
|
|
358
|
-
async fn poll_workflow_task(
|
|
359
|
-
|
|
358
|
+
async fn poll_workflow_task(
|
|
359
|
+
&self,
|
|
360
|
+
task_queue: String,
|
|
361
|
+
is_sticky: bool,
|
|
362
|
+
) -> Result<PollWorkflowTaskQueueResponse>;
|
|
360
363
|
|
|
361
364
|
/// Fetch new activity tasks from the provided queue. Should block indefinitely if there is no
|
|
362
365
|
/// work.
|
|
@@ -516,12 +519,17 @@ impl ServerGatewayApis for ServerGateway {
|
|
|
516
519
|
async fn poll_workflow_task(
|
|
517
520
|
&self,
|
|
518
521
|
task_queue: String,
|
|
522
|
+
is_sticky: bool,
|
|
519
523
|
) -> Result<PollWorkflowTaskQueueResponse> {
|
|
520
524
|
let mut request = PollWorkflowTaskQueueRequest {
|
|
521
525
|
namespace: self.opts.namespace.clone(),
|
|
522
526
|
task_queue: Some(TaskQueue {
|
|
523
527
|
name: task_queue,
|
|
524
|
-
kind:
|
|
528
|
+
kind: if is_sticky {
|
|
529
|
+
TaskQueueKind::Sticky
|
|
530
|
+
} else {
|
|
531
|
+
TaskQueueKind::Normal
|
|
532
|
+
} as i32,
|
|
525
533
|
}),
|
|
526
534
|
identity: self.opts.identity.clone(),
|
|
527
535
|
binary_checksum: self.opts.worker_binary_id.clone(),
|
|
@@ -894,7 +902,7 @@ mockall::mock! {
|
|
|
894
902
|
) -> impl Future<Output = Result<StartWorkflowExecutionResponse>> + Send + 'b
|
|
895
903
|
where 'a: 'b, Self: 'b;
|
|
896
904
|
|
|
897
|
-
fn poll_workflow_task<'a, 'b>(&'a self, task_queue: String)
|
|
905
|
+
fn poll_workflow_task<'a, 'b>(&'a self, task_queue: String, is_sticky: bool)
|
|
898
906
|
-> impl Future<Output = Result<PollWorkflowTaskQueueResponse>> + Send + 'b
|
|
899
907
|
where 'a: 'b, Self: 'b;
|
|
900
908
|
|
|
@@ -152,7 +152,7 @@ where
|
|
|
152
152
|
|
|
153
153
|
async fn shutdown_box(self: Box<Self>) {
|
|
154
154
|
let this = *self;
|
|
155
|
-
this.shutdown().await
|
|
155
|
+
this.shutdown().await;
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
158
|
|
|
@@ -192,7 +192,7 @@ impl Poller<PollWorkflowTaskQueueResponse> for WorkflowTaskPoller {
|
|
|
192
192
|
|
|
193
193
|
async fn shutdown_box(self: Box<Self>) {
|
|
194
194
|
let this = *self;
|
|
195
|
-
this.shutdown().await
|
|
195
|
+
this.shutdown().await;
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
198
|
|
|
@@ -200,6 +200,7 @@ pub type PollWorkflowTaskBuffer = LongPollBuffer<PollWorkflowTaskQueueResponse>;
|
|
|
200
200
|
pub fn new_workflow_task_buffer(
|
|
201
201
|
sg: Arc<impl ServerGatewayApis + Send + Sync + 'static + ?Sized>,
|
|
202
202
|
task_queue: String,
|
|
203
|
+
is_sticky: bool,
|
|
203
204
|
concurrent_pollers: usize,
|
|
204
205
|
buffer_size: usize,
|
|
205
206
|
) -> PollWorkflowTaskBuffer {
|
|
@@ -207,7 +208,7 @@ pub fn new_workflow_task_buffer(
|
|
|
207
208
|
move || {
|
|
208
209
|
let sg = sg.clone();
|
|
209
210
|
let task_queue = task_queue.clone();
|
|
210
|
-
async move { sg.poll_workflow_task(task_queue).await }
|
|
211
|
+
async move { sg.poll_workflow_task(task_queue, is_sticky).await }
|
|
211
212
|
},
|
|
212
213
|
concurrent_pollers,
|
|
213
214
|
buffer_size,
|
|
@@ -246,7 +247,7 @@ mod tests {
|
|
|
246
247
|
mock_gateway
|
|
247
248
|
.expect_poll_workflow_task()
|
|
248
249
|
.times(2)
|
|
249
|
-
.returning(move |_| {
|
|
250
|
+
.returning(move |_, _| {
|
|
250
251
|
async {
|
|
251
252
|
tokio::time::sleep(Duration::from_millis(100)).await;
|
|
252
253
|
Ok(Default::default())
|
|
@@ -255,7 +256,7 @@ mod tests {
|
|
|
255
256
|
});
|
|
256
257
|
let mock_gateway = Arc::new(mock_gateway);
|
|
257
258
|
|
|
258
|
-
let pb = new_workflow_task_buffer(mock_gateway, "someq".to_string(), 1, 1);
|
|
259
|
+
let pb = new_workflow_task_buffer(mock_gateway, "someq".to_string(), false, 1, 1);
|
|
259
260
|
|
|
260
261
|
// Poll a bunch of times, "interrupting" it each time, we should only actually have polled
|
|
261
262
|
// once since the poll takes a while
|