@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.
Files changed (90) hide show
  1. package/Cargo.lock +245 -247
  2. package/Cargo.toml +1 -1
  3. package/lib/errors.d.ts +9 -0
  4. package/lib/errors.js +13 -0
  5. package/lib/errors.js.map +1 -1
  6. package/lib/index.d.ts +19 -3
  7. package/lib/index.js.map +1 -1
  8. package/package.json +3 -3
  9. package/releases/aarch64-apple-darwin/index.node +0 -0
  10. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  11. package/releases/x86_64-apple-darwin/index.node +0 -0
  12. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  13. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  14. package/sdk-core/.github/workflows/heavy.yml +1 -1
  15. package/sdk-core/.github/workflows/semgrep.yml +25 -0
  16. package/sdk-core/README.md +2 -0
  17. package/sdk-core/cargo-tokio-console.sh +5 -0
  18. package/sdk-core/client/src/lib.rs +6 -41
  19. package/sdk-core/client/src/raw.rs +9 -0
  20. package/sdk-core/client/src/retry.rs +0 -16
  21. package/sdk-core/core/Cargo.toml +9 -5
  22. package/sdk-core/core/src/abstractions.rs +7 -75
  23. package/sdk-core/core/src/core_tests/activity_tasks.rs +16 -8
  24. package/sdk-core/core/src/core_tests/local_activities.rs +97 -5
  25. package/sdk-core/core/src/core_tests/mod.rs +1 -1
  26. package/sdk-core/core/src/core_tests/workers.rs +16 -16
  27. package/sdk-core/core/src/core_tests/workflow_tasks.rs +247 -28
  28. package/sdk-core/core/src/lib.rs +2 -3
  29. package/sdk-core/core/src/pollers/mod.rs +30 -3
  30. package/sdk-core/core/src/pollers/poll_buffer.rs +166 -77
  31. package/sdk-core/core/src/protosext/mod.rs +4 -8
  32. package/sdk-core/core/src/replay/mod.rs +1 -1
  33. package/sdk-core/core/src/telemetry/metrics.rs +9 -0
  34. package/sdk-core/core/src/telemetry/mod.rs +3 -0
  35. package/sdk-core/core/src/test_help/mod.rs +9 -16
  36. package/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +6 -31
  37. package/sdk-core/core/src/worker/activities/local_activities.rs +214 -110
  38. package/sdk-core/core/src/worker/activities.rs +72 -47
  39. package/sdk-core/core/src/worker/client/mocks.rs +1 -1
  40. package/sdk-core/core/src/worker/client.rs +45 -32
  41. package/sdk-core/core/src/worker/mod.rs +170 -122
  42. package/sdk-core/core/src/worker/workflow/driven_workflow.rs +0 -4
  43. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +9 -2
  44. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +9 -2
  45. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +6 -3
  46. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +74 -22
  47. package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +3 -2
  48. package/sdk-core/core/src/worker/workflow/managed_run.rs +16 -3
  49. package/sdk-core/core/src/worker/workflow/mod.rs +13 -22
  50. package/sdk-core/core/src/worker/workflow/run_cache.rs +5 -0
  51. package/sdk-core/core/src/worker/workflow/wft_extraction.rs +4 -7
  52. package/sdk-core/core/src/worker/workflow/wft_poller.rs +38 -8
  53. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +1 -0
  54. package/sdk-core/core-api/src/worker.rs +43 -2
  55. package/sdk-core/protos/api_upstream/Makefile +1 -1
  56. package/sdk-core/protos/api_upstream/buf.yaml +1 -6
  57. package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +12 -0
  58. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +11 -0
  59. package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +13 -2
  60. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +1 -0
  61. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +2 -0
  62. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +9 -0
  63. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +19 -0
  64. package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +5 -0
  65. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +36 -4
  66. package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +24 -7
  67. package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +4 -0
  68. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +76 -44
  69. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +23 -1
  70. package/sdk-core/protos/google/rpc/status.proto +52 -0
  71. package/sdk-core/protos/local/temporal/sdk/core/common/common.proto +16 -0
  72. package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +4 -0
  73. package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +6 -0
  74. package/sdk-core/sdk/src/lib.rs +31 -10
  75. package/sdk-core/sdk/src/workflow_future.rs +7 -5
  76. package/sdk-core/sdk-core-protos/src/history_builder.rs +2 -0
  77. package/sdk-core/sdk-core-protos/src/history_info.rs +1 -0
  78. package/sdk-core/sdk-core-protos/src/lib.rs +82 -73
  79. package/sdk-core/test-utils/Cargo.toml +1 -1
  80. package/sdk-core/test-utils/src/lib.rs +50 -37
  81. package/sdk-core/tests/integ_tests/metrics_tests.rs +143 -10
  82. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +26 -15
  83. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +1 -1
  84. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +2 -2
  85. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +5 -1
  86. package/sdk-core/tests/integ_tests/workflow_tests.rs +1 -0
  87. package/src/conversions.rs +9 -2
  88. package/src/runtime.rs +5 -7
  89. package/ts/errors.ts +15 -0
  90. 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 DispatchOrTimeoutLA {
42
+ pub(crate) enum NextPendingLAAction {
43
43
  /// Send the activity task to lang
44
44
  Dispatch(ActivityTask),
45
- /// Notify the machines (and maybe lang) that this LA has timed out
46
- Timeout {
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<DispatchOrTimeoutLA> {
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(DispatchOrTimeoutLA::Dispatch(c)),
376
- CancelOrTimeout::Timeout {
377
- run_id,
378
- resolution,
379
- dispatch_cancel,
380
- } => {
381
- let task = if dispatch_cancel {
382
- let tt = self
383
- .dat
384
- .lock()
385
- .la_info
386
- .get(&ExecutingLAId {
387
- run_id: run_id.clone(),
388
- seq_num: resolution.seq,
389
- })
390
- .as_ref()
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(DispatchOrTimeoutLA::Timeout {
447
- run_id: new_la.workflow_exec_info.run_id,
448
- resolution: LocalActivityResolution {
449
- seq: sa.seq,
450
- result: LocalActivityExecutionResult::timeout(TimeoutType::ScheduleToStart),
451
- runtime: sat_for,
452
- attempt,
453
- backoff: None,
454
- original_schedule_time: orig_sched_time,
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
- task: None,
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(DispatchOrTimeoutLA::Dispatch(ActivityTask {
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.and_then(|d| d.try_into().ok()),
493
- start_to_close_timeout: start_to_close.and_then(|d| d.try_into().ok()),
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 (pass, fail, or cancelled)
510
+ /// Mark a local activity as having completed
502
511
  pub(crate) fn complete(
503
512
  &self,
504
513
  task_token: &TaskToken,
505
- status: &LocalActivityExecutionResult,
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
- match status {
528
- LocalActivityExecutionResult::Completed(_)
529
- | LocalActivityExecutionResult::TimedOut(_)
530
- | LocalActivityExecutionResult::Cancelled { .. } => {
531
- // Timeouts are included in this branch since they are not retried
532
- self.complete_notify.notify_one();
533
- LACompleteAction::Report(info)
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
- f.failure
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 failed, will retry after backing off for {:?}",
549
- backoff_dur
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
- // We want this to be reported, as the workflow will mark this
553
- // failure down, then start a timer for backoff.
554
- return LACompleteAction::LangDoesTimerBackoff(
555
- backoff_dur.try_into().expect("backoff fits into proto"),
556
- info,
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(info)
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
- Report(LocalInFlightActInfo),
673
- /// Lang needs to be told to do the schedule-a-timer-then-rerun hack
674
- LangDoesTimerBackoff(prost_types::Duration, LocalInFlightActInfo),
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.take() {
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 DispatchOrTimeoutLA {
936
+ impl NextPendingLAAction {
852
937
  fn unwrap(self) -> ActivityTask {
853
938
  match self {
854
- DispatchOrTimeoutLA::Dispatch(t) => t,
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
- &LocalActivityExecutionResult::Completed(Default::default()),
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, &LocalActivityExecutionResult::Completed(Default::default()));
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
- &LocalActivityExecutionResult::Failed(Default::default()),
1083
+ LocalActivityExecutionResult::Failed(Default::default()),
990
1084
  );
991
- assert_matches!(res, LACompleteAction::LangDoesTimerBackoff(dur, info)
992
- if dur.seconds == 10 && info.attempt == 5
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
- &LocalActivityExecutionResult::Failed(ActFail {
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
- &LocalActivityExecutionResult::Failed(Default::default()),
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
- &LocalActivityExecutionResult::Failed(Default::default()),
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
- assert_matches!(
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
- assert_matches!(
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
- &LocalActivityExecutionResult::Failed(Default::default()),
1374
+ LocalActivityExecutionResult::Failed(Default::default()),
1271
1375
  );
1272
1376
  }
1273
1377
  };