@temporalio/core-bridge 1.4.4 → 1.5.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 (123) hide show
  1. package/Cargo.lock +327 -419
  2. package/Cargo.toml +1 -1
  3. package/index.js +25 -2
  4. package/lib/errors.d.ts +22 -0
  5. package/lib/errors.js +65 -0
  6. package/lib/errors.js.map +1 -0
  7. package/lib/index.d.ts +440 -0
  8. package/lib/index.js +8 -0
  9. package/lib/index.js.map +1 -0
  10. package/package.json +11 -5
  11. package/releases/aarch64-apple-darwin/index.node +0 -0
  12. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  13. package/releases/x86_64-apple-darwin/index.node +0 -0
  14. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  15. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  16. package/sdk-core/.buildkite/docker/Dockerfile +1 -1
  17. package/sdk-core/.buildkite/docker/docker-compose.yaml +2 -2
  18. package/sdk-core/bridge-ffi/Cargo.toml +1 -1
  19. package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +0 -25
  20. package/sdk-core/bridge-ffi/src/lib.rs +29 -108
  21. package/sdk-core/bridge-ffi/src/wrappers.rs +35 -25
  22. package/sdk-core/client/Cargo.toml +1 -1
  23. package/sdk-core/client/src/lib.rs +12 -20
  24. package/sdk-core/client/src/raw.rs +9 -8
  25. package/sdk-core/client/src/retry.rs +100 -23
  26. package/sdk-core/core/Cargo.toml +5 -5
  27. package/sdk-core/core/benches/workflow_replay.rs +13 -10
  28. package/sdk-core/core/src/abstractions.rs +22 -22
  29. package/sdk-core/core/src/core_tests/activity_tasks.rs +1 -1
  30. package/sdk-core/core/src/core_tests/local_activities.rs +228 -6
  31. package/sdk-core/core/src/core_tests/queries.rs +247 -89
  32. package/sdk-core/core/src/core_tests/workers.rs +2 -2
  33. package/sdk-core/core/src/core_tests/workflow_cancels.rs +1 -1
  34. package/sdk-core/core/src/core_tests/workflow_tasks.rs +46 -27
  35. package/sdk-core/core/src/lib.rs +139 -32
  36. package/sdk-core/core/src/replay/mod.rs +185 -41
  37. package/sdk-core/core/src/telemetry/log_export.rs +190 -0
  38. package/sdk-core/core/src/telemetry/metrics.rs +184 -139
  39. package/sdk-core/core/src/telemetry/mod.rs +296 -318
  40. package/sdk-core/core/src/telemetry/prometheus_server.rs +4 -3
  41. package/sdk-core/core/src/test_help/mod.rs +9 -7
  42. package/sdk-core/core/src/worker/activities/local_activities.rs +2 -1
  43. package/sdk-core/core/src/worker/activities.rs +40 -23
  44. package/sdk-core/core/src/worker/client/mocks.rs +1 -1
  45. package/sdk-core/core/src/worker/client.rs +30 -4
  46. package/sdk-core/core/src/worker/mod.rs +22 -18
  47. package/sdk-core/core/src/worker/workflow/driven_workflow.rs +10 -19
  48. package/sdk-core/core/src/worker/workflow/history_update.rs +99 -25
  49. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +1 -5
  50. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +1 -5
  51. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +1 -5
  52. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +1 -5
  53. package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +1 -5
  54. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +2 -6
  55. package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +1 -5
  56. package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +18 -21
  57. package/sdk-core/core/src/worker/workflow/machines/mod.rs +12 -38
  58. package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +178 -0
  59. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +1 -5
  60. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +1 -5
  61. package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +1 -5
  62. package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +8 -2
  63. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +1 -5
  64. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +232 -216
  65. package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +1 -6
  66. package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +4 -4
  67. package/sdk-core/core/src/worker/workflow/managed_run.rs +13 -5
  68. package/sdk-core/core/src/worker/workflow/mod.rs +61 -9
  69. package/sdk-core/core/src/worker/workflow/wft_poller.rs +2 -2
  70. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +56 -11
  71. package/sdk-core/core-api/Cargo.toml +4 -3
  72. package/sdk-core/core-api/src/lib.rs +1 -43
  73. package/sdk-core/core-api/src/telemetry.rs +147 -0
  74. package/sdk-core/core-api/src/worker.rs +13 -0
  75. package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +1 -1
  76. package/sdk-core/histories/evict_while_la_running_no_interference-23_history.bin +0 -0
  77. package/sdk-core/histories/evict_while_la_running_no_interference-85_history.bin +0 -0
  78. package/sdk-core/protos/api_upstream/.github/CODEOWNERS +1 -1
  79. package/sdk-core/protos/api_upstream/buf.yaml +0 -3
  80. package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +3 -7
  81. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +8 -0
  82. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +1 -2
  83. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +2 -0
  84. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +3 -0
  85. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +13 -0
  86. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +19 -59
  87. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +0 -19
  88. package/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +108 -29
  89. package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -2
  90. package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +1 -0
  91. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +47 -8
  92. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +15 -1
  93. package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +2 -0
  94. package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +8 -1
  95. package/sdk-core/sdk/src/interceptors.rs +36 -3
  96. package/sdk-core/sdk/src/lib.rs +7 -4
  97. package/sdk-core/sdk/src/workflow_context.rs +13 -2
  98. package/sdk-core/sdk-core-protos/src/history_builder.rs +47 -1
  99. package/sdk-core/sdk-core-protos/src/history_info.rs +22 -22
  100. package/sdk-core/sdk-core-protos/src/lib.rs +49 -27
  101. package/sdk-core/test-utils/Cargo.toml +1 -0
  102. package/sdk-core/test-utils/src/lib.rs +81 -29
  103. package/sdk-core/tests/integ_tests/metrics_tests.rs +37 -0
  104. package/sdk-core/tests/integ_tests/polling_tests.rs +0 -13
  105. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +145 -4
  106. package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +53 -0
  107. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +106 -20
  108. package/sdk-core/tests/integ_tests/workflow_tests.rs +18 -8
  109. package/sdk-core/tests/main.rs +6 -4
  110. package/src/conversions.rs +52 -47
  111. package/src/errors.rs +28 -86
  112. package/src/helpers.rs +3 -4
  113. package/src/lib.rs +2 -2
  114. package/src/runtime.rs +132 -61
  115. package/src/testing.rs +7 -4
  116. package/src/worker.rs +67 -50
  117. package/ts/errors.ts +55 -0
  118. package/{index.d.ts → ts/index.ts} +121 -15
  119. package/sdk-core/core/src/log_export.rs +0 -62
  120. package/sdk-core/core/src/worker/workflow/machines/mutable_side_effect_state_machine.rs +0 -127
  121. package/sdk-core/core/src/worker/workflow/machines/side_effect_state_machine.rs +0 -71
  122. package/sdk-core/protos/api_upstream/temporal/api/cluster/v1/message.proto +0 -83
  123. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/cluster.proto +0 -40
@@ -1,7 +1,7 @@
1
1
  use crate::{
2
2
  test_help::{
3
3
  build_mock_pollers, canned_histories, hist_to_poll_resp, mock_worker, single_hist_mock_sg,
4
- MockPollCfg, ResponseType, TEST_Q,
4
+ MockPollCfg, ResponseType,
5
5
  },
6
6
  worker::{client::mocks::mock_workflow_client, LEGACY_QUERY_ID},
7
7
  };
@@ -16,22 +16,24 @@ use temporal_sdk_core_protos::{
16
16
  remove_from_cache::EvictionReason, workflow_activation_job, WorkflowActivationJob,
17
17
  },
18
18
  workflow_commands::{
19
- ActivityCancellationType, CompleteWorkflowExecution, ContinueAsNewWorkflowExecution,
20
- QueryResult, QuerySuccess, RequestCancelActivity,
19
+ query_result, ActivityCancellationType, CompleteWorkflowExecution,
20
+ ContinueAsNewWorkflowExecution, QueryResult, QuerySuccess, RequestCancelActivity,
21
21
  },
22
22
  workflow_completion::WorkflowActivationCompletion,
23
23
  },
24
24
  temporal::api::{
25
25
  common::v1::Payload,
26
+ enums::v1::EventType,
26
27
  failure::v1::Failure,
27
- history::v1::History,
28
+ history::v1::{history_event, ActivityTaskCancelRequestedEventAttributes, History},
28
29
  query::v1::WorkflowQuery,
29
30
  workflowservice::v1::{
30
31
  GetWorkflowExecutionHistoryResponse, RespondWorkflowTaskCompletedResponse,
31
32
  },
32
33
  },
34
+ TestHistoryBuilder,
33
35
  };
34
- use temporal_sdk_core_test_utils::{schedule_activity_cmd, start_timer_cmd};
36
+ use temporal_sdk_core_test_utils::{schedule_activity_cmd, start_timer_cmd, WorkerTestHelpers};
35
37
 
36
38
  #[rstest::rstest]
37
39
  #[case::with_history(true)]
@@ -44,9 +46,9 @@ async fn legacy_query(#[case] include_history: bool) {
44
46
  let mut header = HashMap::new();
45
47
  header.insert("head".to_string(), Payload::from(b"er"));
46
48
  let tasks = [
47
- hist_to_poll_resp(&t, wfid.to_owned(), 1.into(), TEST_Q.to_string()),
49
+ hist_to_poll_resp(&t, wfid.to_owned(), 1.into()),
48
50
  {
49
- let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), 1.into(), TEST_Q.to_string());
51
+ let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), 1.into());
50
52
  pr.query = Some(WorkflowQuery {
51
53
  query_type: "query-type".to_string(),
52
54
  query_args: Some(b"hi".into()),
@@ -57,7 +59,7 @@ async fn legacy_query(#[case] include_history: bool) {
57
59
  }
58
60
  pr
59
61
  },
60
- hist_to_poll_resp(&t, wfid.to_owned(), 2.into(), TEST_Q.to_string()),
62
+ hist_to_poll_resp(&t, wfid.to_owned(), 2.into()),
61
63
  ];
62
64
  let mut mock = MockPollCfg::from_resp_batches(wfid, t, tasks, mock_workflow_client());
63
65
  mock.num_expected_legacy_query_resps = 1;
@@ -155,29 +157,21 @@ async fn new_queries(#[case] num_queries: usize) {
155
157
  let t = canned_histories::single_timer("1");
156
158
  let mut header = HashMap::new();
157
159
  header.insert("head".to_string(), Payload::from(b"er"));
158
- let tasks = VecDeque::from(vec![
159
- hist_to_poll_resp(&t, wfid.to_owned(), 1.into(), TEST_Q.to_string()),
160
- {
161
- let mut pr = hist_to_poll_resp(
162
- &t,
163
- wfid.to_owned(),
164
- ResponseType::OneTask(2),
165
- TEST_Q.to_string(),
160
+ let tasks = VecDeque::from(vec![hist_to_poll_resp(&t, wfid.to_owned(), 1.into()), {
161
+ let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::OneTask(2));
162
+ pr.queries = HashMap::new();
163
+ for i in 1..=num_queries {
164
+ pr.queries.insert(
165
+ format!("q{}", i),
166
+ WorkflowQuery {
167
+ query_type: "query-type".to_string(),
168
+ query_args: Some(b"hi".into()),
169
+ header: Some(header.clone().into()),
170
+ },
166
171
  );
167
- pr.queries = HashMap::new();
168
- for i in 1..=num_queries {
169
- pr.queries.insert(
170
- format!("q{}", i),
171
- WorkflowQuery {
172
- query_type: "query-type".to_string(),
173
- query_args: Some(b"hi".into()),
174
- header: Some(header.clone().into()),
175
- },
176
- );
177
- }
178
- pr
179
- },
180
- ]);
172
+ }
173
+ pr
174
+ }]);
181
175
  let mut mock_client = mock_workflow_client();
182
176
  mock_client.expect_respond_legacy_query().times(0);
183
177
  let mut mock = single_hist_mock_sg(wfid, t, tasks, mock_client, true);
@@ -237,19 +231,16 @@ async fn new_queries(#[case] num_queries: usize) {
237
231
  async fn legacy_query_failure_on_wft_failure() {
238
232
  let wfid = "fake_wf_id";
239
233
  let t = canned_histories::single_timer("1");
240
- let tasks = VecDeque::from(vec![
241
- hist_to_poll_resp(&t, wfid.to_owned(), 1.into(), TEST_Q.to_string()),
242
- {
243
- let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), 1.into(), TEST_Q.to_string());
244
- pr.query = Some(WorkflowQuery {
245
- query_type: "query-type".to_string(),
246
- query_args: Some(b"hi".into()),
247
- header: None,
248
- });
249
- pr.history = Some(History { events: vec![] });
250
- pr
251
- },
252
- ]);
234
+ let tasks = VecDeque::from(vec![hist_to_poll_resp(&t, wfid.to_owned(), 1.into()), {
235
+ let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), 1.into());
236
+ pr.query = Some(WorkflowQuery {
237
+ query_type: "query-type".to_string(),
238
+ query_args: Some(b"hi".into()),
239
+ header: None,
240
+ });
241
+ pr.history = Some(History { events: vec![] });
242
+ pr
243
+ }]);
253
244
  let mut mock = MockPollCfg::from_resp_batches(wfid, t, tasks, mock_workflow_client());
254
245
  mock.num_expected_legacy_query_resps = 1;
255
246
  let mut mock = build_mock_pollers(mock);
@@ -292,12 +283,7 @@ async fn query_failure_because_nondeterminism(#[values(true, false)] legacy: boo
292
283
  let wfid = "fake_wf_id";
293
284
  let t = canned_histories::single_timer("1");
294
285
  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
- );
286
+ let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::AllHistory);
301
287
  if legacy {
302
288
  pr.query = Some(WorkflowQuery {
303
289
  query_type: "query-type".to_string(),
@@ -356,12 +342,7 @@ async fn legacy_query_after_complete(#[values(false, true)] full_history: bool)
356
342
  t
357
343
  };
358
344
  let query_with_hist_task = {
359
- let mut pr = hist_to_poll_resp(
360
- &t,
361
- wfid.to_owned(),
362
- ResponseType::AllHistory,
363
- TEST_Q.to_string(),
364
- );
345
+ let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::AllHistory);
365
346
  pr.query = Some(WorkflowQuery {
366
347
  query_type: "query-type".to_string(),
367
348
  query_args: Some(b"hi".into()),
@@ -375,15 +356,7 @@ async fn legacy_query_after_complete(#[values(false, true)] full_history: bool)
375
356
  let mut tasks = if full_history {
376
357
  vec![]
377
358
  } 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
- ]
359
+ vec![hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::AllHistory).resp]
387
360
  };
388
361
  tasks.extend([query_with_hist_task.clone(), query_with_hist_task]);
389
362
 
@@ -456,29 +429,14 @@ async fn query_cache_miss_causes_page_fetch_dont_reply_wft_too_early(
456
429
  QueryHists::Empty => {
457
430
  // Create a no-history poll response. This happens to be easiest to do by just ripping
458
431
  // out the history after making a normal one.
459
- let mut pr = hist_to_poll_resp(
460
- &t,
461
- wfid.to_owned(),
462
- ResponseType::AllHistory,
463
- TEST_Q.to_string(),
464
- );
432
+ let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::AllHistory);
465
433
  pr.history = Some(Default::default());
466
434
  pr
467
435
  }
468
- QueryHists::Full => hist_to_poll_resp(
469
- &t,
470
- wfid.to_owned(),
471
- ResponseType::AllHistory,
472
- TEST_Q.to_string(),
473
- ),
436
+ QueryHists::Full => hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::AllHistory),
474
437
  QueryHists::Partial => {
475
438
  // Create a partial task
476
- hist_to_poll_resp(
477
- &t,
478
- wfid.to_owned(),
479
- ResponseType::OneTask(2),
480
- TEST_Q.to_string(),
481
- )
439
+ hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::OneTask(2))
482
440
  }
483
441
  };
484
442
  pr.queries = HashMap::new();
@@ -579,12 +537,7 @@ async fn query_replay_with_continue_as_new_doesnt_reply_empty_command() {
579
537
  let wfid = "fake_wf_id";
580
538
  let t = canned_histories::single_timer("1");
581
539
  let query_with_hist_task = {
582
- let mut pr = hist_to_poll_resp(
583
- &t,
584
- wfid.to_owned(),
585
- ResponseType::ToTaskNum(1),
586
- TEST_Q.to_string(),
587
- );
540
+ let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::ToTaskNum(1));
588
541
  pr.queries = HashMap::new();
589
542
  pr.queries.insert(
590
543
  "the-query".to_string(),
@@ -682,7 +635,7 @@ async fn legacy_query_response_gets_not_found_not_fatal() {
682
635
  let wfid = "fake_wf_id";
683
636
  let t = canned_histories::single_timer("1");
684
637
  let tasks = [{
685
- let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), 1.into(), TEST_Q.to_string());
638
+ let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), 1.into());
686
639
  pr.query = Some(WorkflowQuery {
687
640
  query_type: "query-type".to_string(),
688
641
  query_args: Some(b"hi".into()),
@@ -734,3 +687,208 @@ async fn legacy_query_response_gets_not_found_not_fatal() {
734
687
 
735
688
  core.shutdown().await;
736
689
  }
690
+
691
+ #[tokio::test]
692
+ async fn new_query_fail() {
693
+ let wfid = "fake_wf_id";
694
+ let t = canned_histories::single_timer("1");
695
+ let tasks = VecDeque::from(vec![{
696
+ let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), 1.into());
697
+ pr.queries = HashMap::new();
698
+ pr.queries.insert(
699
+ "q1".to_string(),
700
+ WorkflowQuery {
701
+ query_type: "query-type".to_string(),
702
+ query_args: Some(b"hi".into()),
703
+ header: Default::default(),
704
+ },
705
+ );
706
+ pr
707
+ }]);
708
+ let mut mock_client = mock_workflow_client();
709
+ mock_client
710
+ .expect_complete_workflow_task()
711
+ .times(1)
712
+ .returning(|resp| {
713
+ // Verify there is a failed query response along w/ start timer cmd
714
+ assert_eq!(resp.commands.len(), 1);
715
+ assert_matches!(
716
+ resp.query_responses.as_slice(),
717
+ &[QueryResult {
718
+ variant: Some(query_result::Variant::Failed(_)),
719
+ ..
720
+ }]
721
+ );
722
+ Ok(RespondWorkflowTaskCompletedResponse::default())
723
+ });
724
+
725
+ let mut mock = single_hist_mock_sg(wfid, t, tasks, mock_client, true);
726
+ mock.worker_cfg(|wc| wc.max_cached_workflows = 10);
727
+ let core = mock_worker(mock);
728
+
729
+ let task = core.poll_workflow_activation().await.unwrap();
730
+ assert_matches!(
731
+ task.jobs[0],
732
+ WorkflowActivationJob {
733
+ variant: Some(workflow_activation_job::Variant::StartWorkflow(_)),
734
+ }
735
+ );
736
+
737
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
738
+ task.run_id,
739
+ start_timer_cmd(1, Duration::from_secs(1)),
740
+ ))
741
+ .await
742
+ .unwrap();
743
+ let task = core.poll_workflow_activation().await.unwrap();
744
+ assert_matches!(
745
+ task.jobs[0],
746
+ WorkflowActivationJob {
747
+ variant: Some(workflow_activation_job::Variant::QueryWorkflow(_)),
748
+ }
749
+ );
750
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
751
+ task.run_id,
752
+ QueryResult {
753
+ query_id: "q1".to_string(),
754
+ variant: Some(query_result::Variant::Failed("ahhh".into())),
755
+ }
756
+ .into(),
757
+ ))
758
+ .await
759
+ .unwrap();
760
+ }
761
+
762
+ /// This test verifies that if we get a task with a legacy query in it while in the middle of
763
+ /// processing some local-only work (in this case, resolving an activity as soon as it was
764
+ /// cancelled) that we do not combine the legacy query with the resolve job.
765
+ #[tokio::test]
766
+ async fn legacy_query_combined_with_timer_fire_repro() {
767
+ let wfid = "fake_wf_id";
768
+ let mut t = TestHistoryBuilder::default();
769
+ t.add_by_type(EventType::WorkflowExecutionStarted);
770
+ t.add_full_wf_task();
771
+ let scheduled_event_id = t.add_activity_task_scheduled("1");
772
+ let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
773
+ t.add_timer_fired(timer_started_event_id, "1".to_string());
774
+ t.add_full_wf_task();
775
+ t.add(
776
+ EventType::ActivityTaskCancelRequested,
777
+ history_event::Attributes::ActivityTaskCancelRequestedEventAttributes(
778
+ ActivityTaskCancelRequestedEventAttributes {
779
+ scheduled_event_id,
780
+ ..Default::default()
781
+ },
782
+ ),
783
+ );
784
+
785
+ let tasks = [
786
+ hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::ToTaskNum(1)),
787
+ {
788
+ // One task is super important here - as we need to look like we hit the cache
789
+ // to apply this query right away
790
+ let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::OneTask(2));
791
+ pr.queries = HashMap::new();
792
+ pr.queries.insert(
793
+ "the-query".to_string(),
794
+ WorkflowQuery {
795
+ query_type: "query-type".to_string(),
796
+ query_args: Some(b"hi".into()),
797
+ header: None,
798
+ },
799
+ );
800
+ pr
801
+ },
802
+ {
803
+ let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::ToTaskNum(2));
804
+ // Strip history, we need to look like we hit the cache for a legacy query
805
+ pr.history = Some(History { events: vec![] });
806
+ pr.query = Some(WorkflowQuery {
807
+ query_type: "query-type".to_string(),
808
+ query_args: Some(b"hi".into()),
809
+ header: None,
810
+ });
811
+ pr
812
+ },
813
+ ];
814
+ let mut mock = mock_workflow_client();
815
+ mock.expect_respond_legacy_query()
816
+ .times(1)
817
+ .returning(move |_, _| Ok(Default::default()));
818
+ let mut mock = single_hist_mock_sg(wfid, t, tasks, mock, true);
819
+ mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
820
+ let core = mock_worker(mock);
821
+
822
+ let task = core.poll_workflow_activation().await.unwrap();
823
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
824
+ task.run_id,
825
+ vec![
826
+ schedule_activity_cmd(
827
+ 1,
828
+ "whatever",
829
+ "1",
830
+ ActivityCancellationType::TryCancel,
831
+ Duration::from_secs(60),
832
+ Duration::from_secs(60),
833
+ ),
834
+ start_timer_cmd(1, Duration::from_secs(1)),
835
+ ],
836
+ ))
837
+ .await
838
+ .unwrap();
839
+
840
+ let task = core.poll_workflow_activation().await.unwrap();
841
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
842
+ task.run_id,
843
+ vec![
844
+ RequestCancelActivity { seq: 1 }.into(),
845
+ QueryResult {
846
+ query_id: "the-query".to_string(),
847
+ variant: Some(
848
+ QuerySuccess {
849
+ response: Some("whatever".into()),
850
+ }
851
+ .into(),
852
+ ),
853
+ }
854
+ .into(),
855
+ ],
856
+ ))
857
+ .await
858
+ .unwrap();
859
+
860
+ // First should get the activity resolve
861
+ let task = core.poll_workflow_activation().await.unwrap();
862
+ assert_matches!(
863
+ task.jobs.as_slice(),
864
+ [WorkflowActivationJob {
865
+ variant: Some(workflow_activation_job::Variant::ResolveActivity(_)),
866
+ }]
867
+ );
868
+ core.complete_execution(&task.run_id).await;
869
+
870
+ // Then the query
871
+ let task = core.poll_workflow_activation().await.unwrap();
872
+ assert_matches!(
873
+ task.jobs.as_slice(),
874
+ [WorkflowActivationJob {
875
+ variant: Some(workflow_activation_job::Variant::QueryWorkflow(_)),
876
+ }]
877
+ );
878
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
879
+ task.run_id,
880
+ QueryResult {
881
+ query_id: LEGACY_QUERY_ID.to_string(),
882
+ variant: Some(
883
+ QuerySuccess {
884
+ response: Some("whatever".into()),
885
+ }
886
+ .into(),
887
+ ),
888
+ }
889
+ .into(),
890
+ ))
891
+ .await
892
+ .unwrap();
893
+ core.shutdown().await;
894
+ }
@@ -24,7 +24,7 @@ use tokio::sync::{watch, Barrier};
24
24
  #[tokio::test]
25
25
  async fn after_shutdown_of_worker_get_shutdown_err() {
26
26
  let t = canned_histories::single_timer("1");
27
- let worker = build_fake_worker("fake_wf_id", t, &[1]);
27
+ let worker = build_fake_worker("fake_wf_id", t, [1]);
28
28
  let res = worker.poll_workflow_activation().await.unwrap();
29
29
  assert_eq!(res.jobs.len(), 1);
30
30
  let run_id = res.run_id;
@@ -53,7 +53,7 @@ async fn after_shutdown_of_worker_get_shutdown_err() {
53
53
  #[tokio::test]
54
54
  async fn shutdown_worker_can_complete_pending_activation() {
55
55
  let t = canned_histories::single_timer("1");
56
- let worker = build_fake_worker("fake_wf_id", t, &[2]);
56
+ let worker = build_fake_worker("fake_wf_id", t, [2]);
57
57
  let res = worker.poll_workflow_activation().await.unwrap();
58
58
  assert_eq!(res.jobs.len(), 1);
59
59
  // Complete the timer, will queue PA
@@ -107,7 +107,7 @@ async fn timer_then_cancel_req_then_timer_then_cancelled() {
107
107
  async fn immediate_cancel() {
108
108
  let wfid = "fake_wf_id";
109
109
  let t = canned_histories::immediate_wf_cancel();
110
- let core = build_fake_worker(wfid, t, &[1]);
110
+ let core = build_fake_worker(wfid, t, [1]);
111
111
 
112
112
  poll_and_reply(
113
113
  &core,
@@ -7,7 +7,6 @@ use crate::{
7
7
  mock_worker, poll_and_reply, poll_and_reply_clears_outstanding_evicts, single_hist_mock_sg,
8
8
  test_worker_cfg, FakeWfResponses, MockPollCfg, MocksHolder, ResponseType,
9
9
  WorkflowCachingPolicy::{self, AfterEveryReply, NonSticky},
10
- TEST_Q,
11
10
  },
12
11
  worker::client::mocks::{mock_manual_workflow_client, mock_workflow_client},
13
12
  Worker,
@@ -652,7 +651,7 @@ async fn workflow_update_random_seed_on_workflow_reset() {
652
651
  timer_1_id.to_string().as_str(),
653
652
  new_run_id,
654
653
  );
655
- let core = build_fake_worker(wfid, t, &[2]);
654
+ let core = build_fake_worker(wfid, t, [2]);
656
655
 
657
656
  poll_and_reply(
658
657
  &core,
@@ -706,7 +705,7 @@ async fn cancel_timer_before_sent_wf_bridge() {
706
705
  t.add_full_wf_task();
707
706
  t.add_workflow_execution_completed();
708
707
 
709
- let core = build_fake_worker(wfid, t, &[1]);
708
+ let core = build_fake_worker(wfid, t, [1]);
710
709
 
711
710
  poll_and_reply(
712
711
  &core,
@@ -1037,7 +1036,6 @@ async fn lots_of_workflows() {
1037
1036
  let completed_count = Arc::new(Semaphore::new(0));
1038
1037
  let killer = async {
1039
1038
  let _ = completed_count.acquire_many(total_wfs).await.unwrap();
1040
- dbg!("Shutdown initted");
1041
1039
  worker.initiate_shutdown();
1042
1040
  };
1043
1041
  let poller = fanout_tasks(5, |_| {
@@ -1122,7 +1120,7 @@ async fn complete_after_eviction() {
1122
1120
  let t = canned_histories::single_timer("1");
1123
1121
  let mut mock = mock_workflow_client();
1124
1122
  mock.expect_complete_workflow_task().times(0);
1125
- let mock = single_hist_mock_sg(wfid, t, &[2], mock, true);
1123
+ let mock = single_hist_mock_sg(wfid, t, [2], mock, true);
1126
1124
  let core = mock_worker(mock);
1127
1125
 
1128
1126
  let activation = core.poll_workflow_activation().await.unwrap();
@@ -1164,7 +1162,7 @@ async fn sends_appropriate_sticky_task_queue_responses() {
1164
1162
  .times(1)
1165
1163
  .returning(|_| Ok(Default::default()));
1166
1164
  mock.expect_complete_workflow_task().times(0);
1167
- let mut mock = single_hist_mock_sg(wfid, t, &[1], mock, false);
1165
+ let mut mock = single_hist_mock_sg(wfid, t, [1], mock, false);
1168
1166
  mock.worker_cfg(|wc| wc.max_cached_workflows = 10);
1169
1167
  let core = mock_worker(mock);
1170
1168
 
@@ -1182,7 +1180,7 @@ async fn sends_appropriate_sticky_task_queue_responses() {
1182
1180
  async fn new_server_work_while_eviction_outstanding_doesnt_overwrite_activation() {
1183
1181
  let wfid = "fake_wf_id";
1184
1182
  let t = canned_histories::single_timer("1");
1185
- let mock = single_hist_mock_sg(wfid, t, &[1, 2], mock_workflow_client(), false);
1183
+ let mock = single_hist_mock_sg(wfid, t, [1, 2], mock_workflow_client(), false);
1186
1184
  let taskmap = mock.outstanding_task_map.clone().unwrap();
1187
1185
  let core = mock_worker(mock);
1188
1186
 
@@ -1224,7 +1222,7 @@ async fn buffered_work_drained_on_shutdown() {
1224
1222
  t.add_workflow_task_scheduled_and_started();
1225
1223
  // Need to build the first response before adding the timeout events b/c otherwise the history
1226
1224
  // builder will include them in the first task
1227
- let resp_1 = hist_to_poll_resp(&t, wfid.to_owned(), 1.into(), TEST_Q.to_string()).resp;
1225
+ let resp_1 = hist_to_poll_resp(&t, wfid.to_owned(), 1.into()).resp;
1228
1226
  t.add_workflow_task_timed_out();
1229
1227
  t.add_full_wf_task();
1230
1228
  let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
@@ -1242,10 +1240,7 @@ async fn buffered_work_drained_on_shutdown() {
1242
1240
  // Extend the task list with the now timeout-included version of the task. We add a bunch of
1243
1241
  // them because the poll loop will spin while new tasks are available and it is buffering them
1244
1242
  tasks.extend(
1245
- std::iter::repeat_with(|| {
1246
- hist_to_poll_resp(&t, wfid.to_owned(), 2.into(), TEST_Q.to_string()).resp
1247
- })
1248
- .take(50),
1243
+ std::iter::repeat_with(|| hist_to_poll_resp(&t, wfid.to_owned(), 2.into()).resp).take(50),
1249
1244
  );
1250
1245
  let mut mock = mock_workflow_client();
1251
1246
  mock.expect_complete_workflow_task()
@@ -1448,7 +1443,7 @@ async fn tries_cancel_of_completed_activity() {
1448
1443
  t.add_workflow_task_scheduled_and_started();
1449
1444
 
1450
1445
  let mock = mock_workflow_client();
1451
- let mut mock = single_hist_mock_sg("fake_wf_id", t, &[1, 2], mock, true);
1446
+ let mut mock = single_hist_mock_sg("fake_wf_id", t, [1, 2], mock, true);
1452
1447
  mock.worker_cfg(|cfg| cfg.max_cached_workflows = 1);
1453
1448
  let core = mock_worker(mock);
1454
1449
 
@@ -1658,9 +1653,7 @@ async fn tasks_from_completion_are_delivered() {
1658
1653
 
1659
1654
  let mut mock = mock_workflow_client();
1660
1655
  let complete_resp = RespondWorkflowTaskCompletedResponse {
1661
- workflow_task: Some(
1662
- hist_to_poll_resp(&t, wfid.to_owned(), 2.into(), TEST_Q.to_string()).resp,
1663
- ),
1656
+ workflow_task: Some(hist_to_poll_resp(&t, wfid.to_owned(), 2.into()).resp),
1664
1657
  activity_tasks: vec![],
1665
1658
  };
1666
1659
  mock.expect_complete_workflow_task()
@@ -1829,7 +1822,7 @@ async fn eviction_waits_until_replay_finished() {
1829
1822
  let wfid = "fake_wf_id";
1830
1823
  let t = canned_histories::long_sequential_timers(3);
1831
1824
  let mock = mock_workflow_client();
1832
- let mock = single_hist_mock_sg(wfid, t, &[3], mock, true);
1825
+ let mock = single_hist_mock_sg(wfid, t, [3], mock, true);
1833
1826
  let core = mock_worker(mock);
1834
1827
 
1835
1828
  let activation = core.poll_workflow_activation().await.unwrap();
@@ -1890,7 +1883,7 @@ async fn autocompletes_wft_no_work() {
1890
1883
  t.add_activity_task_completed(scheduled_event_id, started_event_id, Default::default());
1891
1884
  t.add_full_wf_task();
1892
1885
  let mock = mock_workflow_client();
1893
- let mut mock = single_hist_mock_sg(wfid, t, &[1, 2, 3, 4], mock, true);
1886
+ let mut mock = single_hist_mock_sg(wfid, t, [1, 2, 3, 4], mock, true);
1894
1887
  mock.worker_cfg(|w| w.max_cached_workflows = 1);
1895
1888
  let core = mock_worker(mock);
1896
1889
 
@@ -1951,8 +1944,7 @@ async fn no_race_acquiring_permits() {
1951
1944
  .expect_poll_workflow_task()
1952
1945
  .returning(move |_, _| {
1953
1946
  let t = canned_histories::single_timer("1");
1954
- let poll_resp =
1955
- hist_to_poll_resp(&t, wfid.to_owned(), 2.into(), TEST_Q.to_string()).resp;
1947
+ let poll_resp = hist_to_poll_resp(&t, wfid.to_owned(), 2.into()).resp;
1956
1948
  async move {
1957
1949
  task_barr.wait().await;
1958
1950
  Ok(poll_resp.clone())
@@ -2031,13 +2023,7 @@ async fn continue_as_new_preserves_some_values() {
2031
2023
  mock_client
2032
2024
  .expect_poll_workflow_task()
2033
2025
  .returning(move |_, _| {
2034
- Ok(hist_to_poll_resp(
2035
- &hist,
2036
- wfid.to_owned(),
2037
- ResponseType::AllHistory,
2038
- TEST_Q.to_string(),
2039
- )
2040
- .resp)
2026
+ Ok(hist_to_poll_resp(&hist, wfid.to_owned(), ResponseType::AllHistory).resp)
2041
2027
  });
2042
2028
  mock_client
2043
2029
  .expect_complete_workflow_task()
@@ -2068,3 +2054,36 @@ async fn continue_as_new_preserves_some_values() {
2068
2054
  .await
2069
2055
  .unwrap();
2070
2056
  }
2057
+
2058
+ #[rstest]
2059
+ #[tokio::test]
2060
+ async fn ignorable_events_are_ok(#[values(true, false)] attribs_unset: bool) {
2061
+ let mut t = TestHistoryBuilder::default();
2062
+ t.add_by_type(EventType::WorkflowExecutionStarted);
2063
+ let id = t.add_get_event_id(
2064
+ EventType::Unspecified,
2065
+ Some(
2066
+ history_event::Attributes::WorkflowPropertiesModifiedExternallyEventAttributes(
2067
+ Default::default(),
2068
+ ),
2069
+ ),
2070
+ );
2071
+ t.modify_event(id, |e| e.worker_may_ignore = true);
2072
+ if attribs_unset {
2073
+ t.modify_event(id, |e| {
2074
+ e.event_type = EventType::WorkflowPropertiesModifiedExternally as i32;
2075
+ e.attributes = None;
2076
+ });
2077
+ }
2078
+ t.add_workflow_task_scheduled_and_started();
2079
+
2080
+ let mock = mock_workflow_client();
2081
+ let mock = single_hist_mock_sg("wheee", t, [ResponseType::AllHistory], mock, true);
2082
+ let core = mock_worker(mock);
2083
+
2084
+ let act = core.poll_workflow_activation().await.unwrap();
2085
+ assert_matches!(
2086
+ act.jobs[0].variant,
2087
+ Some(workflow_activation_job::Variant::StartWorkflow(_))
2088
+ );
2089
+ }