@temporalio/core-bridge 1.7.4 → 1.8.1
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 +245 -247
- package/Cargo.toml +1 -1
- package/lib/errors.d.ts +9 -0
- package/lib/errors.js +13 -0
- package/lib/errors.js.map +1 -1
- package/lib/index.d.ts +19 -3
- package/lib/index.js.map +1 -1
- 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/.github/workflows/heavy.yml +1 -1
- package/sdk-core/.github/workflows/semgrep.yml +25 -0
- package/sdk-core/README.md +2 -0
- package/sdk-core/cargo-tokio-console.sh +5 -0
- package/sdk-core/client/src/lib.rs +6 -41
- package/sdk-core/client/src/raw.rs +9 -0
- package/sdk-core/client/src/retry.rs +0 -16
- package/sdk-core/core/Cargo.toml +9 -5
- package/sdk-core/core/src/abstractions.rs +7 -75
- package/sdk-core/core/src/core_tests/activity_tasks.rs +16 -8
- package/sdk-core/core/src/core_tests/local_activities.rs +97 -5
- package/sdk-core/core/src/core_tests/mod.rs +1 -1
- package/sdk-core/core/src/core_tests/workers.rs +16 -16
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +247 -28
- package/sdk-core/core/src/lib.rs +2 -3
- package/sdk-core/core/src/pollers/mod.rs +30 -3
- package/sdk-core/core/src/pollers/poll_buffer.rs +166 -77
- package/sdk-core/core/src/protosext/mod.rs +4 -8
- package/sdk-core/core/src/replay/mod.rs +1 -1
- package/sdk-core/core/src/telemetry/metrics.rs +9 -0
- package/sdk-core/core/src/telemetry/mod.rs +3 -0
- package/sdk-core/core/src/test_help/mod.rs +9 -16
- package/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +6 -31
- package/sdk-core/core/src/worker/activities/local_activities.rs +214 -110
- package/sdk-core/core/src/worker/activities.rs +72 -47
- package/sdk-core/core/src/worker/client/mocks.rs +1 -1
- package/sdk-core/core/src/worker/client.rs +45 -32
- package/sdk-core/core/src/worker/mod.rs +170 -122
- package/sdk-core/core/src/worker/workflow/driven_workflow.rs +0 -4
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +9 -2
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +9 -2
- package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +6 -3
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +74 -22
- package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +3 -2
- package/sdk-core/core/src/worker/workflow/managed_run.rs +16 -3
- package/sdk-core/core/src/worker/workflow/mod.rs +13 -22
- package/sdk-core/core/src/worker/workflow/run_cache.rs +5 -0
- package/sdk-core/core/src/worker/workflow/wft_extraction.rs +4 -7
- package/sdk-core/core/src/worker/workflow/wft_poller.rs +38 -8
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +1 -0
- package/sdk-core/core-api/src/worker.rs +43 -2
- package/sdk-core/protos/api_upstream/Makefile +1 -1
- package/sdk-core/protos/api_upstream/buf.yaml +1 -6
- package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +12 -0
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +11 -0
- package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +13 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +1 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +2 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +9 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +19 -0
- package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +5 -0
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +36 -4
- package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +24 -7
- package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +4 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +76 -44
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +23 -1
- package/sdk-core/protos/google/rpc/status.proto +52 -0
- package/sdk-core/protos/local/temporal/sdk/core/common/common.proto +16 -0
- package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +4 -0
- package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +6 -0
- package/sdk-core/sdk/src/lib.rs +31 -10
- package/sdk-core/sdk/src/workflow_future.rs +7 -5
- package/sdk-core/sdk-core-protos/src/history_builder.rs +2 -0
- package/sdk-core/sdk-core-protos/src/history_info.rs +1 -0
- package/sdk-core/sdk-core-protos/src/lib.rs +82 -73
- package/sdk-core/test-utils/Cargo.toml +1 -1
- package/sdk-core/test-utils/src/lib.rs +50 -37
- package/sdk-core/tests/integ_tests/metrics_tests.rs +143 -10
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +26 -15
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +2 -2
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +5 -1
- package/sdk-core/tests/integ_tests/workflow_tests.rs +1 -0
- package/src/conversions.rs +9 -2
- package/src/runtime.rs +5 -7
- package/ts/errors.ts +15 -0
- package/ts/index.ts +22 -4
|
@@ -39,15 +39,11 @@ use tokio_util::sync::CancellationToken;
|
|
|
39
39
|
|
|
40
40
|
#[allow(clippy::large_enum_variant)] // Timeouts are relatively rare
|
|
41
41
|
#[derive(Debug)]
|
|
42
|
-
pub(crate) enum
|
|
42
|
+
pub(crate) enum NextPendingLAAction {
|
|
43
43
|
/// Send the activity task to lang
|
|
44
44
|
Dispatch(ActivityTask),
|
|
45
|
-
///
|
|
46
|
-
|
|
47
|
-
run_id: String,
|
|
48
|
-
resolution: LocalActivityResolution,
|
|
49
|
-
task: Option<ActivityTask>,
|
|
50
|
-
},
|
|
45
|
+
/// The worker must re-feed this completion back through the machines. Includes timeouts.
|
|
46
|
+
Autocomplete(LACompleteAction),
|
|
51
47
|
}
|
|
52
48
|
|
|
53
49
|
#[derive(Debug)]
|
|
@@ -87,6 +83,24 @@ impl LocalActivityExecutionResult {
|
|
|
87
83
|
}),
|
|
88
84
|
})
|
|
89
85
|
}
|
|
86
|
+
|
|
87
|
+
fn get_timeout_type(&self) -> Option<TimeoutType> {
|
|
88
|
+
match self {
|
|
89
|
+
Self::TimedOut(ActFail {
|
|
90
|
+
failure:
|
|
91
|
+
Some(APIFailure {
|
|
92
|
+
failure_info:
|
|
93
|
+
Some(failure::FailureInfo::TimeoutFailureInfo(TimeoutFailureInfo {
|
|
94
|
+
timeout_type,
|
|
95
|
+
..
|
|
96
|
+
})),
|
|
97
|
+
..
|
|
98
|
+
}),
|
|
99
|
+
..
|
|
100
|
+
}) => TimeoutType::from_i32(*timeout_type),
|
|
101
|
+
_ => None,
|
|
102
|
+
}
|
|
103
|
+
}
|
|
90
104
|
}
|
|
91
105
|
|
|
92
106
|
#[derive(Debug, Clone)]
|
|
@@ -368,46 +382,30 @@ impl LocalActivityManager {
|
|
|
368
382
|
|
|
369
383
|
/// Returns the next pending local-activity related action, or None if shutdown has initiated
|
|
370
384
|
/// and there are no more remaining actions to take.
|
|
371
|
-
pub(crate) async fn next_pending(&self) -> Option<
|
|
385
|
+
pub(crate) async fn next_pending(&self) -> Option<NextPendingLAAction> {
|
|
372
386
|
let (new_or_retry, permit) = match self.rcvs.lock().await.next().await? {
|
|
373
387
|
NewOrCancel::Cancel(c) => {
|
|
374
388
|
return match c {
|
|
375
|
-
CancelOrTimeout::Cancel(c) => Some(
|
|
376
|
-
CancelOrTimeout::Timeout {
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
.
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
.map(|lai| lai.task_token.clone());
|
|
392
|
-
if let Some(task_token) = tt {
|
|
393
|
-
self.complete(&task_token, &resolution.result);
|
|
394
|
-
Some(ActivityTask {
|
|
395
|
-
task_token: task_token.0,
|
|
396
|
-
variant: Some(activity_task::Variant::Cancel(Cancel {
|
|
397
|
-
reason: ActivityCancelReason::TimedOut as i32,
|
|
398
|
-
})),
|
|
399
|
-
})
|
|
400
|
-
} else {
|
|
401
|
-
None
|
|
402
|
-
}
|
|
389
|
+
CancelOrTimeout::Cancel(c) => Some(NextPendingLAAction::Dispatch(c)),
|
|
390
|
+
CancelOrTimeout::Timeout { run_id, resolution } => {
|
|
391
|
+
let tt = self
|
|
392
|
+
.dat
|
|
393
|
+
.lock()
|
|
394
|
+
.la_info
|
|
395
|
+
.get(&ExecutingLAId {
|
|
396
|
+
run_id,
|
|
397
|
+
seq_num: resolution.seq,
|
|
398
|
+
})
|
|
399
|
+
.as_ref()
|
|
400
|
+
.map(|lai| lai.task_token.clone());
|
|
401
|
+
if let Some(task_token) = tt {
|
|
402
|
+
Some(NextPendingLAAction::Autocomplete(
|
|
403
|
+
self.complete(&task_token, resolution.result),
|
|
404
|
+
))
|
|
403
405
|
} else {
|
|
406
|
+
// This timeout is for a no-longer-tracked activity, so, whatever
|
|
404
407
|
None
|
|
405
|
-
}
|
|
406
|
-
Some(DispatchOrTimeoutLA::Timeout {
|
|
407
|
-
run_id,
|
|
408
|
-
resolution,
|
|
409
|
-
task,
|
|
410
|
-
})
|
|
408
|
+
}
|
|
411
409
|
}
|
|
412
410
|
};
|
|
413
411
|
}
|
|
@@ -443,18 +441,22 @@ impl LocalActivityManager {
|
|
|
443
441
|
if let Some(s2s) = sa.schedule_to_start_timeout.as_ref() {
|
|
444
442
|
let sat_for = new_la.schedule_time.elapsed().unwrap_or_default();
|
|
445
443
|
if sat_for > *s2s {
|
|
446
|
-
return Some(
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
444
|
+
return Some(NextPendingLAAction::Autocomplete(
|
|
445
|
+
LACompleteAction::Report {
|
|
446
|
+
run_id: new_la.workflow_exec_info.run_id,
|
|
447
|
+
resolution: LocalActivityResolution {
|
|
448
|
+
seq: sa.seq,
|
|
449
|
+
result: LocalActivityExecutionResult::timeout(
|
|
450
|
+
TimeoutType::ScheduleToStart,
|
|
451
|
+
),
|
|
452
|
+
runtime: sat_for,
|
|
453
|
+
attempt,
|
|
454
|
+
backoff: None,
|
|
455
|
+
original_schedule_time: orig_sched_time,
|
|
456
|
+
},
|
|
457
|
+
task: None,
|
|
455
458
|
},
|
|
456
|
-
|
|
457
|
-
});
|
|
459
|
+
));
|
|
458
460
|
}
|
|
459
461
|
}
|
|
460
462
|
|
|
@@ -474,7 +476,7 @@ impl LocalActivityManager {
|
|
|
474
476
|
);
|
|
475
477
|
|
|
476
478
|
let (schedule_to_close, start_to_close) = sa.close_timeouts.into_sched_and_start();
|
|
477
|
-
Some(
|
|
479
|
+
Some(NextPendingLAAction::Dispatch(ActivityTask {
|
|
478
480
|
task_token: tt.0,
|
|
479
481
|
variant: Some(activity_task::Variant::Start(Start {
|
|
480
482
|
workflow_namespace: self.namespace.clone(),
|
|
@@ -489,8 +491,15 @@ impl LocalActivityManager {
|
|
|
489
491
|
current_attempt_scheduled_time: Some(new_la.schedule_time.into()),
|
|
490
492
|
started_time: Some(SystemTime::now().into()),
|
|
491
493
|
attempt,
|
|
492
|
-
schedule_to_close_timeout: schedule_to_close
|
|
493
|
-
|
|
494
|
+
schedule_to_close_timeout: schedule_to_close
|
|
495
|
+
.unwrap_or(Duration::ZERO)
|
|
496
|
+
.try_into()
|
|
497
|
+
.ok(),
|
|
498
|
+
start_to_close_timeout: start_to_close
|
|
499
|
+
.or(schedule_to_close)
|
|
500
|
+
.unwrap()
|
|
501
|
+
.try_into()
|
|
502
|
+
.ok(),
|
|
494
503
|
heartbeat_timeout: None,
|
|
495
504
|
retry_policy: Some(sa.retry_policy),
|
|
496
505
|
is_local: true,
|
|
@@ -498,11 +507,11 @@ impl LocalActivityManager {
|
|
|
498
507
|
}))
|
|
499
508
|
}
|
|
500
509
|
|
|
501
|
-
/// Mark a local activity as having completed
|
|
510
|
+
/// Mark a local activity as having completed
|
|
502
511
|
pub(crate) fn complete(
|
|
503
512
|
&self,
|
|
504
513
|
task_token: &TaskToken,
|
|
505
|
-
status:
|
|
514
|
+
status: LocalActivityExecutionResult,
|
|
506
515
|
) -> LACompleteAction {
|
|
507
516
|
let mut dlock = self.dat.lock();
|
|
508
517
|
if let Some(info) = dlock.outstanding_activity_tasks.remove(task_token) {
|
|
@@ -524,37 +533,92 @@ impl LocalActivityManager {
|
|
|
524
533
|
}
|
|
525
534
|
}
|
|
526
535
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
}
|
|
535
|
-
LocalActivityExecutionResult::Failed(f) => {
|
|
536
|
-
if let Some(backoff_dur) = info.la_info.schedule_cmd.retry_policy.should_retry(
|
|
536
|
+
enum Outcome {
|
|
537
|
+
FailurePath { backoff: Option<Duration> },
|
|
538
|
+
JustReport,
|
|
539
|
+
}
|
|
540
|
+
macro_rules! calc_backoff {
|
|
541
|
+
($fail: ident) => {
|
|
542
|
+
info.la_info.schedule_cmd.retry_policy.should_retry(
|
|
537
543
|
info.attempt as usize,
|
|
538
|
-
|
|
544
|
+
$fail
|
|
545
|
+
.failure
|
|
539
546
|
.as_ref()
|
|
540
547
|
.and_then(|f| f.maybe_application_failure()),
|
|
541
|
-
)
|
|
548
|
+
)
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
let mut is_timeout = false;
|
|
553
|
+
let outcome = match &status {
|
|
554
|
+
LocalActivityExecutionResult::Failed(fail) => Outcome::FailurePath {
|
|
555
|
+
backoff: calc_backoff!(fail),
|
|
556
|
+
},
|
|
557
|
+
LocalActivityExecutionResult::TimedOut(fail)
|
|
558
|
+
if matches!(status.get_timeout_type(), Some(TimeoutType::StartToClose)) =>
|
|
559
|
+
{
|
|
560
|
+
// Start to close timeouts are retryable, other timeout types aren't.
|
|
561
|
+
is_timeout = true;
|
|
562
|
+
Outcome::FailurePath {
|
|
563
|
+
backoff: calc_backoff!(fail),
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
LocalActivityExecutionResult::TimedOut(_) => {
|
|
567
|
+
is_timeout = true;
|
|
568
|
+
Outcome::JustReport
|
|
569
|
+
}
|
|
570
|
+
LocalActivityExecutionResult::Completed(_)
|
|
571
|
+
| LocalActivityExecutionResult::Cancelled { .. } => Outcome::JustReport,
|
|
572
|
+
};
|
|
573
|
+
|
|
574
|
+
let mut resolution = LocalActivityResolution {
|
|
575
|
+
seq: info.la_info.schedule_cmd.seq,
|
|
576
|
+
result: status,
|
|
577
|
+
runtime: info.dispatch_time.elapsed(),
|
|
578
|
+
attempt: info.attempt,
|
|
579
|
+
backoff: None,
|
|
580
|
+
original_schedule_time: info.la_info.schedule_cmd.original_schedule_time,
|
|
581
|
+
};
|
|
582
|
+
// We want to generate a cancel task if the reason for failure was a timeout.
|
|
583
|
+
let task = if is_timeout {
|
|
584
|
+
Some(ActivityTask {
|
|
585
|
+
task_token: task_token.clone().0,
|
|
586
|
+
variant: Some(activity_task::Variant::Cancel(Cancel {
|
|
587
|
+
reason: ActivityCancelReason::TimedOut as i32,
|
|
588
|
+
})),
|
|
589
|
+
})
|
|
590
|
+
} else {
|
|
591
|
+
None
|
|
592
|
+
};
|
|
593
|
+
|
|
594
|
+
match outcome {
|
|
595
|
+
Outcome::FailurePath { backoff } => {
|
|
596
|
+
if let Some(backoff_dur) = backoff {
|
|
597
|
+
let fail_or_timeout = if is_timeout { "timed out" } else { "failed" };
|
|
542
598
|
let will_use_timer =
|
|
543
599
|
backoff_dur > info.la_info.schedule_cmd.local_retry_threshold;
|
|
544
600
|
debug!(run_id = %info.la_info.workflow_exec_info.run_id,
|
|
545
601
|
seq_num = %info.la_info.schedule_cmd.seq,
|
|
546
602
|
attempt = %info.attempt,
|
|
547
603
|
will_use_timer,
|
|
548
|
-
"Local activity
|
|
549
|
-
|
|
604
|
+
"Local activity {}, will retry after backing off for {:?}",
|
|
605
|
+
fail_or_timeout,
|
|
606
|
+
backoff_dur
|
|
550
607
|
);
|
|
551
608
|
if will_use_timer {
|
|
552
|
-
//
|
|
553
|
-
//
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
609
|
+
// This la needs to write a failure marker, and then we will tell lang how
|
|
610
|
+
// long of a timer to schedule to back off for. We do this because there are
|
|
611
|
+
// no other situations where core generates "internal" commands so it is
|
|
612
|
+
// much simpler for lang to reply with the timer / next LA command than to
|
|
613
|
+
// do it internally. Plus, this backoff hack we'd like to eliminate
|
|
614
|
+
// eventually.
|
|
615
|
+
resolution.backoff =
|
|
616
|
+
Some(backoff_dur.try_into().expect("backoff fits into proto"));
|
|
617
|
+
return LACompleteAction::Report {
|
|
618
|
+
run_id: info.la_info.workflow_exec_info.run_id,
|
|
619
|
+
resolution,
|
|
620
|
+
task,
|
|
621
|
+
};
|
|
558
622
|
}
|
|
559
623
|
// Immediately create a new task token for the to-be-retried LA
|
|
560
624
|
let tt = dlock.gen_next_token();
|
|
@@ -586,14 +650,32 @@ impl LocalActivityManager {
|
|
|
586
650
|
timeout_bag: maybe_old_lai.and_then(|old| old.timeout_bag),
|
|
587
651
|
},
|
|
588
652
|
);
|
|
589
|
-
|
|
590
|
-
LACompleteAction::WillBeRetried
|
|
653
|
+
LACompleteAction::WillBeRetried(task)
|
|
591
654
|
} else {
|
|
592
|
-
LACompleteAction::Report
|
|
655
|
+
LACompleteAction::Report {
|
|
656
|
+
run_id: info.la_info.workflow_exec_info.run_id,
|
|
657
|
+
resolution,
|
|
658
|
+
task,
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
Outcome::JustReport => {
|
|
663
|
+
self.complete_notify.notify_one();
|
|
664
|
+
LACompleteAction::Report {
|
|
665
|
+
run_id: info.la_info.workflow_exec_info.run_id,
|
|
666
|
+
resolution,
|
|
667
|
+
task,
|
|
593
668
|
}
|
|
594
669
|
}
|
|
595
670
|
}
|
|
596
671
|
} else {
|
|
672
|
+
if !matches!(
|
|
673
|
+
status,
|
|
674
|
+
LocalActivityExecutionResult::TimedOut(_)
|
|
675
|
+
| LocalActivityExecutionResult::Cancelled { .. }
|
|
676
|
+
) {
|
|
677
|
+
warn!("Tried to complete untracked local activity");
|
|
678
|
+
}
|
|
597
679
|
LACompleteAction::Untracked
|
|
598
680
|
}
|
|
599
681
|
}
|
|
@@ -668,13 +750,18 @@ impl LocalActivityManager {
|
|
|
668
750
|
#[derive(Debug)]
|
|
669
751
|
#[allow(clippy::large_enum_variant)] // Most will be reported
|
|
670
752
|
pub(crate) enum LACompleteAction {
|
|
671
|
-
/// Caller should report the status to the workflow
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
753
|
+
/// Caller should report the status to the workflow machines - which may resolve the activity
|
|
754
|
+
/// or might result in scheduling a backoff timer.
|
|
755
|
+
Report {
|
|
756
|
+
run_id: String,
|
|
757
|
+
resolution: LocalActivityResolution,
|
|
758
|
+
/// May be set if a task also needs to be dispatched to lang. EX: Cancelling a timed-out
|
|
759
|
+
/// activity.
|
|
760
|
+
task: Option<ActivityTask>,
|
|
761
|
+
},
|
|
675
762
|
/// The activity will be re-enqueued for another attempt (and so status should not be reported
|
|
676
763
|
/// to the workflow)
|
|
677
|
-
WillBeRetried,
|
|
764
|
+
WillBeRetried(Option<ActivityTask>),
|
|
678
765
|
/// The activity was unknown
|
|
679
766
|
Untracked,
|
|
680
767
|
}
|
|
@@ -695,7 +782,6 @@ enum CancelOrTimeout {
|
|
|
695
782
|
Timeout {
|
|
696
783
|
run_id: String,
|
|
697
784
|
resolution: LocalActivityResolution,
|
|
698
|
-
dispatch_cancel: bool,
|
|
699
785
|
},
|
|
700
786
|
}
|
|
701
787
|
|
|
@@ -787,7 +873,6 @@ impl TimeoutBag {
|
|
|
787
873
|
let timeout_dat = CancelOrTimeout::Timeout {
|
|
788
874
|
run_id: new_la.workflow_exec_info.run_id.clone(),
|
|
789
875
|
resolution,
|
|
790
|
-
dispatch_cancel: true,
|
|
791
876
|
};
|
|
792
877
|
let start_to_close_dur_and_dat = start_to_close.map(|d| (d, timeout_dat.clone()));
|
|
793
878
|
let fut_dat = schedule_to_close.map(|s2c| (s2c, timeout_dat));
|
|
@@ -811,7 +896,7 @@ impl TimeoutBag {
|
|
|
811
896
|
|
|
812
897
|
/// Must be called once the associated local activity has been started / dispatched to lang.
|
|
813
898
|
fn mark_started(&mut self) {
|
|
814
|
-
if let Some((start_to_close, mut dat)) = self.start_to_close_dur_and_dat.
|
|
899
|
+
if let Some((start_to_close, mut dat)) = self.start_to_close_dur_and_dat.as_ref().cloned() {
|
|
815
900
|
let started_t = Instant::now();
|
|
816
901
|
let cchan = self.cancel_chan.clone();
|
|
817
902
|
self.start_to_close_handle = Some(tokio::spawn(async move {
|
|
@@ -848,15 +933,24 @@ mod tests {
|
|
|
848
933
|
};
|
|
849
934
|
use tokio::task::yield_now;
|
|
850
935
|
|
|
851
|
-
impl
|
|
936
|
+
impl NextPendingLAAction {
|
|
852
937
|
fn unwrap(self) -> ActivityTask {
|
|
853
938
|
match self {
|
|
854
|
-
|
|
939
|
+
NextPendingLAAction::Dispatch(t) => t,
|
|
855
940
|
_ => {
|
|
856
941
|
panic!("Non-dispatched action returned")
|
|
857
942
|
}
|
|
858
943
|
}
|
|
859
944
|
}
|
|
945
|
+
|
|
946
|
+
fn is_timeout(&self, with_task: bool) -> bool {
|
|
947
|
+
matches!(
|
|
948
|
+
self,
|
|
949
|
+
Self::Autocomplete(LACompleteAction::Report{task, resolution, ..})
|
|
950
|
+
if matches!(resolution.result, LocalActivityExecutionResult::TimedOut(_)) &&
|
|
951
|
+
task.is_some() == with_task
|
|
952
|
+
)
|
|
953
|
+
}
|
|
860
954
|
}
|
|
861
955
|
|
|
862
956
|
#[tokio::test]
|
|
@@ -886,7 +980,7 @@ mod tests {
|
|
|
886
980
|
let complete_branch = async {
|
|
887
981
|
lam.complete(
|
|
888
982
|
&next_tt,
|
|
889
|
-
|
|
983
|
+
LocalActivityExecutionResult::Completed(Default::default()),
|
|
890
984
|
)
|
|
891
985
|
};
|
|
892
986
|
tokio::select! {
|
|
@@ -926,7 +1020,7 @@ mod tests {
|
|
|
926
1020
|
// Spin until the receive lock has been grabbed by the call to pending, to ensure
|
|
927
1021
|
// it's advanced enough
|
|
928
1022
|
while lam.rcvs.try_lock().is_ok() { yield_now().await; }
|
|
929
|
-
lam.complete(&tt,
|
|
1023
|
+
lam.complete(&tt, LocalActivityExecutionResult::Completed(Default::default()));
|
|
930
1024
|
} => (),
|
|
931
1025
|
};
|
|
932
1026
|
}
|
|
@@ -986,10 +1080,10 @@ mod tests {
|
|
|
986
1080
|
let tt = TaskToken(next.task_token);
|
|
987
1081
|
let res = lam.complete(
|
|
988
1082
|
&tt,
|
|
989
|
-
|
|
1083
|
+
LocalActivityExecutionResult::Failed(Default::default()),
|
|
990
1084
|
);
|
|
991
|
-
assert_matches!(res, LACompleteAction::
|
|
992
|
-
if
|
|
1085
|
+
assert_matches!(res, LACompleteAction::Report{resolution, ..}
|
|
1086
|
+
if resolution.backoff.as_ref().unwrap().seconds == 10 && resolution.attempt == 5
|
|
993
1087
|
)
|
|
994
1088
|
}
|
|
995
1089
|
|
|
@@ -1021,7 +1115,7 @@ mod tests {
|
|
|
1021
1115
|
let tt = TaskToken(next.task_token);
|
|
1022
1116
|
let res = lam.complete(
|
|
1023
1117
|
&tt,
|
|
1024
|
-
|
|
1118
|
+
LocalActivityExecutionResult::Failed(ActFail {
|
|
1025
1119
|
failure: Some(Failure {
|
|
1026
1120
|
failure_info: Some(FailureInfo::ApplicationFailureInfo(
|
|
1027
1121
|
ApplicationFailureInfo {
|
|
@@ -1034,7 +1128,7 @@ mod tests {
|
|
|
1034
1128
|
}),
|
|
1035
1129
|
}),
|
|
1036
1130
|
);
|
|
1037
|
-
assert_matches!(res, LACompleteAction::Report
|
|
1131
|
+
assert_matches!(res, LACompleteAction::Report { .. });
|
|
1038
1132
|
}
|
|
1039
1133
|
|
|
1040
1134
|
#[tokio::test]
|
|
@@ -1068,7 +1162,7 @@ mod tests {
|
|
|
1068
1162
|
let tt = TaskToken(next.task_token);
|
|
1069
1163
|
lam.complete(
|
|
1070
1164
|
&tt,
|
|
1071
|
-
|
|
1165
|
+
LocalActivityExecutionResult::Failed(Default::default()),
|
|
1072
1166
|
);
|
|
1073
1167
|
// Cancel the activity, which is performing local backoff
|
|
1074
1168
|
let immediate_res = lam.enqueue([LocalActRequest::Cancel(ExecutingLAId {
|
|
@@ -1115,7 +1209,7 @@ mod tests {
|
|
|
1115
1209
|
let tt = TaskToken(next.task_token);
|
|
1116
1210
|
lam.complete(
|
|
1117
1211
|
&tt,
|
|
1118
|
-
|
|
1212
|
+
LocalActivityExecutionResult::Failed(Default::default()),
|
|
1119
1213
|
);
|
|
1120
1214
|
lam.next_pending().await.unwrap().unwrap();
|
|
1121
1215
|
assert_eq!(lam.num_in_backoff(), 0);
|
|
@@ -1152,10 +1246,7 @@ mod tests {
|
|
|
1152
1246
|
// Wait more than the timeout before grabbing the task
|
|
1153
1247
|
sleep(timeout + Duration::from_millis(10)).await;
|
|
1154
1248
|
|
|
1155
|
-
|
|
1156
|
-
lam.next_pending().await.unwrap(),
|
|
1157
|
-
DispatchOrTimeoutLA::Timeout { .. }
|
|
1158
|
-
);
|
|
1249
|
+
assert!(dbg!(lam.next_pending().await.unwrap()).is_timeout(false));
|
|
1159
1250
|
assert_eq!(lam.num_in_backoff(), 0);
|
|
1160
1251
|
assert_eq!(lam.num_outstanding(), 0);
|
|
1161
1252
|
}
|
|
@@ -1180,6 +1271,7 @@ mod tests {
|
|
|
1180
1271
|
retry_policy: RetryPolicy {
|
|
1181
1272
|
initial_interval: Some(prost_dur!(from_millis(10))),
|
|
1182
1273
|
backoff_coefficient: 1.0,
|
|
1274
|
+
maximum_attempts: 1,
|
|
1183
1275
|
..Default::default()
|
|
1184
1276
|
},
|
|
1185
1277
|
local_retry_threshold: Duration::from_secs(500),
|
|
@@ -1195,15 +1287,27 @@ mod tests {
|
|
|
1195
1287
|
}
|
|
1196
1288
|
.into()]);
|
|
1197
1289
|
|
|
1198
|
-
lam.next_pending().await.unwrap().unwrap();
|
|
1290
|
+
let next = lam.next_pending().await.unwrap().unwrap();
|
|
1199
1291
|
assert_eq!(lam.num_in_backoff(), 0);
|
|
1200
1292
|
assert_eq!(lam.num_outstanding(), 1);
|
|
1201
1293
|
|
|
1294
|
+
if let Some(activity_task::Variant::Start(start)) = next.variant {
|
|
1295
|
+
// Validate that timeouts reported to lang matches what server would have provided
|
|
1296
|
+
// if this had been a normal activity with the same timeout configuration.
|
|
1297
|
+
if is_schedule {
|
|
1298
|
+
assert_eq!(start.schedule_to_close_timeout, timeout.try_into().ok());
|
|
1299
|
+
assert_eq!(start.start_to_close_timeout, timeout.try_into().ok());
|
|
1300
|
+
} else {
|
|
1301
|
+
assert_eq!(
|
|
1302
|
+
start.schedule_to_close_timeout,
|
|
1303
|
+
Duration::ZERO.try_into().ok()
|
|
1304
|
+
);
|
|
1305
|
+
assert_eq!(start.start_to_close_timeout, timeout.try_into().ok());
|
|
1306
|
+
}
|
|
1307
|
+
};
|
|
1308
|
+
|
|
1202
1309
|
sleep(timeout + Duration::from_millis(10)).await;
|
|
1203
|
-
|
|
1204
|
-
lam.next_pending().await.unwrap(),
|
|
1205
|
-
DispatchOrTimeoutLA::Timeout { .. }
|
|
1206
|
-
);
|
|
1310
|
+
assert!(lam.next_pending().await.unwrap().is_timeout(true));
|
|
1207
1311
|
assert_eq!(lam.num_outstanding(), 0);
|
|
1208
1312
|
}
|
|
1209
1313
|
|
|
@@ -1267,7 +1371,7 @@ mod tests {
|
|
|
1267
1371
|
let tt = TaskToken(next.task_token);
|
|
1268
1372
|
lam.complete(
|
|
1269
1373
|
&tt,
|
|
1270
|
-
|
|
1374
|
+
LocalActivityExecutionResult::Failed(Default::default()),
|
|
1271
1375
|
);
|
|
1272
1376
|
}
|
|
1273
1377
|
};
|