@temporalio/core-bridge 1.5.2 → 1.7.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 (194) hide show
  1. package/Cargo.lock +304 -112
  2. package/lib/index.d.ts +8 -6
  3. package/lib/index.js.map +1 -1
  4. package/package.json +9 -4
  5. package/releases/aarch64-apple-darwin/index.node +0 -0
  6. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  7. package/releases/x86_64-apple-darwin/index.node +0 -0
  8. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  9. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  10. package/sdk-core/.buildkite/docker/Dockerfile +2 -2
  11. package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
  12. package/sdk-core/.buildkite/pipeline.yml +2 -4
  13. package/sdk-core/.cargo/config.toml +5 -2
  14. package/sdk-core/.github/workflows/heavy.yml +29 -0
  15. package/sdk-core/Cargo.toml +1 -1
  16. package/sdk-core/README.md +20 -10
  17. package/sdk-core/client/src/lib.rs +215 -39
  18. package/sdk-core/client/src/metrics.rs +17 -8
  19. package/sdk-core/client/src/raw.rs +4 -4
  20. package/sdk-core/client/src/retry.rs +32 -20
  21. package/sdk-core/core/Cargo.toml +25 -12
  22. package/sdk-core/core/src/abstractions/take_cell.rs +28 -0
  23. package/sdk-core/core/src/abstractions.rs +204 -14
  24. package/sdk-core/core/src/core_tests/activity_tasks.rs +143 -50
  25. package/sdk-core/core/src/core_tests/child_workflows.rs +6 -5
  26. package/sdk-core/core/src/core_tests/determinism.rs +165 -2
  27. package/sdk-core/core/src/core_tests/local_activities.rs +431 -43
  28. package/sdk-core/core/src/core_tests/queries.rs +34 -16
  29. package/sdk-core/core/src/core_tests/workers.rs +8 -5
  30. package/sdk-core/core/src/core_tests/workflow_tasks.rs +588 -55
  31. package/sdk-core/core/src/ephemeral_server/mod.rs +113 -12
  32. package/sdk-core/core/src/internal_flags.rs +155 -0
  33. package/sdk-core/core/src/lib.rs +16 -9
  34. package/sdk-core/core/src/protosext/mod.rs +1 -1
  35. package/sdk-core/core/src/replay/mod.rs +16 -27
  36. package/sdk-core/core/src/telemetry/log_export.rs +1 -1
  37. package/sdk-core/core/src/telemetry/metrics.rs +69 -35
  38. package/sdk-core/core/src/telemetry/mod.rs +60 -21
  39. package/sdk-core/core/src/telemetry/prometheus_server.rs +19 -13
  40. package/sdk-core/core/src/test_help/mod.rs +73 -14
  41. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +119 -160
  42. package/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
  43. package/sdk-core/core/src/worker/activities/local_activities.rs +379 -129
  44. package/sdk-core/core/src/worker/activities.rs +350 -175
  45. package/sdk-core/core/src/worker/client/mocks.rs +22 -2
  46. package/sdk-core/core/src/worker/client.rs +18 -2
  47. package/sdk-core/core/src/worker/mod.rs +183 -64
  48. package/sdk-core/core/src/worker/workflow/bridge.rs +1 -3
  49. package/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -5
  50. package/sdk-core/core/src/worker/workflow/history_update.rs +916 -277
  51. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +216 -183
  52. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +9 -12
  53. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +7 -9
  54. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +160 -87
  55. package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +13 -14
  56. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +7 -9
  57. package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +14 -17
  58. package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +242 -110
  59. package/sdk-core/core/src/worker/workflow/machines/mod.rs +27 -19
  60. package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +9 -11
  61. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +321 -206
  62. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +13 -18
  63. package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +20 -29
  64. package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +2 -2
  65. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +257 -51
  66. package/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +6 -17
  67. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +310 -150
  68. package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +17 -20
  69. package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +31 -15
  70. package/sdk-core/core/src/worker/workflow/managed_run.rs +1052 -380
  71. package/sdk-core/core/src/worker/workflow/mod.rs +598 -390
  72. package/sdk-core/core/src/worker/workflow/run_cache.rs +40 -57
  73. package/sdk-core/core/src/worker/workflow/wft_extraction.rs +137 -0
  74. package/sdk-core/core/src/worker/workflow/wft_poller.rs +1 -4
  75. package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +117 -0
  76. package/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +24 -0
  77. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +469 -718
  78. package/sdk-core/core-api/Cargo.toml +2 -1
  79. package/sdk-core/core-api/src/errors.rs +1 -34
  80. package/sdk-core/core-api/src/lib.rs +19 -9
  81. package/sdk-core/core-api/src/telemetry.rs +4 -6
  82. package/sdk-core/core-api/src/worker.rs +19 -1
  83. package/sdk-core/etc/deps.svg +115 -140
  84. package/sdk-core/etc/regen-depgraph.sh +5 -0
  85. package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +86 -61
  86. package/sdk-core/fsm/rustfsm_trait/src/lib.rs +29 -71
  87. package/sdk-core/histories/ends_empty_wft_complete.bin +0 -0
  88. package/sdk-core/histories/evict_while_la_running_no_interference-16_history.bin +0 -0
  89. package/sdk-core/histories/old_change_marker_format.bin +0 -0
  90. package/sdk-core/protos/api_upstream/.github/CODEOWNERS +2 -1
  91. package/sdk-core/protos/api_upstream/Makefile +6 -6
  92. package/sdk-core/protos/api_upstream/build/go.mod +7 -0
  93. package/sdk-core/protos/api_upstream/build/go.sum +5 -0
  94. package/sdk-core/protos/api_upstream/build/tools.go +29 -0
  95. package/sdk-core/protos/api_upstream/go.mod +6 -0
  96. package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +9 -2
  97. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +7 -26
  98. package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +13 -2
  99. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +3 -2
  100. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +3 -7
  101. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +3 -2
  102. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +8 -8
  103. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +25 -2
  104. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +2 -2
  105. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +2 -2
  106. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +2 -2
  107. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +2 -2
  108. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +2 -2
  109. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +24 -19
  110. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +2 -2
  111. package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +2 -2
  112. package/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +2 -2
  113. package/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +2 -2
  114. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +49 -26
  115. package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +4 -2
  116. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +5 -2
  117. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +2 -2
  118. package/sdk-core/protos/api_upstream/temporal/api/protocol/v1/message.proto +57 -0
  119. package/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +2 -2
  120. package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +2 -2
  121. package/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +2 -2
  122. package/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
  123. package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -2
  124. package/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +71 -6
  125. package/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +2 -2
  126. package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +2 -2
  127. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +64 -28
  128. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +4 -4
  129. package/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +7 -8
  130. package/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +10 -7
  131. package/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +19 -30
  132. package/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
  133. package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
  134. package/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +8 -0
  135. package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +67 -60
  136. package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +85 -84
  137. package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +9 -3
  138. package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +2 -2
  139. package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +2 -2
  140. package/sdk-core/sdk/Cargo.toml +5 -4
  141. package/sdk-core/sdk/src/lib.rs +108 -26
  142. package/sdk-core/sdk/src/workflow_context/options.rs +7 -1
  143. package/sdk-core/sdk/src/workflow_context.rs +24 -17
  144. package/sdk-core/sdk/src/workflow_future.rs +16 -15
  145. package/sdk-core/sdk-core-protos/Cargo.toml +5 -2
  146. package/sdk-core/sdk-core-protos/build.rs +36 -2
  147. package/sdk-core/sdk-core-protos/src/history_builder.rs +138 -106
  148. package/sdk-core/sdk-core-protos/src/history_info.rs +10 -1
  149. package/sdk-core/sdk-core-protos/src/lib.rs +272 -87
  150. package/sdk-core/sdk-core-protos/src/task_token.rs +12 -2
  151. package/sdk-core/test-utils/Cargo.toml +3 -1
  152. package/sdk-core/test-utils/src/canned_histories.rs +106 -296
  153. package/sdk-core/test-utils/src/histfetch.rs +1 -1
  154. package/sdk-core/test-utils/src/lib.rs +82 -23
  155. package/sdk-core/test-utils/src/wf_input_saver.rs +50 -0
  156. package/sdk-core/test-utils/src/workflows.rs +29 -0
  157. package/sdk-core/tests/fuzzy_workflow.rs +130 -0
  158. package/sdk-core/tests/{load_tests.rs → heavy_tests.rs} +125 -51
  159. package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
  160. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +10 -5
  161. package/sdk-core/tests/integ_tests/metrics_tests.rs +218 -16
  162. package/sdk-core/tests/integ_tests/polling_tests.rs +4 -47
  163. package/sdk-core/tests/integ_tests/queries_tests.rs +5 -128
  164. package/sdk-core/tests/integ_tests/visibility_tests.rs +83 -25
  165. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +161 -72
  166. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
  167. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +6 -13
  168. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +80 -3
  169. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +6 -2
  170. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -10
  171. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +94 -200
  172. package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +2 -4
  173. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +34 -28
  174. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +76 -7
  175. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
  176. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +18 -14
  177. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +6 -20
  178. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +10 -21
  179. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +7 -8
  180. package/sdk-core/tests/integ_tests/workflow_tests.rs +13 -14
  181. package/sdk-core/tests/main.rs +3 -13
  182. package/sdk-core/tests/runner.rs +75 -36
  183. package/sdk-core/tests/wf_input_replay.rs +32 -0
  184. package/src/conversions.rs +14 -8
  185. package/src/runtime.rs +9 -8
  186. package/ts/index.ts +8 -6
  187. package/sdk-core/bridge-ffi/Cargo.toml +0 -24
  188. package/sdk-core/bridge-ffi/LICENSE.txt +0 -23
  189. package/sdk-core/bridge-ffi/build.rs +0 -25
  190. package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +0 -224
  191. package/sdk-core/bridge-ffi/src/lib.rs +0 -746
  192. package/sdk-core/bridge-ffi/src/wrappers.rs +0 -221
  193. package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +0 -210
  194. package/sdk-core/sdk/src/conversions.rs +0 -8
@@ -16,11 +16,12 @@ use rstest::{fixture, rstest};
16
16
  use std::{
17
17
  collections::{HashMap, VecDeque},
18
18
  sync::{
19
- atomic::{AtomicU64, Ordering},
19
+ atomic::{AtomicBool, AtomicU64, Ordering},
20
20
  Arc,
21
21
  },
22
22
  time::Duration,
23
23
  };
24
+ use temporal_client::WorkflowOptions;
24
25
  use temporal_sdk::{ActivityOptions, CancellableFuture, WfContext};
25
26
  use temporal_sdk_core_api::{errors::PollWfError, Worker as WorkerTrait};
26
27
  use temporal_sdk_core_protos::{
@@ -33,24 +34,29 @@ use temporal_sdk_core_protos::{
33
34
  workflow_commands::{
34
35
  ActivityCancellationType, CancelTimer, CompleteWorkflowExecution,
35
36
  ContinueAsNewWorkflowExecution, FailWorkflowExecution, RequestCancelActivity,
36
- ScheduleActivity,
37
+ ScheduleActivity, SetPatchMarker,
37
38
  },
38
39
  workflow_completion::WorkflowActivationCompletion,
39
40
  },
40
- default_wes_attribs,
41
+ default_act_sched, default_wes_attribs,
41
42
  temporal::api::{
42
43
  command::v1::command::Attributes,
43
44
  common::v1::{Payload, RetryPolicy},
44
45
  enums::v1::{EventType, WorkflowTaskFailedCause},
45
46
  failure::v1::Failure,
46
- history::v1::{history_event, TimerFiredEventAttributes},
47
+ history::v1::{
48
+ history_event, TimerFiredEventAttributes,
49
+ WorkflowPropertiesModifiedExternallyEventAttributes,
50
+ },
47
51
  workflowservice::v1::{
48
52
  GetWorkflowExecutionHistoryResponse, RespondWorkflowTaskCompletedResponse,
49
53
  },
50
54
  },
51
- DEFAULT_WORKFLOW_TYPE,
55
+ DEFAULT_ACTIVITY_TYPE, DEFAULT_WORKFLOW_TYPE,
56
+ };
57
+ use temporal_sdk_core_test_utils::{
58
+ fanout_tasks, schedule_activity_cmd, start_timer_cmd, WorkerTestHelpers,
52
59
  };
53
- use temporal_sdk_core_test_utils::{fanout_tasks, start_timer_cmd};
54
60
  use tokio::{
55
61
  join,
56
62
  sync::{Barrier, Semaphore},
@@ -120,7 +126,7 @@ async fn single_activity_completion(worker: Worker) {
120
126
  &job_assert!(workflow_activation_job::Variant::StartWorkflow(_)),
121
127
  vec![ScheduleActivity {
122
128
  activity_id: "fake_activity".to_string(),
123
- ..Default::default()
129
+ ..default_act_sched()
124
130
  }
125
131
  .into()],
126
132
  ),
@@ -245,7 +251,7 @@ async fn scheduled_activity_cancellation_try_cancel(hist_batches: &'static [usiz
245
251
  seq: activity_seq,
246
252
  activity_id: activity_id.to_string(),
247
253
  cancellation_type: ActivityCancellationType::TryCancel as i32,
248
- ..Default::default()
254
+ ..default_act_sched()
249
255
  }
250
256
  .into()],
251
257
  ),
@@ -281,7 +287,7 @@ async fn scheduled_activity_timeout(hist_batches: &'static [usize]) {
281
287
  vec![ScheduleActivity {
282
288
  seq: activity_seq,
283
289
  activity_id: activity_id.to_string(),
284
- ..Default::default()
290
+ ..default_act_sched()
285
291
  }
286
292
  .into()],
287
293
  ),
@@ -334,7 +340,7 @@ async fn started_activity_timeout(hist_batches: &'static [usize]) {
334
340
  vec![ScheduleActivity {
335
341
  seq: activity_seq,
336
342
  activity_id: activity_seq.to_string(),
337
- ..Default::default()
343
+ ..default_act_sched()
338
344
  }
339
345
  .into()],
340
346
  ),
@@ -389,7 +395,7 @@ async fn cancelled_activity_timeout(hist_batches: &'static [usize]) {
389
395
  vec![ScheduleActivity {
390
396
  seq: activity_seq,
391
397
  activity_id: activity_id.to_string(),
392
- ..Default::default()
398
+ ..default_act_sched()
393
399
  }
394
400
  .into()],
395
401
  ),
@@ -457,10 +463,10 @@ async fn abandoned_activities_ignore_start_and_complete(hist_batches: &'static [
457
463
  t.add_by_type(EventType::WorkflowExecutionStarted);
458
464
  t.add_full_wf_task();
459
465
  let act_scheduled_event_id = t.add_activity_task_scheduled(activity_id);
460
- let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
466
+ let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
461
467
  t.add_timer_fired(timer_started_event_id, "1".to_string());
462
468
  t.add_full_wf_task();
463
- let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
469
+ let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
464
470
  let act_started_event_id = t.add_activity_task_started(act_scheduled_event_id);
465
471
  t.add_activity_task_completed(
466
472
  act_scheduled_event_id,
@@ -476,7 +482,7 @@ async fn abandoned_activities_ignore_start_and_complete(hist_batches: &'static [
476
482
 
477
483
  worker.register_wf(wf_type.to_owned(), |ctx: WfContext| async move {
478
484
  let act_fut = ctx.activity(ActivityOptions {
479
- activity_type: "echo_activity".to_string(),
485
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
480
486
  start_to_close_timeout: Some(Duration::from_secs(5)),
481
487
  cancellation_type: ActivityCancellationType::Abandon,
482
488
  ..Default::default()
@@ -542,7 +548,7 @@ async fn verify_activity_cancellation(
542
548
  seq: activity_seq,
543
549
  activity_id: activity_seq.to_string(),
544
550
  cancellation_type: cancel_type as i32,
545
- ..Default::default()
551
+ ..default_act_sched()
546
552
  }
547
553
  .into()],
548
554
  ),
@@ -610,7 +616,7 @@ async fn verify_activity_cancellation_wait_for_cancellation(activity_id: u32, wo
610
616
  seq: activity_id,
611
617
  activity_id: activity_id.to_string(),
612
618
  cancellation_type: ActivityCancellationType::WaitCancellationCompleted as i32,
613
- ..Default::default()
619
+ ..default_act_sched()
614
620
  }
615
621
  .into()],
616
622
  ),
@@ -892,7 +898,7 @@ async fn max_wft_respected() {
892
898
  let total_wfs = 100;
893
899
  let wf_ids: Vec<_> = (0..total_wfs)
894
900
  .into_iter()
895
- .map(|i| format!("fake-wf-{}", i))
901
+ .map(|i| format!("fake-wf-{i}"))
896
902
  .collect();
897
903
  let hists = wf_ids.iter().map(|wf_id| {
898
904
  let hist = canned_histories::single_timer("1");
@@ -947,7 +953,7 @@ async fn activity_not_canceled_on_replay_repro(hist_batches: &'static [usize]) {
947
953
  seq: activity_id,
948
954
  activity_id: activity_id.to_string(),
949
955
  cancellation_type: ActivityCancellationType::TryCancel as i32,
950
- ..Default::default()
956
+ ..default_act_sched()
951
957
  }
952
958
  .into(),
953
959
  start_timer_cmd(1, Duration::from_secs(1)),
@@ -989,9 +995,9 @@ async fn activity_not_canceled_when_also_completed_repro(hist_batches: &'static
989
995
  &job_assert!(workflow_activation_job::Variant::StartWorkflow(_)),
990
996
  vec![ScheduleActivity {
991
997
  seq: activity_id,
992
- activity_id: activity_id.to_string(),
998
+ activity_id: "act-1".to_string(),
993
999
  cancellation_type: ActivityCancellationType::TryCancel as i32,
994
- ..Default::default()
1000
+ ..default_act_sched()
995
1001
  }
996
1002
  .into()],
997
1003
  ),
@@ -1022,7 +1028,7 @@ async fn activity_not_canceled_when_also_completed_repro(hist_batches: &'static
1022
1028
  async fn lots_of_workflows() {
1023
1029
  let total_wfs = 500;
1024
1030
  let hists = (0..total_wfs).into_iter().map(|i| {
1025
- let wf_id = format!("fake-wf-{}", i);
1031
+ let wf_id = format!("fake-wf-{i}");
1026
1032
  let hist = canned_histories::single_timer("1");
1027
1033
  FakeWfResponses {
1028
1034
  wf_id,
@@ -1092,7 +1098,7 @@ async fn wft_timeout_repro(hist_batches: &'static [usize]) {
1092
1098
  seq: activity_id,
1093
1099
  activity_id: activity_id.to_string(),
1094
1100
  cancellation_type: ActivityCancellationType::TryCancel as i32,
1095
- ..Default::default()
1101
+ ..default_act_sched()
1096
1102
  }
1097
1103
  .into()],
1098
1104
  ),
@@ -1225,14 +1231,13 @@ async fn buffered_work_drained_on_shutdown() {
1225
1231
  let resp_1 = hist_to_poll_resp(&t, wfid.to_owned(), 1.into()).resp;
1226
1232
  t.add_workflow_task_timed_out();
1227
1233
  t.add_full_wf_task();
1228
- let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
1229
- t.add(
1230
- EventType::TimerFired,
1231
- history_event::Attributes::TimerFiredEventAttributes(TimerFiredEventAttributes {
1234
+ let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
1235
+ t.add(history_event::Attributes::TimerFiredEventAttributes(
1236
+ TimerFiredEventAttributes {
1232
1237
  started_event_id: timer_started_event_id,
1233
1238
  timer_id: "1".to_string(),
1234
- }),
1235
- );
1239
+ },
1240
+ ));
1236
1241
  t.add_full_wf_task();
1237
1242
  t.add_workflow_execution_completed();
1238
1243
 
@@ -1264,6 +1269,8 @@ async fn buffered_work_drained_on_shutdown() {
1264
1269
  .unwrap();
1265
1270
  };
1266
1271
  let complete_first = async move {
1272
+ // If the first complete is sent too fast, we may not have had a chance to buffer work.
1273
+ tokio::time::sleep(Duration::from_millis(50)).await;
1267
1274
  core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
1268
1275
  act1.run_id,
1269
1276
  start_timer_cmd(1, Duration::from_secs(1)),
@@ -1272,8 +1279,6 @@ async fn buffered_work_drained_on_shutdown() {
1272
1279
  .unwrap();
1273
1280
  };
1274
1281
  join!(poll_fut, complete_first, async {
1275
- // If the shutdown is sent too too fast, we might not have got a chance to even buffer work
1276
- tokio::time::sleep(Duration::from_millis(5)).await;
1277
1282
  core.shutdown().await;
1278
1283
  });
1279
1284
  }
@@ -1303,7 +1308,7 @@ async fn fail_wft_then_recover() {
1303
1308
  act.run_id.clone(),
1304
1309
  vec![ScheduleActivity {
1305
1310
  activity_id: "fake_activity".to_string(),
1306
- ..Default::default()
1311
+ ..default_act_sched()
1307
1312
  }
1308
1313
  .into()],
1309
1314
  ))
@@ -1355,12 +1360,17 @@ async fn poll_response_triggers_wf_error() {
1355
1360
  t.add_full_wf_task();
1356
1361
  t.add_workflow_execution_completed();
1357
1362
 
1358
- let mh = MockPollCfg::from_resp_batches(
1363
+ let mut mh = MockPollCfg::from_resp_batches(
1359
1364
  "fake_wf_id",
1360
1365
  t,
1361
1366
  [ResponseType::AllHistory],
1362
1367
  mock_workflow_client(),
1363
1368
  );
1369
+ // Fail wft will be called when auto-failing.
1370
+ mh.num_expected_fails = 1;
1371
+ mh.expect_fail_wft_matcher = Box::new(move |_, cause, _| {
1372
+ matches!(cause, WorkflowTaskFailedCause::NonDeterministicError)
1373
+ });
1364
1374
  let mock = build_mock_pollers(mh);
1365
1375
  let core = mock_worker(mock);
1366
1376
  // Poll for first WFT, which is immediately an eviction
@@ -1453,7 +1463,7 @@ async fn tries_cancel_of_completed_activity() {
1453
1463
  ScheduleActivity {
1454
1464
  seq: 1,
1455
1465
  activity_id: "1".to_string(),
1456
- ..Default::default()
1466
+ ..default_act_sched()
1457
1467
  }
1458
1468
  .into(),
1459
1469
  ))
@@ -1546,9 +1556,8 @@ async fn failing_wft_doesnt_eat_permit_forever() {
1546
1556
  ))
1547
1557
  .await
1548
1558
  .unwrap();
1549
- assert_eq!(worker.available_wft_permits().await, 2);
1550
-
1551
1559
  worker.shutdown().await;
1560
+ assert_eq!(worker.available_wft_permits().await, 2);
1552
1561
  }
1553
1562
 
1554
1563
  #[tokio::test]
@@ -1574,6 +1583,8 @@ async fn cache_miss_will_fetch_history() {
1574
1583
  let mut mock = build_mock_pollers(mh);
1575
1584
  mock.worker_cfg(|cfg| {
1576
1585
  cfg.max_cached_workflows = 1;
1586
+ // Also verifies tying the WFT permit to the fetch request doesn't get us stuck
1587
+ cfg.max_outstanding_workflow_tasks = 1;
1577
1588
  });
1578
1589
  let worker = mock_worker(mock);
1579
1590
 
@@ -1655,6 +1666,7 @@ async fn tasks_from_completion_are_delivered() {
1655
1666
  let complete_resp = RespondWorkflowTaskCompletedResponse {
1656
1667
  workflow_task: Some(hist_to_poll_resp(&t, wfid.to_owned(), 2.into()).resp),
1657
1668
  activity_tasks: vec![],
1669
+ reset_history_event_id: 0,
1658
1670
  };
1659
1671
  mock.expect_complete_workflow_task()
1660
1672
  .times(1)
@@ -1686,12 +1698,63 @@ async fn tasks_from_completion_are_delivered() {
1686
1698
  core.shutdown().await;
1687
1699
  }
1688
1700
 
1701
+ #[tokio::test]
1702
+ async fn pagination_works_with_tasks_from_completion() {
1703
+ let wfid = "fake_wf_id";
1704
+ let mut t = TestHistoryBuilder::default();
1705
+ t.add_by_type(EventType::WorkflowExecutionStarted);
1706
+ t.add_full_wf_task();
1707
+ t.add_we_signaled("sig", vec![]);
1708
+ t.add_full_wf_task();
1709
+ t.add_workflow_execution_completed();
1710
+ let get_exec_resp: GetWorkflowExecutionHistoryResponse = t.get_history_info(2).unwrap().into();
1711
+
1712
+ let mut mock = mock_workflow_client();
1713
+ let mut needs_pag_resp = hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::OneTask(2)).resp;
1714
+ needs_pag_resp.next_page_token = vec![1];
1715
+ let complete_resp = RespondWorkflowTaskCompletedResponse {
1716
+ workflow_task: Some(needs_pag_resp),
1717
+ ..Default::default()
1718
+ };
1719
+ mock.expect_complete_workflow_task()
1720
+ .times(1)
1721
+ .returning(move |_| Ok(complete_resp.clone()));
1722
+ mock.expect_complete_workflow_task()
1723
+ .times(1)
1724
+ .returning(|_| Ok(Default::default()));
1725
+ mock.expect_get_workflow_execution_history()
1726
+ .returning(move |_, _, _| Ok(get_exec_resp.clone()))
1727
+ .times(1);
1728
+ let mut mock = single_hist_mock_sg(wfid, t, [1], mock, true);
1729
+ mock.worker_cfg(|wc| wc.max_cached_workflows = 2);
1730
+ let core = mock_worker(mock);
1731
+
1732
+ let wf_task = core.poll_workflow_activation().await.unwrap();
1733
+ core.complete_workflow_activation(WorkflowActivationCompletion::empty(wf_task.run_id))
1734
+ .await
1735
+ .unwrap();
1736
+ let wf_task = core.poll_workflow_activation().await.unwrap();
1737
+ assert_matches!(
1738
+ wf_task.jobs.as_slice(),
1739
+ [WorkflowActivationJob {
1740
+ variant: Some(workflow_activation_job::Variant::SignalWorkflow(_)),
1741
+ },]
1742
+ );
1743
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
1744
+ wf_task.run_id,
1745
+ vec![CompleteWorkflowExecution { result: None }.into()],
1746
+ ))
1747
+ .await
1748
+ .unwrap();
1749
+ core.shutdown().await;
1750
+ }
1751
+
1689
1752
  #[tokio::test]
1690
1753
  async fn poll_faster_than_complete_wont_overflow_cache() {
1691
1754
  // Make workflow tasks for 5 different runs
1692
1755
  let tasks: Vec<_> = (1..=5)
1693
1756
  .map(|i| FakeWfResponses {
1694
- wf_id: format!("wf-{}", i),
1757
+ wf_id: format!("wf-{i}"),
1695
1758
  hist: canned_histories::single_timer("1"),
1696
1759
  response_batches: vec![ResponseType::ToTaskNum(1)],
1697
1760
  })
@@ -1900,7 +1963,7 @@ async fn autocompletes_wft_no_work() {
1900
1963
  seq: 1,
1901
1964
  activity_id: activity_id.to_string(),
1902
1965
  cancellation_type: ActivityCancellationType::Abandon as i32,
1903
- ..Default::default()
1966
+ ..default_act_sched()
1904
1967
  }
1905
1968
  .into(),
1906
1969
  ))
@@ -2013,10 +2076,7 @@ async fn continue_as_new_preserves_some_values() {
2013
2076
  let mut mock_client = mock_workflow_client();
2014
2077
  let hist = {
2015
2078
  let mut t = TestHistoryBuilder::default();
2016
- t.add(
2017
- EventType::WorkflowExecutionStarted,
2018
- wes_attrs.clone().into(),
2019
- );
2079
+ t.add(wes_attrs.clone());
2020
2080
  t.add_full_wf_task();
2021
2081
  t
2022
2082
  };
@@ -2060,21 +2120,19 @@ async fn continue_as_new_preserves_some_values() {
2060
2120
  async fn ignorable_events_are_ok(#[values(true, false)] attribs_unset: bool) {
2061
2121
  let mut t = TestHistoryBuilder::default();
2062
2122
  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;
2123
+ let id = t.add(WorkflowPropertiesModifiedExternallyEventAttributes::default());
2124
+ t.modify_event(id, |e| {
2125
+ e.worker_may_ignore = true;
2126
+ // Ignorable events are ignored if we can't interpret the proto of either the event attribs
2127
+ // or proto - otherwise (this is the _may_ part of may ignore), we'll still try to process
2128
+ // it. That processing may ultimately still choose to do nothing, if we want to _explicitly_
2129
+ // ignore it.
2130
+ if attribs_unset {
2075
2131
  e.attributes = None;
2076
- });
2077
- }
2132
+ } else {
2133
+ e.event_type = EventType::Unspecified as i32;
2134
+ }
2135
+ });
2078
2136
  t.add_workflow_task_scheduled_and_started();
2079
2137
 
2080
2138
  let mock = mock_workflow_client();
@@ -2087,3 +2145,478 @@ async fn ignorable_events_are_ok(#[values(true, false)] attribs_unset: bool) {
2087
2145
  Some(workflow_activation_job::Variant::StartWorkflow(_))
2088
2146
  );
2089
2147
  }
2148
+
2149
+ #[tokio::test]
2150
+ async fn fetching_to_continue_replay_works() {
2151
+ let mut mock_client = mock_workflow_client();
2152
+ let mut t = TestHistoryBuilder::default();
2153
+ t.add_by_type(EventType::WorkflowExecutionStarted);
2154
+ t.add_full_wf_task();
2155
+ t.add_full_wf_task(); // ends 7
2156
+ let mut need_fetch_resp =
2157
+ hist_to_poll_resp(&t, "wfid".to_owned(), ResponseType::AllHistory).resp;
2158
+ need_fetch_resp.next_page_token = vec![1];
2159
+
2160
+ t.add_full_wf_task();
2161
+ t.add_we_signaled("hi", vec![]); // Need to make there be two complete WFTs
2162
+ t.add_full_wf_task(); // end 14
2163
+ let mut fetch_resp: GetWorkflowExecutionHistoryResponse =
2164
+ t.get_full_history_info().unwrap().into();
2165
+ // Should only contain events after 7
2166
+ if let Some(ref mut h) = fetch_resp.history {
2167
+ h.events.retain(|e| e.event_id >= 8);
2168
+ }
2169
+ // And indicate that even *more* needs to be fetched after this, so we see a request for the
2170
+ // next page happen.
2171
+ fetch_resp.next_page_token = vec![2];
2172
+
2173
+ let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
2174
+ t.add_timer_fired(timer_started_event_id, "1".to_string());
2175
+ t.add_full_wf_task();
2176
+ let mut final_fetch_resp: GetWorkflowExecutionHistoryResponse =
2177
+ t.get_full_history_info().unwrap().into();
2178
+ // Should have only the final event
2179
+ if let Some(ref mut h) = final_fetch_resp.history {
2180
+ h.events.retain(|e| e.event_id >= 15);
2181
+ }
2182
+
2183
+ let tasks = vec![
2184
+ ResponseType::ToTaskNum(1),
2185
+ ResponseType::Raw(need_fetch_resp),
2186
+ ];
2187
+ mock_client
2188
+ .expect_get_workflow_execution_history()
2189
+ .returning(move |_, _, _| Ok(fetch_resp.clone()))
2190
+ .times(1);
2191
+ mock_client
2192
+ .expect_get_workflow_execution_history()
2193
+ .returning(move |_, _, _| Ok(final_fetch_resp.clone()))
2194
+ .times(1);
2195
+ let mut mock = single_hist_mock_sg("wfid", t, tasks, mock_client, true);
2196
+ mock.worker_cfg(|wc| wc.max_cached_workflows = 10);
2197
+ let core = mock_worker(mock);
2198
+ let act = core.poll_workflow_activation().await.unwrap();
2199
+ assert_matches!(
2200
+ act.jobs[0].variant,
2201
+ Some(workflow_activation_job::Variant::StartWorkflow(_))
2202
+ );
2203
+ core.complete_workflow_activation(WorkflowActivationCompletion::empty(act.run_id))
2204
+ .await
2205
+ .unwrap();
2206
+ let act = core.poll_workflow_activation().await.unwrap();
2207
+ assert_matches!(
2208
+ act.jobs.as_slice(),
2209
+ [WorkflowActivationJob {
2210
+ variant: Some(workflow_activation_job::Variant::SignalWorkflow(_)),
2211
+ }]
2212
+ );
2213
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
2214
+ act.run_id,
2215
+ start_timer_cmd(1, Duration::from_secs(1)),
2216
+ ))
2217
+ .await
2218
+ .unwrap();
2219
+ let act = core.poll_workflow_activation().await.unwrap();
2220
+ assert_matches!(
2221
+ act.jobs.as_slice(),
2222
+ [WorkflowActivationJob {
2223
+ variant: Some(workflow_activation_job::Variant::FireTimer(_)),
2224
+ }]
2225
+ );
2226
+ }
2227
+
2228
+ #[tokio::test]
2229
+ async fn fetching_error_evicts_wf() {
2230
+ let mut mock_client = mock_workflow_client();
2231
+ let mut t = TestHistoryBuilder::default();
2232
+ t.add_by_type(EventType::WorkflowExecutionStarted);
2233
+ t.add_workflow_task_scheduled_and_started();
2234
+ t.add_workflow_task_completed();
2235
+ let mut need_fetch_resp =
2236
+ hist_to_poll_resp(&t, "wfid".to_owned(), ResponseType::AllHistory).resp;
2237
+ need_fetch_resp.next_page_token = vec![1];
2238
+ let tasks = vec![
2239
+ ResponseType::ToTaskNum(1),
2240
+ ResponseType::Raw(need_fetch_resp),
2241
+ ];
2242
+ mock_client
2243
+ .expect_get_workflow_execution_history()
2244
+ .returning(move |_, _, _| Err(tonic::Status::not_found("Ahh broken")))
2245
+ .times(1);
2246
+ let mut mock = single_hist_mock_sg("wfid", t, tasks, mock_client, true);
2247
+ mock.worker_cfg(|wc| wc.max_cached_workflows = 10);
2248
+ let core = mock_worker(mock);
2249
+ let act = core.poll_workflow_activation().await.unwrap();
2250
+ assert_matches!(
2251
+ act.jobs[0].variant,
2252
+ Some(workflow_activation_job::Variant::StartWorkflow(_))
2253
+ );
2254
+ core.complete_workflow_activation(WorkflowActivationCompletion::empty(act.run_id))
2255
+ .await
2256
+ .unwrap();
2257
+ let evict_act = core.poll_workflow_activation().await.unwrap();
2258
+ assert_matches!(
2259
+ evict_act.jobs.as_slice(),
2260
+ [WorkflowActivationJob {
2261
+ variant: Some(workflow_activation_job::Variant::RemoveFromCache(r)),
2262
+ }] => r.message.contains("Fetching history failed")
2263
+ );
2264
+ }
2265
+
2266
+ /// This test verifies that if we fail to fetch a page during a completion, that we don't get stuck
2267
+ /// in the complete waiting for the completion to finish.
2268
+ #[tokio::test]
2269
+ async fn ensure_fetching_fail_during_complete_sends_task_failure() {
2270
+ let wfid = "fake_wf_id";
2271
+ let mut t = TestHistoryBuilder::default();
2272
+ t.add_by_type(EventType::WorkflowExecutionStarted);
2273
+ t.add_full_wf_task(); // started 3
2274
+ t.add_we_signaled("sig1", vec![]);
2275
+ t.add_full_wf_task(); // started 7
2276
+ t.add_we_signaled("sig2", vec![]);
2277
+ t.add_full_wf_task(); // started 11
2278
+ t.add_workflow_execution_completed();
2279
+
2280
+ let mut first_poll = hist_to_poll_resp(&t, wfid, ResponseType::ToTaskNum(1)).resp;
2281
+ first_poll.next_page_token = vec![1];
2282
+ first_poll.previous_started_event_id = 3;
2283
+
2284
+ let mut next_page: GetWorkflowExecutionHistoryResponse = t.get_history_info(2).unwrap().into();
2285
+ next_page.next_page_token = vec![2];
2286
+
2287
+ let mut mock = mock_workflow_client();
2288
+ mock.expect_get_workflow_execution_history()
2289
+ .returning(move |_, _, _| {
2290
+ error!("Called fetch!");
2291
+ Ok(next_page.clone())
2292
+ })
2293
+ .times(1);
2294
+ let mut really_empty_fetch_resp: GetWorkflowExecutionHistoryResponse =
2295
+ t.get_history_info(1).unwrap().into();
2296
+ really_empty_fetch_resp.history = Some(Default::default());
2297
+ mock.expect_get_workflow_execution_history()
2298
+ .returning(move |_, _, _| {
2299
+ error!("Called fetch second time!");
2300
+ Ok(really_empty_fetch_resp.clone())
2301
+ })
2302
+ .times(1);
2303
+ mock.expect_fail_workflow_task()
2304
+ .returning(|_, _, _| Ok(Default::default()))
2305
+ .times(1);
2306
+
2307
+ let mut mock = single_hist_mock_sg(wfid, t, [ResponseType::Raw(first_poll)], mock, true);
2308
+ mock.make_wft_stream_interminable();
2309
+ mock.worker_cfg(|wc| wc.max_cached_workflows = 2);
2310
+ let core = mock_worker(mock);
2311
+
2312
+ let wf_task = core.poll_workflow_activation().await.unwrap();
2313
+ core.complete_workflow_activation(WorkflowActivationCompletion::empty(wf_task.run_id))
2314
+ .await
2315
+ .unwrap();
2316
+
2317
+ let wf_task = core.poll_workflow_activation().await.unwrap();
2318
+ assert_matches!(
2319
+ wf_task.jobs.as_slice(),
2320
+ [WorkflowActivationJob {
2321
+ variant: Some(workflow_activation_job::Variant::SignalWorkflow(_)),
2322
+ },]
2323
+ );
2324
+ core.complete_workflow_activation(WorkflowActivationCompletion::empty(wf_task.run_id))
2325
+ .await
2326
+ .unwrap();
2327
+
2328
+ // Expect to see eviction b/c of history fetching error here.
2329
+ let wf_task = core.poll_workflow_activation().await.unwrap();
2330
+ assert_matches!(
2331
+ wf_task.jobs.as_slice(),
2332
+ [WorkflowActivationJob {
2333
+ variant: Some(workflow_activation_job::Variant::RemoveFromCache(_)),
2334
+ },]
2335
+ );
2336
+
2337
+ core.shutdown().await;
2338
+ }
2339
+
2340
+ #[tokio::test]
2341
+ async fn lang_internal_flags() {
2342
+ let mut t = TestHistoryBuilder::default();
2343
+ t.add_by_type(EventType::WorkflowExecutionStarted);
2344
+ t.add_full_wf_task();
2345
+ t.set_flags_first_wft(&[], &[1]);
2346
+ t.add_we_signaled("sig1", vec![]);
2347
+ t.add_full_wf_task();
2348
+ t.set_flags_last_wft(&[], &[2]);
2349
+ t.add_we_signaled("sig2", vec![]);
2350
+ t.add_full_wf_task();
2351
+ t.add_workflow_execution_completed();
2352
+
2353
+ let mut mh = MockPollCfg::from_resp_batches(
2354
+ "fake_wf_id",
2355
+ t,
2356
+ [ResponseType::ToTaskNum(2), ResponseType::AllHistory],
2357
+ mock_workflow_client(),
2358
+ );
2359
+ mh.completion_asserts = Some(Box::new(|c| {
2360
+ assert_matches!(c.sdk_metadata.lang_used_flags.as_slice(), &[2]);
2361
+ }));
2362
+ let mut mock = build_mock_pollers(mh);
2363
+ mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
2364
+ let core = mock_worker(mock);
2365
+
2366
+ let act = core.poll_workflow_activation().await.unwrap();
2367
+ assert_matches!(act.available_internal_flags.as_slice(), [1]);
2368
+ core.complete_workflow_activation(WorkflowActivationCompletion::empty(act.run_id))
2369
+ .await
2370
+ .unwrap();
2371
+
2372
+ let act = core.poll_workflow_activation().await.unwrap();
2373
+ let mut completion = WorkflowActivationCompletion::empty(act.run_id);
2374
+ completion.add_internal_flags(2);
2375
+ core.complete_workflow_activation(completion).await.unwrap();
2376
+
2377
+ let act = core.poll_workflow_activation().await.unwrap();
2378
+ assert_matches!(act.available_internal_flags.as_slice(), [1, 2]);
2379
+ core.complete_execution(&act.run_id).await;
2380
+ core.shutdown().await;
2381
+ }
2382
+
2383
+ // Verify we send flags to server when they're used
2384
+ #[tokio::test]
2385
+ async fn core_internal_flags() {
2386
+ let mut t = TestHistoryBuilder::default();
2387
+ t.add_by_type(EventType::WorkflowExecutionStarted);
2388
+ t.add_full_wf_task();
2389
+ let act_scheduled_event_id = t.add_activity_task_scheduled("act-id");
2390
+ let act_started_event_id = t.add_activity_task_started(act_scheduled_event_id);
2391
+ t.add_activity_task_completed(
2392
+ act_scheduled_event_id,
2393
+ act_started_event_id,
2394
+ Default::default(),
2395
+ );
2396
+ t.add_full_wf_task();
2397
+ t.add_workflow_execution_completed();
2398
+
2399
+ let mut mh = MockPollCfg::from_resp_batches(
2400
+ "fake_wf_id",
2401
+ t,
2402
+ [ResponseType::ToTaskNum(1), ResponseType::ToTaskNum(2)],
2403
+ mock_workflow_client(),
2404
+ );
2405
+ let first_poll = AtomicBool::new(true);
2406
+ mh.completion_asserts = Some(Box::new(move |c| {
2407
+ if !first_poll.load(Ordering::Acquire) {
2408
+ assert_matches!(c.sdk_metadata.core_used_flags.as_slice(), &[1]);
2409
+ }
2410
+ first_poll.store(false, Ordering::Release);
2411
+ }));
2412
+ let mut mock = build_mock_pollers(mh);
2413
+ mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
2414
+ let core = mock_worker(mock);
2415
+
2416
+ let act = core.poll_workflow_activation().await.unwrap();
2417
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
2418
+ act.run_id,
2419
+ schedule_activity_cmd(
2420
+ 1,
2421
+ "whatever",
2422
+ "act-id",
2423
+ ActivityCancellationType::TryCancel,
2424
+ Duration::from_secs(60),
2425
+ Duration::from_secs(60),
2426
+ ),
2427
+ ))
2428
+ .await
2429
+ .unwrap();
2430
+
2431
+ let act = core.poll_workflow_activation().await.unwrap();
2432
+ core.complete_execution(&act.run_id).await;
2433
+ core.shutdown().await;
2434
+ }
2435
+
2436
+ #[tokio::test]
2437
+ async fn post_terminal_commands_are_discarded() {
2438
+ let mut t = TestHistoryBuilder::default();
2439
+ t.add_by_type(EventType::WorkflowExecutionStarted);
2440
+ t.add_full_wf_task();
2441
+ t.add_workflow_execution_completed();
2442
+
2443
+ let mut mh = MockPollCfg::from_resp_batches(
2444
+ "fake_wf_id",
2445
+ t,
2446
+ [ResponseType::ToTaskNum(1), ResponseType::AllHistory],
2447
+ mock_workflow_client(),
2448
+ );
2449
+ mh.completion_asserts = Some(Box::new(|c| {
2450
+ // Only the complete execution command should actually be sent
2451
+ assert_eq!(c.commands.len(), 1);
2452
+ }));
2453
+ let mut mock = build_mock_pollers(mh);
2454
+ mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
2455
+ let core = mock_worker(mock);
2456
+
2457
+ let act = core.poll_workflow_activation().await.unwrap();
2458
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
2459
+ act.run_id,
2460
+ vec![
2461
+ CompleteWorkflowExecution { result: None }.into(),
2462
+ start_timer_cmd(1, Duration::from_secs(1)),
2463
+ ],
2464
+ ))
2465
+ .await
2466
+ .unwrap();
2467
+
2468
+ // This just ensures applying the complete history w/ the completion command works, though
2469
+ // there's no activation.
2470
+ let act = core.poll_workflow_activation().await;
2471
+ assert_matches!(act.unwrap_err(), PollWfError::ShutDown);
2472
+
2473
+ core.shutdown().await;
2474
+ }
2475
+
2476
+ // Lang expects to always see jobs in this order:
2477
+ // patches, signals, everything else, queries
2478
+ #[tokio::test]
2479
+ async fn jobs_are_in_appropriate_order() {
2480
+ let p1 = "patchy-mc-patchface";
2481
+ let p2 = "enchi-the-kitty";
2482
+ let mut t = TestHistoryBuilder::default();
2483
+ t.add_by_type(EventType::WorkflowExecutionStarted);
2484
+ t.add_full_wf_task();
2485
+ t.add_has_change_marker(p1, false);
2486
+ let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
2487
+ t.add_timer_fired(timer_started_event_id, "1".to_string());
2488
+ t.add_we_signaled("yummy-salmon", vec![]);
2489
+ t.add_full_wf_task();
2490
+ t.add_has_change_marker(p2, false);
2491
+ t.add_workflow_execution_completed();
2492
+
2493
+ let mh = MockPollCfg::from_resp_batches(
2494
+ "fake_wf_id",
2495
+ t,
2496
+ [ResponseType::AllHistory],
2497
+ mock_workflow_client(),
2498
+ );
2499
+ let mut mock = build_mock_pollers(mh);
2500
+ mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
2501
+ let core = mock_worker(mock);
2502
+
2503
+ let act = core.poll_workflow_activation().await.unwrap();
2504
+ // Patch notifications always come first
2505
+ assert_matches!(
2506
+ act.jobs[0].variant.as_ref().unwrap(),
2507
+ workflow_activation_job::Variant::NotifyHasPatch(_)
2508
+ );
2509
+ assert_matches!(
2510
+ act.jobs[1].variant.as_ref().unwrap(),
2511
+ workflow_activation_job::Variant::StartWorkflow(_)
2512
+ );
2513
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
2514
+ act.run_id,
2515
+ vec![
2516
+ SetPatchMarker {
2517
+ patch_id: p1.to_string(),
2518
+ deprecated: false,
2519
+ }
2520
+ .into(),
2521
+ start_timer_cmd(1, Duration::from_secs(1)),
2522
+ ],
2523
+ ))
2524
+ .await
2525
+ .unwrap();
2526
+ let act = core.poll_workflow_activation().await.unwrap();
2527
+ assert_matches!(
2528
+ act.jobs[0].variant.as_ref().unwrap(),
2529
+ workflow_activation_job::Variant::NotifyHasPatch(_)
2530
+ );
2531
+ assert_matches!(
2532
+ act.jobs[1].variant.as_ref().unwrap(),
2533
+ workflow_activation_job::Variant::SignalWorkflow(_)
2534
+ );
2535
+ assert_matches!(
2536
+ act.jobs[2].variant.as_ref().unwrap(),
2537
+ workflow_activation_job::Variant::FireTimer(_)
2538
+ );
2539
+ }
2540
+
2541
+ #[rstest]
2542
+ #[tokio::test]
2543
+ async fn history_length_with_fail_and_timeout(
2544
+ #[values(true, false)] use_cache: bool,
2545
+ #[values(1, 2, 3)] history_responses_case: u8,
2546
+ ) {
2547
+ let wfid = "fake_wf_id";
2548
+ let mut t = TestHistoryBuilder::default();
2549
+ t.add_by_type(EventType::WorkflowExecutionStarted);
2550
+ t.add_full_wf_task();
2551
+ let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
2552
+ t.add_timer_fired(timer_started_event_id, "1".to_string());
2553
+ t.add_workflow_task_scheduled_and_started();
2554
+ t.add_workflow_task_failed_with_failure(WorkflowTaskFailedCause::Unspecified, "ahh".into());
2555
+ t.add_workflow_task_scheduled_and_started();
2556
+ t.add_workflow_task_timed_out();
2557
+ t.add_full_wf_task();
2558
+ let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
2559
+ t.add_timer_fired(timer_started_event_id, "2".to_string());
2560
+ t.add_full_wf_task();
2561
+ t.add_workflow_execution_completed();
2562
+
2563
+ let mut mock_client = mock_workflow_client();
2564
+ let history_responses = match history_responses_case {
2565
+ 1 => vec![ResponseType::AllHistory],
2566
+ 2 => vec![
2567
+ ResponseType::ToTaskNum(1),
2568
+ ResponseType::ToTaskNum(2),
2569
+ ResponseType::AllHistory,
2570
+ ],
2571
+ 3 => {
2572
+ let mut needs_fetch = hist_to_poll_resp(&t, wfid, ResponseType::ToTaskNum(2)).resp;
2573
+ needs_fetch.next_page_token = vec![1];
2574
+ // Truncate the history a bit in order to force incomplete WFT
2575
+ needs_fetch.history.as_mut().unwrap().events.truncate(6);
2576
+ let needs_fetch_resp = ResponseType::Raw(needs_fetch);
2577
+ let mut empty_fetch_resp: GetWorkflowExecutionHistoryResponse =
2578
+ t.get_history_info(1).unwrap().into();
2579
+ empty_fetch_resp.history.as_mut().unwrap().events = vec![];
2580
+ mock_client
2581
+ .expect_get_workflow_execution_history()
2582
+ .returning(move |_, _, _| Ok(empty_fetch_resp.clone()))
2583
+ .times(1);
2584
+ vec![
2585
+ ResponseType::ToTaskNum(1),
2586
+ needs_fetch_resp,
2587
+ ResponseType::ToTaskNum(2),
2588
+ ResponseType::AllHistory,
2589
+ ]
2590
+ }
2591
+ _ => unreachable!(),
2592
+ };
2593
+
2594
+ let mut mh = MockPollCfg::from_resp_batches(wfid, t, history_responses, mock_client);
2595
+ if history_responses_case == 3 {
2596
+ // Expect the failed pagination fetch
2597
+ mh.num_expected_fails = 1;
2598
+ }
2599
+ let mut worker = mock_sdk_cfg(mh, |wc| {
2600
+ if use_cache {
2601
+ wc.max_cached_workflows = 1;
2602
+ }
2603
+ });
2604
+ worker.register_wf(DEFAULT_WORKFLOW_TYPE, |ctx: WfContext| async move {
2605
+ assert_eq!(ctx.history_length(), 3);
2606
+ ctx.timer(Duration::from_secs(1)).await;
2607
+ assert_eq!(ctx.history_length(), 14);
2608
+ ctx.timer(Duration::from_secs(1)).await;
2609
+ assert_eq!(ctx.history_length(), 19);
2610
+ Ok(().into())
2611
+ });
2612
+ worker
2613
+ .submit_wf(
2614
+ wfid.to_owned(),
2615
+ DEFAULT_WORKFLOW_TYPE.to_owned(),
2616
+ vec![],
2617
+ WorkflowOptions::default(),
2618
+ )
2619
+ .await
2620
+ .unwrap();
2621
+ worker.run_until_done().await.unwrap();
2622
+ }