@temporalio/core-bridge 0.17.2 → 0.18.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.
Files changed (170) hide show
  1. package/Cargo.lock +339 -226
  2. package/Cargo.toml +7 -3
  3. package/common.js +50 -0
  4. package/index.d.ts +7 -0
  5. package/index.js +12 -0
  6. package/package.json +7 -4
  7. package/releases/aarch64-apple-darwin/index.node +0 -0
  8. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  9. package/{index.node → releases/index.node} +0 -0
  10. package/releases/x86_64-apple-darwin/index.node +0 -0
  11. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  12. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  13. package/scripts/build.js +10 -50
  14. package/sdk-core/.buildkite/docker/Dockerfile +1 -1
  15. package/sdk-core/.buildkite/docker/docker-compose.yaml +2 -2
  16. package/sdk-core/.buildkite/pipeline.yml +2 -0
  17. package/sdk-core/Cargo.toml +1 -88
  18. package/sdk-core/README.md +30 -6
  19. package/sdk-core/bridge-ffi/Cargo.toml +24 -0
  20. package/sdk-core/bridge-ffi/LICENSE.txt +23 -0
  21. package/sdk-core/bridge-ffi/build.rs +25 -0
  22. package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +216 -0
  23. package/sdk-core/bridge-ffi/src/lib.rs +829 -0
  24. package/sdk-core/bridge-ffi/src/wrappers.rs +193 -0
  25. package/sdk-core/client/Cargo.toml +32 -0
  26. package/sdk-core/{src/pollers/gateway.rs → client/src/lib.rs} +101 -195
  27. package/sdk-core/client/src/metrics.rs +89 -0
  28. package/sdk-core/client/src/mocks.rs +167 -0
  29. package/sdk-core/{src/pollers → client/src}/retry.rs +172 -14
  30. package/sdk-core/core/Cargo.toml +96 -0
  31. package/sdk-core/{src → core/src}/core_tests/activity_tasks.rs +193 -37
  32. package/sdk-core/{src → core/src}/core_tests/child_workflows.rs +14 -14
  33. package/sdk-core/{src → core/src}/core_tests/determinism.rs +8 -8
  34. package/sdk-core/core/src/core_tests/local_activities.rs +328 -0
  35. package/sdk-core/{src → core/src}/core_tests/mod.rs +6 -9
  36. package/sdk-core/{src → core/src}/core_tests/queries.rs +45 -52
  37. package/sdk-core/{src → core/src}/core_tests/replay_flag.rs +8 -12
  38. package/sdk-core/{src → core/src}/core_tests/workers.rs +120 -33
  39. package/sdk-core/{src → core/src}/core_tests/workflow_cancels.rs +16 -26
  40. package/sdk-core/{src → core/src}/core_tests/workflow_tasks.rs +264 -286
  41. package/sdk-core/core/src/lib.rs +374 -0
  42. package/sdk-core/{src → core/src}/log_export.rs +3 -27
  43. package/sdk-core/core/src/pending_activations.rs +162 -0
  44. package/sdk-core/{src → core/src}/pollers/mod.rs +4 -22
  45. package/sdk-core/{src → core/src}/pollers/poll_buffer.rs +1 -1
  46. package/sdk-core/core/src/protosext/mod.rs +396 -0
  47. package/sdk-core/core/src/replay/mod.rs +210 -0
  48. package/sdk-core/core/src/retry_logic.rs +144 -0
  49. package/sdk-core/{src → core/src}/telemetry/metrics.rs +3 -58
  50. package/sdk-core/{src → core/src}/telemetry/mod.rs +8 -8
  51. package/sdk-core/{src → core/src}/telemetry/prometheus_server.rs +0 -0
  52. package/sdk-core/{src → core/src}/test_help/mod.rs +34 -73
  53. package/sdk-core/{src → core/src}/worker/activities/activity_heartbeat_manager.rs +95 -42
  54. package/sdk-core/core/src/worker/activities/local_activities.rs +973 -0
  55. package/sdk-core/{src → core/src}/worker/activities.rs +52 -33
  56. package/sdk-core/{src → core/src}/worker/dispatcher.rs +8 -6
  57. package/sdk-core/{src → core/src}/worker/mod.rs +305 -195
  58. package/sdk-core/core/src/worker/wft_delivery.rs +81 -0
  59. package/sdk-core/{src → core/src}/workflow/bridge.rs +5 -2
  60. package/sdk-core/{src → core/src}/workflow/driven_workflow.rs +17 -7
  61. package/sdk-core/{src → core/src}/workflow/history_update.rs +33 -7
  62. package/sdk-core/{src → core/src/workflow}/machines/activity_state_machine.rs +26 -26
  63. package/sdk-core/{src → core/src/workflow}/machines/cancel_external_state_machine.rs +8 -11
  64. package/sdk-core/{src → core/src/workflow}/machines/cancel_workflow_state_machine.rs +19 -21
  65. package/sdk-core/{src → core/src/workflow}/machines/child_workflow_state_machine.rs +19 -21
  66. package/sdk-core/{src → core/src/workflow}/machines/complete_workflow_state_machine.rs +3 -5
  67. package/sdk-core/{src → core/src/workflow}/machines/continue_as_new_workflow_state_machine.rs +18 -18
  68. package/sdk-core/{src → core/src/workflow}/machines/fail_workflow_state_machine.rs +5 -6
  69. package/sdk-core/core/src/workflow/machines/local_activity_state_machine.rs +1451 -0
  70. package/sdk-core/{src → core/src/workflow}/machines/mod.rs +54 -107
  71. package/sdk-core/{src → core/src/workflow}/machines/mutable_side_effect_state_machine.rs +0 -0
  72. package/sdk-core/{src → core/src/workflow}/machines/patch_state_machine.rs +29 -30
  73. package/sdk-core/{src → core/src/workflow}/machines/side_effect_state_machine.rs +0 -0
  74. package/sdk-core/{src → core/src/workflow}/machines/signal_external_state_machine.rs +17 -19
  75. package/sdk-core/{src → core/src/workflow}/machines/timer_state_machine.rs +20 -21
  76. package/sdk-core/{src → core/src/workflow}/machines/transition_coverage.rs +5 -2
  77. package/sdk-core/{src → core/src/workflow}/machines/upsert_search_attributes_state_machine.rs +0 -0
  78. package/sdk-core/core/src/workflow/machines/workflow_machines/local_acts.rs +96 -0
  79. package/sdk-core/{src → core/src/workflow}/machines/workflow_machines.rs +344 -160
  80. package/sdk-core/{src → core/src/workflow}/machines/workflow_task_state_machine.rs +1 -1
  81. package/sdk-core/{src → core/src}/workflow/mod.rs +200 -39
  82. package/sdk-core/{src → core/src}/workflow/workflow_tasks/cache_manager.rs +0 -0
  83. package/sdk-core/{src → core/src}/workflow/workflow_tasks/concurrency_manager.rs +38 -5
  84. package/sdk-core/{src → core/src}/workflow/workflow_tasks/mod.rs +297 -81
  85. package/sdk-core/{test_utils → core-api}/Cargo.toml +10 -7
  86. package/sdk-core/{src → core-api/src}/errors.rs +42 -90
  87. package/sdk-core/core-api/src/lib.rs +158 -0
  88. package/sdk-core/{src/worker/config.rs → core-api/src/worker.rs} +18 -23
  89. package/sdk-core/etc/deps.svg +156 -0
  90. package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +5 -5
  91. package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +3 -5
  92. package/sdk-core/fsm/rustfsm_trait/src/lib.rs +7 -1
  93. package/sdk-core/histories/fail_wf_task.bin +0 -0
  94. package/sdk-core/histories/timer_workflow_history.bin +0 -0
  95. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +44 -13
  96. package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +19 -1
  97. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +1 -1
  98. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +9 -0
  99. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +1 -0
  100. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +1 -0
  101. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +13 -0
  102. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +14 -7
  103. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +176 -18
  104. package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +6 -0
  105. package/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +11 -0
  106. package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +3 -0
  107. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +156 -7
  108. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +135 -104
  109. package/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +78 -0
  110. package/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +78 -0
  111. package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +205 -0
  112. package/sdk-core/protos/local/temporal/sdk/core/bridge/service.proto +61 -0
  113. package/sdk-core/protos/local/{child_workflow.proto → temporal/sdk/core/child_workflow/child_workflow.proto} +1 -1
  114. package/sdk-core/protos/local/{common.proto → temporal/sdk/core/common/common.proto} +5 -3
  115. package/sdk-core/protos/local/{core_interface.proto → temporal/sdk/core/core_interface.proto} +10 -10
  116. package/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +30 -0
  117. package/sdk-core/protos/local/{workflow_activation.proto → temporal/sdk/core/workflow_activation/workflow_activation.proto} +35 -11
  118. package/sdk-core/protos/local/{workflow_commands.proto → temporal/sdk/core/workflow_commands/workflow_commands.proto} +55 -4
  119. package/sdk-core/protos/local/{workflow_completion.proto → temporal/sdk/core/workflow_completion/workflow_completion.proto} +3 -3
  120. package/sdk-core/sdk/Cargo.toml +32 -0
  121. package/sdk-core/{src/prototype_rust_sdk → sdk/src}/conversions.rs +0 -0
  122. package/sdk-core/sdk/src/lib.rs +699 -0
  123. package/sdk-core/sdk/src/payload_converter.rs +11 -0
  124. package/sdk-core/sdk/src/workflow_context/options.rs +180 -0
  125. package/sdk-core/{src/prototype_rust_sdk → sdk/src}/workflow_context.rs +201 -124
  126. package/sdk-core/{src/prototype_rust_sdk → sdk/src}/workflow_future.rs +63 -30
  127. package/sdk-core/sdk-core-protos/Cargo.toml +10 -0
  128. package/sdk-core/sdk-core-protos/build.rs +28 -6
  129. package/sdk-core/sdk-core-protos/src/constants.rs +7 -0
  130. package/sdk-core/{src/test_help → sdk-core-protos/src}/history_builder.rs +134 -49
  131. package/sdk-core/sdk-core-protos/src/history_info.rs +216 -0
  132. package/sdk-core/sdk-core-protos/src/lib.rs +594 -168
  133. package/sdk-core/sdk-core-protos/src/task_token.rs +38 -0
  134. package/sdk-core/sdk-core-protos/src/utilities.rs +14 -0
  135. package/sdk-core/test-utils/Cargo.toml +32 -0
  136. package/sdk-core/{src/test_help → test-utils/src}/canned_histories.rs +59 -78
  137. package/sdk-core/test-utils/src/histfetch.rs +28 -0
  138. package/sdk-core/{test_utils → test-utils}/src/lib.rs +131 -68
  139. package/sdk-core/tests/integ_tests/client_tests.rs +1 -1
  140. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +11 -7
  141. package/sdk-core/tests/integ_tests/polling_tests.rs +12 -11
  142. package/sdk-core/tests/integ_tests/queries_tests.rs +82 -78
  143. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +91 -71
  144. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +3 -4
  145. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +2 -4
  146. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +4 -6
  147. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +4 -6
  148. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -4
  149. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +496 -0
  150. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +5 -8
  151. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +125 -0
  152. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +7 -13
  153. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +33 -5
  154. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +12 -16
  155. package/sdk-core/tests/integ_tests/workflow_tests.rs +85 -82
  156. package/sdk-core/tests/load_tests.rs +6 -6
  157. package/sdk-core/tests/main.rs +2 -2
  158. package/src/conversions.rs +24 -21
  159. package/src/errors.rs +8 -0
  160. package/src/lib.rs +323 -211
  161. package/sdk-core/protos/local/activity_result.proto +0 -46
  162. package/sdk-core/protos/local/activity_task.proto +0 -66
  163. package/sdk-core/src/core_tests/retry.rs +0 -147
  164. package/sdk-core/src/lib.rs +0 -403
  165. package/sdk-core/src/machines/local_activity_state_machine.rs +0 -117
  166. package/sdk-core/src/pending_activations.rs +0 -249
  167. package/sdk-core/src/protosext/mod.rs +0 -160
  168. package/sdk-core/src/prototype_rust_sdk.rs +0 -412
  169. package/sdk-core/src/task_token.rs +0 -20
  170. package/sdk-core/src/test_help/history_info.rs +0 -158
@@ -1,7 +1,4 @@
1
- use crate::{
2
- errors::ActivityHeartbeatError, pollers::ServerGatewayApis, task_token::TaskToken,
3
- worker::activities::PendingActivityCancel,
4
- };
1
+ use crate::{pollers::ServerGatewayApis, worker::activities::PendingActivityCancel, TaskToken};
5
2
  use futures::StreamExt;
6
3
  use std::{
7
4
  collections::{hash_map::Entry, HashMap},
@@ -15,7 +12,7 @@ use temporal_sdk_core_protos::{
15
12
  use tokio::{
16
13
  sync::{
17
14
  mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
18
- Mutex,
15
+ Mutex, Notify,
19
16
  },
20
17
  task::JoinHandle,
21
18
  };
@@ -27,7 +24,7 @@ pub(crate) struct ActivityHeartbeatManager {
27
24
  /// Cancellations that have been received when heartbeating are queued here and can be consumed
28
25
  /// by [fetch_cancellations]
29
26
  incoming_cancels: Mutex<UnboundedReceiver<PendingActivityCancel>>,
30
- cancellation_token: CancellationToken,
27
+ shutdown_token: CancellationToken,
31
28
  /// Used during `shutdown` to await until all inflight requests are sent.
32
29
  join_handle: Mutex<Option<JoinHandle<()>>>,
33
30
  heartbeat_tx: UnboundedSender<HeartbeatAction>,
@@ -36,7 +33,10 @@ pub(crate) struct ActivityHeartbeatManager {
36
33
  #[derive(Debug)]
37
34
  enum HeartbeatAction {
38
35
  SendHeartbeat(ValidActivityHeartbeat),
39
- Evict(TaskToken),
36
+ Evict {
37
+ token: TaskToken,
38
+ on_complete: Arc<Notify>,
39
+ },
40
40
  CompleteReport(TaskToken),
41
41
  CompleteThrottle(TaskToken),
42
42
  }
@@ -53,12 +53,31 @@ enum HeartbeatExecutorAction {
53
53
  /// Heartbeats are throttled for this task token, sleep until duration or wait to be cancelled
54
54
  Sleep(TaskToken, Duration, CancellationToken),
55
55
  /// Report heartbeat to the server
56
- Report(TaskToken, Vec<common::Payload>),
56
+ Report {
57
+ task_token: TaskToken,
58
+ details: Vec<common::Payload>,
59
+ on_reported: Option<Arc<Notify>>,
60
+ },
61
+ }
62
+
63
+ /// Errors thrown when heartbeating
64
+ #[derive(thiserror::Error, Debug)]
65
+ pub enum ActivityHeartbeatError {
66
+ /// Heartbeat referenced an activity that we don't think exists. It may have completed already.
67
+ #[error("Heartbeat has been sent for activity that either completed or never started on this worker.")]
68
+ UnknownActivity,
69
+ /// There was a set heartbeat timeout, but it was not parseable. A valid timeout is requried
70
+ /// to heartbeat.
71
+ #[error("Unable to parse activity heartbeat timeout.")]
72
+ InvalidHeartbeatTimeout,
73
+ /// Core is shutting down and thus new heartbeats are not accepted
74
+ #[error("New heartbeat requests are not accepted while shutting down")]
75
+ ShuttingDown,
57
76
  }
58
77
 
59
- /// Handle that is used by the core for all interactions with the manager, allows sending new
60
- /// heartbeats or requesting and awaiting for the shutdown. When shutdown is requested, signal gets
61
- /// sent to all processors, which allows them to complete gracefully.
78
+ /// Manages activity heartbeating for a worker. Allows sending new heartbeats or requesting and
79
+ /// awaiting for the shutdown. When shutdown is requested, signal gets sent to all processors, which
80
+ /// allows them to complete gracefully.
62
81
  impl ActivityHeartbeatManager {
63
82
  /// Records a new heartbeat, the first call will result in an immediate call to the server,
64
83
  /// while rapid successive calls would accumulate for up to `delay` and then latest heartbeat
@@ -72,7 +91,7 @@ impl ActivityHeartbeatManager {
72
91
  hb: ActivityHeartbeat,
73
92
  throttle_interval: Duration,
74
93
  ) -> Result<(), ActivityHeartbeatError> {
75
- if self.cancellation_token.is_cancelled() {
94
+ if self.shutdown_token.is_cancelled() {
76
95
  return Err(ActivityHeartbeatError::ShuttingDown);
77
96
  }
78
97
  self.heartbeat_tx
@@ -87,9 +106,15 @@ impl ActivityHeartbeatManager {
87
106
  }
88
107
 
89
108
  /// Tell the heartbeat manager we are done forever with a certain task, so it may be forgotten.
109
+ /// This will also force-flush the most recently provided details.
90
110
  /// Record *should* not be called with the same TaskToken after calling this.
91
- pub(super) fn evict(&self, task_token: TaskToken) {
92
- let _ = self.heartbeat_tx.send(HeartbeatAction::Evict(task_token));
111
+ pub(super) async fn evict(&self, task_token: TaskToken) {
112
+ let completed = Arc::new(Notify::new());
113
+ let _ = self.heartbeat_tx.send(HeartbeatAction::Evict {
114
+ token: task_token,
115
+ on_complete: completed.clone(),
116
+ });
117
+ completed.notified().await;
93
118
  }
94
119
 
95
120
  /// Returns a future that resolves any time there is a new activity cancel that must be
@@ -102,7 +127,7 @@ impl ActivityHeartbeatManager {
102
127
  /// Initiates shutdown procedure by stopping lifecycle loop and awaiting for all in-flight
103
128
  /// heartbeat requests to be flushed to the server.
104
129
  pub(super) async fn shutdown(&self) {
105
- let _ = self.cancellation_token.cancel();
130
+ let _ = self.shutdown_token.cancel();
106
131
  let mut handle = self.join_handle.lock().await;
107
132
  if let Some(h) = handle.take() {
108
133
  h.await.expect("shutdown should exit cleanly");
@@ -171,7 +196,11 @@ impl HeartbeatStreamState {
171
196
  throttled_cancellation_token: None,
172
197
  };
173
198
  e.insert(state);
174
- Some(HeartbeatExecutorAction::Report(hb.task_token, hb.details))
199
+ Some(HeartbeatExecutorAction::Report {
200
+ task_token: hb.task_token,
201
+ details: hb.details,
202
+ on_reported: None,
203
+ })
175
204
  }
176
205
  Entry::Occupied(mut o) => {
177
206
  let state = o.get_mut();
@@ -207,7 +236,11 @@ impl HeartbeatStreamState {
207
236
  // Reset the cancellation token and schedule another report
208
237
  state.throttled_cancellation_token = None;
209
238
  state.last_send_requested = Instant::now();
210
- Some(HeartbeatExecutorAction::Report(tt, details))
239
+ Some(HeartbeatExecutorAction::Report {
240
+ task_token: tt,
241
+ details,
242
+ on_reported: None,
243
+ })
211
244
  } else {
212
245
  // Nothing to report, forget this task token
213
246
  e.remove();
@@ -218,15 +251,29 @@ impl HeartbeatStreamState {
218
251
  }
219
252
  }
220
253
 
221
- /// Activity should not be tracked anymore, cancel throttle timer if running
222
- fn evict(&mut self, tt: TaskToken) -> Option<HeartbeatExecutorAction> {
223
- if let Some(token) = self
224
- .tt_to_state
225
- .remove(&tt)
226
- .and_then(|st| st.throttled_cancellation_token)
227
- {
228
- let _ = token.cancel();
229
- };
254
+ /// Activity should not be tracked anymore, cancel throttle timer if running.
255
+ ///
256
+ /// Will return a report action if there are recorded details present, to ensure we flush the
257
+ /// latest details before we cease tracking this activity.
258
+ fn evict(
259
+ &mut self,
260
+ tt: TaskToken,
261
+ on_complete: Arc<Notify>,
262
+ ) -> Option<HeartbeatExecutorAction> {
263
+ if let Some(state) = self.tt_to_state.remove(&tt) {
264
+ if let Some(cancel_tok) = state.throttled_cancellation_token {
265
+ let _ = cancel_tok.cancel();
266
+ }
267
+ if let Some(last_deets) = state.last_recorded_details {
268
+ return Some(HeartbeatExecutorAction::Report {
269
+ task_token: tt,
270
+ details: last_deets,
271
+ on_reported: Some(on_complete),
272
+ });
273
+ }
274
+ }
275
+ // Since there's nothing to flush immediately report back that eviction is finished
276
+ on_complete.notify_one();
230
277
  None
231
278
  }
232
279
  }
@@ -235,14 +282,14 @@ impl ActivityHeartbeatManager {
235
282
  /// Creates a new instance of an activity heartbeat manager and returns a handle to the user,
236
283
  /// which allows to send new heartbeats and initiate the shutdown.
237
284
  pub fn new(sg: Arc<impl ServerGatewayApis + Send + Sync + 'static + ?Sized>) -> Self {
238
- let (heartbeat_stream_state, heartbeat_tx_source, cancellation_token) =
285
+ let (heartbeat_stream_state, heartbeat_tx_source, shutdown_token) =
239
286
  HeartbeatStreamState::new();
240
287
  let (cancels_tx, cancels_rx) = unbounded_channel();
241
288
  let heartbeat_tx = heartbeat_tx_source.clone();
242
289
 
243
290
  let join_handle = tokio::spawn(
244
291
  // The stream of incoming heartbeats uses unfold to carry state across each item in the
245
- // stream The closure checks if, for any given activity, we should heartbeat or not
292
+ // stream. The closure checks if, for any given activity, we should heartbeat or not
246
293
  // depending on its delay and when we last issued a heartbeat for it.
247
294
  futures::stream::unfold(heartbeat_stream_state, move |mut hb_states| {
248
295
  async move {
@@ -263,12 +310,13 @@ impl ActivityHeartbeatManager {
263
310
  HeartbeatAction::SendHeartbeat(hb) => hb_states.record(hb),
264
311
  HeartbeatAction::CompleteReport(tt) => hb_states.handle_report_completed(tt),
265
312
  HeartbeatAction::CompleteThrottle(tt) => hb_states.handle_throttle_completed(tt),
266
- HeartbeatAction::Evict(tt) => hb_states.evict(tt),
313
+ HeartbeatAction::Evict{ token, on_complete } => hb_states.evict(token, on_complete),
267
314
  },
268
315
  hb_states,
269
316
  ))
270
317
  }
271
318
  })
319
+ // Filters out `None`s
272
320
  .filter_map(|opt| async { opt })
273
321
  .for_each_concurrent(None, move |action| {
274
322
  let heartbeat_tx = heartbeat_tx_source.clone();
@@ -284,7 +332,7 @@ impl ActivityHeartbeatManager {
284
332
  },
285
333
  };
286
334
  }
287
- HeartbeatExecutorAction::Report(tt, details) => {
335
+ HeartbeatExecutorAction::Report { task_token: tt, details, on_reported } => {
288
336
  match sg
289
337
  .record_activity_heartbeat(tt.clone(), details.into_payloads())
290
338
  .await
@@ -301,9 +349,9 @@ impl ActivityHeartbeatManager {
301
349
  );
302
350
  }
303
351
  }
304
- // Send cancels for any activity that learns its workflow already finished
305
- // (which is one thing not found implies - other reasons would seem equally
306
- // valid).
352
+ // Send cancels for any activity that learns its workflow already
353
+ // finished (which is one thing not found implies - other reasons
354
+ // would seem equally valid).
307
355
  Err(s) if s.code() == tonic::Code::NotFound => {
308
356
  cancels_tx
309
357
  .send(PendingActivityCancel::new(
@@ -316,6 +364,9 @@ impl ActivityHeartbeatManager {
316
364
  warn!("Error when recording heartbeat: {:?}", e);
317
365
  }
318
366
  };
367
+ if let Some(onrep) = on_reported {
368
+ onrep.notify_one();
369
+ }
319
370
  let _ = heartbeat_tx.send(HeartbeatAction::CompleteReport(tt));
320
371
  }
321
372
  }
@@ -326,7 +377,7 @@ impl ActivityHeartbeatManager {
326
377
  Self {
327
378
  incoming_cancels: Mutex::new(cancels_rx),
328
379
  join_handle: Mutex::new(Some(join_handle)),
329
- cancellation_token,
380
+ shutdown_token,
330
381
  heartbeat_tx,
331
382
  }
332
383
  }
@@ -335,8 +386,10 @@ impl ActivityHeartbeatManager {
335
386
  #[cfg(test)]
336
387
  mod test {
337
388
  use super::*;
338
- use crate::{pollers::MockServerGatewayApis, test_help::TEST_Q};
389
+ use crate::test_help::TEST_Q;
339
390
  use std::time::Duration;
391
+
392
+ use temporal_client::mocks::mock_gateway;
340
393
  use temporal_sdk_core_protos::{
341
394
  coresdk::common::Payload,
342
395
  temporal::api::workflowservice::v1::RecordActivityTaskHeartbeatResponse,
@@ -347,7 +400,7 @@ mod test {
347
400
  /// every 1/2 of the heartbeat timeout.
348
401
  #[tokio::test]
349
402
  async fn process_heartbeats_and_shutdown() {
350
- let mut mock_gateway = MockServerGatewayApis::new();
403
+ let mut mock_gateway = mock_gateway();
351
404
  mock_gateway
352
405
  .expect_record_activity_heartbeat()
353
406
  .returning(|_, _| Ok(RecordActivityTaskHeartbeatResponse::default()))
@@ -368,7 +421,7 @@ mod test {
368
421
 
369
422
  #[tokio::test]
370
423
  async fn send_heartbeats_less_frequently_than_throttle_interval() {
371
- let mut mock_gateway = MockServerGatewayApis::new();
424
+ let mut mock_gateway = mock_gateway();
372
425
  mock_gateway
373
426
  .expect_record_activity_heartbeat()
374
427
  .returning(|_, _| Ok(RecordActivityTaskHeartbeatResponse::default()))
@@ -388,7 +441,7 @@ mod test {
388
441
  /// interactions with the server - one immediately and one after 500ms after the throttle_interval.
389
442
  #[tokio::test]
390
443
  async fn process_tight_loop_and_shutdown() {
391
- let mut mock_gateway = MockServerGatewayApis::new();
444
+ let mut mock_gateway = mock_gateway();
392
445
  mock_gateway
393
446
  .expect_record_activity_heartbeat()
394
447
  .returning(|_, _| Ok(RecordActivityTaskHeartbeatResponse::default()))
@@ -407,7 +460,7 @@ mod test {
407
460
  /// This test reports one heartbeat and waits for the throttle_interval to elapse before sending another
408
461
  #[tokio::test]
409
462
  async fn report_heartbeat_after_timeout() {
410
- let mut mock_gateway = MockServerGatewayApis::new();
463
+ let mut mock_gateway = mock_gateway();
411
464
  mock_gateway
412
465
  .expect_record_activity_heartbeat()
413
466
  .returning(|_, _| Ok(RecordActivityTaskHeartbeatResponse::default()))
@@ -424,7 +477,7 @@ mod test {
424
477
 
425
478
  #[tokio::test]
426
479
  async fn evict_works() {
427
- let mut mock_gateway = MockServerGatewayApis::new();
480
+ let mut mock_gateway = mock_gateway();
428
481
  mock_gateway
429
482
  .expect_record_activity_heartbeat()
430
483
  .returning(|_, _| Ok(RecordActivityTaskHeartbeatResponse::default()))
@@ -434,7 +487,7 @@ mod test {
434
487
  record_heartbeat(&hm, fake_task_token.clone(), 0, Duration::from_millis(100));
435
488
  // Let it propagate
436
489
  sleep(Duration::from_millis(10)).await;
437
- hm.evict(fake_task_token.clone().into());
490
+ hm.evict(fake_task_token.clone().into()).await;
438
491
  record_heartbeat(&hm, fake_task_token, 0, Duration::from_millis(100));
439
492
  // Let it propagate
440
493
  sleep(Duration::from_millis(10)).await;
@@ -445,7 +498,7 @@ mod test {
445
498
  /// Recording new heartbeats after shutdown is not allowed, and will result in error.
446
499
  #[tokio::test]
447
500
  async fn record_after_shutdown() {
448
- let mut mock_gateway = MockServerGatewayApis::new();
501
+ let mut mock_gateway = mock_gateway();
449
502
  mock_gateway
450
503
  .expect_record_activity_heartbeat()
451
504
  .returning(|_, _| Ok(RecordActivityTaskHeartbeatResponse::default()))