@temporalio/core-bridge 0.23.0 → 1.0.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 (135) hide show
  1. package/Cargo.lock +118 -15
  2. package/Cargo.toml +2 -1
  3. package/LICENSE.md +1 -1
  4. package/README.md +1 -1
  5. package/index.d.ts +47 -18
  6. package/package.json +7 -7
  7. package/releases/aarch64-apple-darwin/index.node +0 -0
  8. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  9. package/releases/x86_64-apple-darwin/index.node +0 -0
  10. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  11. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  12. package/sdk-core/.buildkite/docker/docker-compose.yaml +4 -2
  13. package/sdk-core/ARCHITECTURE.md +9 -7
  14. package/sdk-core/README.md +5 -1
  15. package/sdk-core/arch_docs/diagrams/workflow_internals.svg +1 -0
  16. package/sdk-core/bridge-ffi/src/wrappers.rs +0 -3
  17. package/sdk-core/client/src/lib.rs +26 -8
  18. package/sdk-core/client/src/raw.rs +166 -54
  19. package/sdk-core/client/src/retry.rs +9 -4
  20. package/sdk-core/client/src/workflow_handle/mod.rs +4 -2
  21. package/sdk-core/core/Cargo.toml +2 -0
  22. package/sdk-core/core/src/abstractions.rs +137 -16
  23. package/sdk-core/core/src/core_tests/activity_tasks.rs +258 -63
  24. package/sdk-core/core/src/core_tests/child_workflows.rs +1 -2
  25. package/sdk-core/core/src/core_tests/determinism.rs +2 -2
  26. package/sdk-core/core/src/core_tests/local_activities.rs +8 -7
  27. package/sdk-core/core/src/core_tests/queries.rs +146 -60
  28. package/sdk-core/core/src/core_tests/replay_flag.rs +1 -1
  29. package/sdk-core/core/src/core_tests/workers.rs +39 -23
  30. package/sdk-core/core/src/core_tests/workflow_cancels.rs +1 -1
  31. package/sdk-core/core/src/core_tests/workflow_tasks.rs +387 -280
  32. package/sdk-core/core/src/lib.rs +6 -4
  33. package/sdk-core/core/src/pollers/poll_buffer.rs +16 -10
  34. package/sdk-core/core/src/protosext/mod.rs +6 -6
  35. package/sdk-core/core/src/retry_logic.rs +1 -1
  36. package/sdk-core/core/src/telemetry/metrics.rs +21 -7
  37. package/sdk-core/core/src/telemetry/mod.rs +18 -4
  38. package/sdk-core/core/src/test_help/mod.rs +341 -109
  39. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +18 -9
  40. package/sdk-core/core/src/worker/activities/local_activities.rs +19 -16
  41. package/sdk-core/core/src/worker/activities.rs +156 -29
  42. package/sdk-core/core/src/worker/client.rs +1 -0
  43. package/sdk-core/core/src/worker/mod.rs +132 -659
  44. package/sdk-core/core/src/{workflow → worker/workflow}/bridge.rs +1 -1
  45. package/sdk-core/core/src/{workflow → worker/workflow}/driven_workflow.rs +1 -1
  46. package/sdk-core/core/src/{workflow → worker/workflow}/history_update.rs +16 -2
  47. package/sdk-core/core/src/{workflow → worker/workflow}/machines/activity_state_machine.rs +39 -4
  48. package/sdk-core/core/src/{workflow → worker/workflow}/machines/cancel_external_state_machine.rs +5 -2
  49. package/sdk-core/core/src/{workflow → worker/workflow}/machines/cancel_workflow_state_machine.rs +1 -1
  50. package/sdk-core/core/src/{workflow → worker/workflow}/machines/child_workflow_state_machine.rs +2 -4
  51. package/sdk-core/core/src/{workflow → worker/workflow}/machines/complete_workflow_state_machine.rs +0 -0
  52. package/sdk-core/core/src/{workflow → worker/workflow}/machines/continue_as_new_workflow_state_machine.rs +1 -1
  53. package/sdk-core/core/src/{workflow → worker/workflow}/machines/fail_workflow_state_machine.rs +0 -0
  54. package/sdk-core/core/src/{workflow → worker/workflow}/machines/local_activity_state_machine.rs +2 -5
  55. package/sdk-core/core/src/{workflow → worker/workflow}/machines/mod.rs +1 -1
  56. package/sdk-core/core/src/{workflow → worker/workflow}/machines/mutable_side_effect_state_machine.rs +0 -0
  57. package/sdk-core/core/src/{workflow → worker/workflow}/machines/patch_state_machine.rs +1 -1
  58. package/sdk-core/core/src/{workflow → worker/workflow}/machines/side_effect_state_machine.rs +0 -0
  59. package/sdk-core/core/src/{workflow → worker/workflow}/machines/signal_external_state_machine.rs +4 -2
  60. package/sdk-core/core/src/{workflow → worker/workflow}/machines/timer_state_machine.rs +1 -2
  61. package/sdk-core/core/src/{workflow → worker/workflow}/machines/transition_coverage.rs +1 -1
  62. package/sdk-core/core/src/{workflow → worker/workflow}/machines/upsert_search_attributes_state_machine.rs +5 -7
  63. package/sdk-core/core/src/{workflow → worker/workflow}/machines/workflow_machines/local_acts.rs +2 -2
  64. package/sdk-core/core/src/{workflow → worker/workflow}/machines/workflow_machines.rs +40 -16
  65. package/sdk-core/core/src/{workflow → worker/workflow}/machines/workflow_task_state_machine.rs +0 -0
  66. package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +198 -0
  67. package/sdk-core/core/src/worker/workflow/managed_run.rs +627 -0
  68. package/sdk-core/core/src/worker/workflow/mod.rs +1115 -0
  69. package/sdk-core/core/src/worker/workflow/run_cache.rs +143 -0
  70. package/sdk-core/core/src/worker/workflow/wft_poller.rs +88 -0
  71. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +936 -0
  72. package/sdk-core/core-api/src/errors.rs +3 -10
  73. package/sdk-core/core-api/src/lib.rs +2 -1
  74. package/sdk-core/core-api/src/worker.rs +26 -2
  75. package/sdk-core/etc/dynamic-config.yaml +2 -0
  76. package/sdk-core/integ-with-otel.sh +1 -1
  77. package/sdk-core/protos/api_upstream/Makefile +4 -4
  78. package/sdk-core/protos/api_upstream/api-linter.yaml +2 -0
  79. package/sdk-core/protos/api_upstream/buf.yaml +8 -9
  80. package/sdk-core/protos/api_upstream/temporal/api/cluster/v1/message.proto +83 -0
  81. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +7 -1
  82. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/cluster.proto +40 -0
  83. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +3 -0
  84. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +3 -1
  85. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +60 -0
  86. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +3 -0
  87. package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +32 -4
  88. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +69 -19
  89. package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +13 -0
  90. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +163 -0
  91. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +97 -0
  92. package/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +300 -0
  93. package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +25 -0
  94. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +180 -3
  95. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +53 -3
  96. package/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +2 -2
  97. package/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +6 -5
  98. package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +0 -1
  99. package/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +2 -1
  100. package/sdk-core/protos/local/temporal/sdk/core/common/common.proto +0 -64
  101. package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +2 -1
  102. package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +11 -8
  103. package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +30 -25
  104. package/sdk-core/sdk/src/activity_context.rs +12 -5
  105. package/sdk-core/sdk/src/app_data.rs +37 -0
  106. package/sdk-core/sdk/src/lib.rs +76 -43
  107. package/sdk-core/sdk/src/workflow_context/options.rs +8 -6
  108. package/sdk-core/sdk/src/workflow_context.rs +14 -19
  109. package/sdk-core/sdk/src/workflow_future.rs +11 -6
  110. package/sdk-core/sdk-core-protos/src/history_builder.rs +19 -5
  111. package/sdk-core/sdk-core-protos/src/history_info.rs +11 -6
  112. package/sdk-core/sdk-core-protos/src/lib.rs +74 -176
  113. package/sdk-core/test-utils/src/lib.rs +85 -72
  114. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +11 -9
  115. package/sdk-core/tests/integ_tests/polling_tests.rs +12 -0
  116. package/sdk-core/tests/integ_tests/queries_tests.rs +39 -22
  117. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +49 -4
  118. package/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +61 -0
  119. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -1
  120. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +74 -13
  121. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +19 -0
  122. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -1
  123. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +6 -3
  124. package/sdk-core/tests/integ_tests/workflow_tests.rs +10 -23
  125. package/sdk-core/tests/load_tests.rs +8 -3
  126. package/sdk-core/tests/main.rs +2 -1
  127. package/src/conversions.rs +47 -39
  128. package/src/errors.rs +10 -21
  129. package/src/lib.rs +342 -325
  130. package/sdk-core/core/src/pending_activations.rs +0 -173
  131. package/sdk-core/core/src/worker/wft_delivery.rs +0 -81
  132. package/sdk-core/core/src/workflow/mod.rs +0 -478
  133. package/sdk-core/core/src/workflow/workflow_tasks/cache_manager.rs +0 -194
  134. package/sdk-core/core/src/workflow/workflow_tasks/concurrency_manager.rs +0 -418
  135. package/sdk-core/core/src/workflow/workflow_tasks/mod.rs +0 -989
@@ -1,8 +1,9 @@
1
1
  use crate::{
2
2
  test_help::{
3
- canned_histories, hist_to_poll_resp, mock_worker, MocksHolder, ResponseType, TEST_Q,
3
+ build_mock_pollers, canned_histories, hist_to_poll_resp, mock_worker, single_hist_mock_sg,
4
+ MockPollCfg, ResponseType, TEST_Q,
4
5
  },
5
- worker::client::mocks::mock_workflow_client,
6
+ worker::{client::mocks::mock_workflow_client, LEGACY_QUERY_ID},
6
7
  };
7
8
  use std::{
8
9
  collections::{HashMap, VecDeque},
@@ -26,8 +27,7 @@ use temporal_sdk_core_protos::{
26
27
  history::v1::History,
27
28
  query::v1::WorkflowQuery,
28
29
  workflowservice::v1::{
29
- GetWorkflowExecutionHistoryResponse, RespondQueryTaskCompletedResponse,
30
- RespondWorkflowTaskCompletedResponse,
30
+ GetWorkflowExecutionHistoryResponse, RespondWorkflowTaskCompletedResponse,
31
31
  },
32
32
  },
33
33
  };
@@ -43,7 +43,7 @@ async fn legacy_query(#[case] include_history: bool) {
43
43
  let t = canned_histories::single_timer("1");
44
44
  let mut header = HashMap::new();
45
45
  header.insert("head".to_string(), Payload::from(b"er"));
46
- let tasks = VecDeque::from(vec![
46
+ let tasks = [
47
47
  hist_to_poll_resp(&t, wfid.to_owned(), 1.into(), TEST_Q.to_string()),
48
48
  {
49
49
  let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), 1.into(), TEST_Q.to_string());
@@ -58,17 +58,10 @@ async fn legacy_query(#[case] include_history: bool) {
58
58
  pr
59
59
  },
60
60
  hist_to_poll_resp(&t, wfid.to_owned(), 2.into(), TEST_Q.to_string()),
61
- ]);
62
- let mut mock_client = mock_workflow_client();
63
- mock_client
64
- .expect_complete_workflow_task()
65
- .returning(|_| Ok(RespondWorkflowTaskCompletedResponse::default()));
66
- mock_client
67
- .expect_respond_legacy_query()
68
- .times(1)
69
- .returning(move |_, _| Ok(RespondQueryTaskCompletedResponse::default()));
70
-
71
- let mut mock = MocksHolder::from_client_with_responses(mock_client, tasks, vec![]);
61
+ ];
62
+ let mut mock = MockPollCfg::from_resp_batches(wfid, t, tasks, mock_workflow_client());
63
+ mock.num_expected_legacy_query_resps = 1;
64
+ let mut mock = build_mock_pollers(mock);
72
65
  if !include_history {
73
66
  mock.worker_cfg(|wc| wc.max_cached_workflows = 10);
74
67
  }
@@ -186,12 +179,8 @@ async fn new_queries(#[case] num_queries: usize) {
186
179
  },
187
180
  ]);
188
181
  let mut mock_client = mock_workflow_client();
189
- mock_client
190
- .expect_complete_workflow_task()
191
- .returning(|_| Ok(RespondWorkflowTaskCompletedResponse::default()));
192
182
  mock_client.expect_respond_legacy_query().times(0);
193
-
194
- let mut mock = MocksHolder::from_client_with_responses(mock_client, tasks, vec![]);
183
+ let mut mock = single_hist_mock_sg(wfid, t, tasks, mock_client, true);
195
184
  mock.worker_cfg(|wc| wc.max_cached_workflows = 10);
196
185
  let core = mock_worker(mock);
197
186
 
@@ -260,18 +249,10 @@ async fn legacy_query_failure_on_wft_failure() {
260
249
  pr.history = Some(History { events: vec![] });
261
250
  pr
262
251
  },
263
- hist_to_poll_resp(&t, wfid.to_owned(), 2.into(), TEST_Q.to_string()),
264
252
  ]);
265
- let mut mock_client = mock_workflow_client();
266
- mock_client
267
- .expect_complete_workflow_task()
268
- .returning(|_| Ok(RespondWorkflowTaskCompletedResponse::default()));
269
- mock_client
270
- .expect_respond_legacy_query()
271
- .times(1)
272
- .returning(move |_, _| Ok(RespondQueryTaskCompletedResponse::default()));
273
-
274
- let mut mock = MocksHolder::from_client_with_responses(mock_client, tasks, vec![]);
253
+ let mut mock = MockPollCfg::from_resp_batches(wfid, t, tasks, mock_workflow_client());
254
+ mock.num_expected_legacy_query_resps = 1;
255
+ let mut mock = build_mock_pollers(mock);
275
256
  mock.worker_cfg(|wc| wc.max_cached_workflows = 10);
276
257
  let core = mock_worker(mock);
277
258
 
@@ -305,6 +286,64 @@ async fn legacy_query_failure_on_wft_failure() {
305
286
  core.shutdown().await;
306
287
  }
307
288
 
289
+ #[rstest::rstest]
290
+ #[tokio::test]
291
+ async fn query_failure_because_nondeterminism(#[values(true, false)] legacy: bool) {
292
+ let wfid = "fake_wf_id";
293
+ let t = canned_histories::single_timer("1");
294
+ let tasks = [{
295
+ let mut pr = hist_to_poll_resp(
296
+ &t,
297
+ wfid.to_owned(),
298
+ ResponseType::AllHistory,
299
+ TEST_Q.to_string(),
300
+ );
301
+ if legacy {
302
+ pr.query = Some(WorkflowQuery {
303
+ query_type: "query-type".to_string(),
304
+ query_args: Some(b"hi".into()),
305
+ header: None,
306
+ });
307
+ } else {
308
+ pr.queries = HashMap::new();
309
+ pr.queries.insert(
310
+ "q1".to_string(),
311
+ WorkflowQuery {
312
+ query_type: "query-type".to_string(),
313
+ query_args: Some(b"hi".into()),
314
+ header: None,
315
+ },
316
+ );
317
+ }
318
+ pr
319
+ }];
320
+ let mut mock = MockPollCfg::from_resp_batches(wfid, t, tasks, mock_workflow_client());
321
+ if legacy {
322
+ mock.num_expected_legacy_query_resps = 1;
323
+ } else {
324
+ mock.num_expected_fails = 1;
325
+ }
326
+ let mut mock = build_mock_pollers(mock);
327
+ mock.worker_cfg(|wc| wc.max_cached_workflows = 10);
328
+ let core = mock_worker(mock);
329
+
330
+ let task = core.poll_workflow_activation().await.unwrap();
331
+ // Nondeterminism, should result in WFT/query being failed
332
+ core.complete_workflow_activation(WorkflowActivationCompletion::empty(task.run_id))
333
+ .await
334
+ .unwrap();
335
+ let task = core.poll_workflow_activation().await.unwrap();
336
+ assert_matches!(
337
+ task.jobs[0].variant,
338
+ Some(workflow_activation_job::Variant::RemoveFromCache(_))
339
+ );
340
+ core.complete_workflow_activation(WorkflowActivationCompletion::empty(task.run_id))
341
+ .await
342
+ .unwrap();
343
+
344
+ core.shutdown().await;
345
+ }
346
+
308
347
  #[rstest::rstest]
309
348
  #[tokio::test]
310
349
  async fn legacy_query_after_complete(#[values(false, true)] full_history: bool) {
@@ -328,28 +367,29 @@ async fn legacy_query_after_complete(#[values(false, true)] full_history: bool)
328
367
  query_args: Some(b"hi".into()),
329
368
  header: None,
330
369
  });
331
- pr
370
+ pr.resp
332
371
  };
333
- let tasks = VecDeque::from(vec![
334
- hist_to_poll_resp(
335
- &t,
336
- wfid.to_owned(),
337
- ResponseType::AllHistory,
338
- TEST_Q.to_string(),
339
- ),
340
- query_with_hist_task.clone(),
341
- query_with_hist_task,
342
- ]);
343
- let mut mock_client = mock_workflow_client();
344
- mock_client
345
- .expect_complete_workflow_task()
346
- .returning(|_| Ok(RespondWorkflowTaskCompletedResponse::default()));
347
- mock_client
348
- .expect_respond_legacy_query()
349
- .times(2)
350
- .returning(move |_, _| Ok(RespondQueryTaskCompletedResponse::default()));
372
+ // Server would never send us a workflow task *without* a query that goes all the way to
373
+ // execution completed. So, don't do that. It messes with the mock unlocking the next
374
+ // task since we (appropriately) won't respond to server in that situation.
375
+ let mut tasks = if full_history {
376
+ vec![]
377
+ } else {
378
+ vec![
379
+ hist_to_poll_resp(
380
+ &t,
381
+ wfid.to_owned(),
382
+ ResponseType::AllHistory,
383
+ TEST_Q.to_string(),
384
+ )
385
+ .resp,
386
+ ]
387
+ };
388
+ tasks.extend([query_with_hist_task.clone(), query_with_hist_task]);
351
389
 
352
- let mut mock = MocksHolder::from_client_with_responses(mock_client, tasks, vec![]);
390
+ let mut mock = MockPollCfg::from_resp_batches(wfid, t, tasks, mock_workflow_client());
391
+ mock.num_expected_legacy_query_resps = 2;
392
+ let mut mock = build_mock_pollers(mock);
353
393
  mock.worker_cfg(|wc| wc.max_cached_workflows = 10);
354
394
  let core = mock_worker(mock);
355
395
 
@@ -474,7 +514,7 @@ async fn query_cache_miss_causes_page_fetch_dont_reply_wft_too_early(
474
514
  Ok(RespondWorkflowTaskCompletedResponse::default())
475
515
  });
476
516
 
477
- let mut mock = MocksHolder::from_client_with_responses(mock_client, tasks, vec![]);
517
+ let mut mock = single_hist_mock_sg(wfid, t, tasks, mock_client, true);
478
518
  mock.worker_cfg(|wc| wc.max_cached_workflows = 10);
479
519
  let core = mock_worker(mock);
480
520
  let task = core.poll_workflow_activation().await.unwrap();
@@ -568,7 +608,7 @@ async fn query_replay_with_continue_as_new_doesnt_reply_empty_command() {
568
608
  Ok(RespondWorkflowTaskCompletedResponse::default())
569
609
  });
570
610
 
571
- let mut mock = MocksHolder::from_client_with_responses(mock_client, tasks, vec![]);
611
+ let mut mock = single_hist_mock_sg(wfid, t, tasks, mock_client, true);
572
612
  mock.worker_cfg(|wc| wc.max_cached_workflows = 10);
573
613
  let core = mock_worker(mock);
574
614
 
@@ -634,17 +674,63 @@ async fn query_replay_with_continue_as_new_doesnt_reply_empty_command() {
634
674
  .await
635
675
  .unwrap();
636
676
 
637
- // Need to complete the eviction to finally send commands and finish
677
+ core.shutdown().await;
678
+ }
679
+
680
+ #[tokio::test]
681
+ async fn legacy_query_response_gets_not_found_not_fatal() {
682
+ let wfid = "fake_wf_id";
683
+ let t = canned_histories::single_timer("1");
684
+ let tasks = [{
685
+ let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), 1.into(), TEST_Q.to_string());
686
+ pr.query = Some(WorkflowQuery {
687
+ query_type: "query-type".to_string(),
688
+ query_args: Some(b"hi".into()),
689
+ header: None,
690
+ });
691
+ pr
692
+ }];
693
+ let mut mock = mock_workflow_client();
694
+ mock.expect_respond_legacy_query()
695
+ .times(1)
696
+ .returning(move |_, _| Err(tonic::Status::not_found("Query gone boi")));
697
+ let mock = MockPollCfg::from_resp_batches(wfid, t, tasks, mock);
698
+ let mut mock = build_mock_pollers(mock);
699
+ mock.worker_cfg(|wc| wc.max_cached_workflows = 10);
700
+ let core = mock_worker(mock);
701
+
638
702
  let task = core.poll_workflow_activation().await.unwrap();
703
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
704
+ task.run_id,
705
+ start_timer_cmd(1, Duration::from_secs(1)),
706
+ ))
707
+ .await
708
+ .unwrap();
709
+
710
+ let task = core.poll_workflow_activation().await.unwrap();
711
+ // Poll again, and we end up getting a `query` field query response
639
712
  assert_matches!(
640
713
  task.jobs.as_slice(),
641
714
  [WorkflowActivationJob {
642
- variant: Some(workflow_activation_job::Variant::RemoveFromCache(_))
643
- }]
715
+ variant: Some(workflow_activation_job::Variant::QueryWorkflow(q)),
716
+ }] => q
644
717
  );
645
- core.complete_workflow_activation(WorkflowActivationCompletion::empty(task.run_id))
646
- .await
647
- .unwrap();
718
+ // Fail wft which should result in query being failed
719
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
720
+ task.run_id,
721
+ QueryResult {
722
+ query_id: LEGACY_QUERY_ID.to_string(),
723
+ variant: Some(
724
+ QuerySuccess {
725
+ response: Some("hi".into()),
726
+ }
727
+ .into(),
728
+ ),
729
+ }
730
+ .into(),
731
+ ))
732
+ .await
733
+ .unwrap();
648
734
 
649
735
  core.shutdown().await;
650
736
  }
@@ -1,4 +1,4 @@
1
- use crate::{test_help::canned_histories, workflow::managed_wf::ManagedWFFunc};
1
+ use crate::{test_help::canned_histories, worker::ManagedWFFunc};
2
2
  use rstest::{fixture, rstest};
3
3
  use std::time::Duration;
4
4
  use temporal_sdk::{WfContext, WorkflowFunction};
@@ -1,7 +1,7 @@
1
1
  use crate::{
2
2
  test_help::{
3
3
  build_fake_worker, build_mock_pollers, canned_histories, mock_manual_poller, mock_worker,
4
- MockPollCfg, MockWorker, MocksHolder,
4
+ MockPollCfg, MockWorkerInputs, MocksHolder,
5
5
  },
6
6
  worker::client::mocks::mock_workflow_client,
7
7
  PollActivityError, PollWfError,
@@ -40,16 +40,8 @@ async fn after_shutdown_of_worker_get_shutdown_err() {
40
40
  ))
41
41
  .await
42
42
  .unwrap();
43
- // Since non-sticky, one more activation for eviction
44
- let res = worker.poll_workflow_activation().await.unwrap();
45
- assert_matches!(
46
- res.jobs[0].variant,
47
- Some(workflow_activation_job::Variant::RemoveFromCache(_))
48
- );
49
- worker
50
- .complete_workflow_activation(WorkflowActivationCompletion::empty(run_id.clone()))
51
- .await
52
- .unwrap();
43
+
44
+ // Shutdown proceeds if the only outstanding activations are evictions
53
45
  assert_matches!(
54
46
  worker.poll_workflow_activation().await.unwrap_err(),
55
47
  PollWfError::ShutDown
@@ -83,9 +75,7 @@ async fn shutdown_worker_can_complete_pending_activation() {
83
75
  ))
84
76
  .await
85
77
  .unwrap();
86
- // Since non-sticky, one more activation for eviction
87
- worker.poll_workflow_activation().await.unwrap();
88
- // Now it's shut down
78
+ // Shutdown proceeds if the only outstanding activations are evictions
89
79
  assert_matches!(
90
80
  worker.poll_workflow_activation().await.unwrap_err(),
91
81
  PollWfError::ShutDown
@@ -109,7 +99,7 @@ async fn worker_shutdown_during_poll_doesnt_deadlock() {
109
99
  }
110
100
  .boxed()
111
101
  });
112
- let mw = MockWorker::new(Box::new(mock_poller));
102
+ let mw = MockWorkerInputs::new_from_poller(Box::new(mock_poller));
113
103
  let mut mock_client = mock_workflow_client();
114
104
  mock_client
115
105
  .expect_complete_workflow_task()
@@ -182,16 +172,11 @@ async fn complete_with_task_not_found_during_shutdown() {
182
172
  complete_order.borrow_mut().push(3);
183
173
  };
184
174
  let poll_fut = async {
185
- // This should *not* return shutdown, but instead should do nothing until the complete
186
- // goes through, at which point it will return the eviction.
187
- let res = core.poll_workflow_activation().await.unwrap();
175
+ // This will return shutdown once the completion goes through
188
176
  assert_matches!(
189
- res.jobs[0].variant,
190
- Some(workflow_activation_job::Variant::RemoveFromCache(_))
177
+ core.poll_workflow_activation().await.unwrap_err(),
178
+ PollWfError::ShutDown
191
179
  );
192
- core.complete_workflow_activation(WorkflowActivationCompletion::empty(res.run_id))
193
- .await
194
- .unwrap();
195
180
  complete_order.borrow_mut().push(2);
196
181
  };
197
182
  let complete_fut = async {
@@ -208,3 +193,34 @@ async fn complete_with_task_not_found_during_shutdown() {
208
193
  // workflow task is marked complete as soon as we get not found back from the server.
209
194
  assert_eq!(&complete_order.into_inner(), &[1, 3, 2])
210
195
  }
196
+
197
+ #[tokio::test]
198
+ async fn complete_eviction_after_shutdown_doesnt_panic() {
199
+ let t = canned_histories::single_timer("1");
200
+ let mut mh = build_mock_pollers(MockPollCfg::from_resp_batches(
201
+ "fakeid",
202
+ t,
203
+ [1],
204
+ mock_workflow_client(),
205
+ ));
206
+ mh.make_wft_stream_interminable();
207
+ let core = mock_worker(mh);
208
+
209
+ let res = core.poll_workflow_activation().await.unwrap();
210
+ assert_eq!(res.jobs.len(), 1);
211
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
212
+ res.run_id,
213
+ vec![start_timer_cmd(1, Duration::from_secs(1))],
214
+ ))
215
+ .await
216
+ .unwrap();
217
+ let res = core.poll_workflow_activation().await.unwrap();
218
+ assert_matches!(
219
+ res.jobs[0].variant,
220
+ Some(workflow_activation_job::Variant::RemoveFromCache(_))
221
+ );
222
+ core.shutdown().await;
223
+ core.complete_workflow_activation(WorkflowActivationCompletion::empty(res.run_id))
224
+ .await
225
+ .unwrap();
226
+ }
@@ -2,8 +2,8 @@ use crate::{
2
2
  job_assert,
3
3
  test_help::{
4
4
  build_fake_worker, canned_histories, gen_assert_and_reply, poll_and_reply, ResponseType,
5
+ WorkflowCachingPolicy::NonSticky,
5
6
  },
6
- workflow::WorkflowCachingPolicy::NonSticky,
7
7
  };
8
8
  use rstest::rstest;
9
9
  use std::time::Duration;