temporalio 0.0.2 → 0.1.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 (202) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +25 -23
  3. data/bridge/Cargo.lock +168 -59
  4. data/bridge/Cargo.toml +4 -2
  5. data/bridge/sdk-core/README.md +19 -6
  6. data/bridge/sdk-core/client/src/lib.rs +215 -39
  7. data/bridge/sdk-core/client/src/metrics.rs +17 -8
  8. data/bridge/sdk-core/client/src/raw.rs +4 -4
  9. data/bridge/sdk-core/client/src/retry.rs +32 -20
  10. data/bridge/sdk-core/core/Cargo.toml +22 -9
  11. data/bridge/sdk-core/core/src/abstractions.rs +203 -14
  12. data/bridge/sdk-core/core/src/core_tests/activity_tasks.rs +76 -41
  13. data/bridge/sdk-core/core/src/core_tests/determinism.rs +165 -2
  14. data/bridge/sdk-core/core/src/core_tests/local_activities.rs +204 -83
  15. data/bridge/sdk-core/core/src/core_tests/queries.rs +3 -4
  16. data/bridge/sdk-core/core/src/core_tests/workers.rs +1 -3
  17. data/bridge/sdk-core/core/src/core_tests/workflow_tasks.rs +397 -54
  18. data/bridge/sdk-core/core/src/ephemeral_server/mod.rs +106 -12
  19. data/bridge/sdk-core/core/src/internal_flags.rs +136 -0
  20. data/bridge/sdk-core/core/src/lib.rs +16 -9
  21. data/bridge/sdk-core/core/src/telemetry/log_export.rs +1 -1
  22. data/bridge/sdk-core/core/src/telemetry/metrics.rs +69 -35
  23. data/bridge/sdk-core/core/src/telemetry/mod.rs +29 -13
  24. data/bridge/sdk-core/core/src/telemetry/prometheus_server.rs +17 -12
  25. data/bridge/sdk-core/core/src/test_help/mod.rs +62 -12
  26. data/bridge/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +112 -156
  27. data/bridge/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
  28. data/bridge/sdk-core/core/src/worker/activities/local_activities.rs +352 -122
  29. data/bridge/sdk-core/core/src/worker/activities.rs +233 -157
  30. data/bridge/sdk-core/core/src/worker/client/mocks.rs +22 -2
  31. data/bridge/sdk-core/core/src/worker/client.rs +18 -2
  32. data/bridge/sdk-core/core/src/worker/mod.rs +165 -58
  33. data/bridge/sdk-core/core/src/worker/workflow/bridge.rs +1 -3
  34. data/bridge/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -5
  35. data/bridge/sdk-core/core/src/worker/workflow/history_update.rs +856 -277
  36. data/bridge/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +100 -43
  37. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +7 -7
  38. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +5 -4
  39. data/bridge/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +87 -27
  40. data/bridge/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +5 -4
  41. data/bridge/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +5 -4
  42. data/bridge/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +5 -4
  43. data/bridge/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +137 -62
  44. data/bridge/sdk-core/core/src/worker/workflow/machines/mod.rs +25 -17
  45. data/bridge/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +7 -6
  46. data/bridge/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +103 -152
  47. data/bridge/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +7 -7
  48. data/bridge/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +9 -9
  49. data/bridge/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +2 -2
  50. data/bridge/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +14 -7
  51. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +5 -16
  52. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +201 -121
  53. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +11 -14
  54. data/bridge/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +30 -15
  55. data/bridge/sdk-core/core/src/worker/workflow/managed_run.rs +1026 -376
  56. data/bridge/sdk-core/core/src/worker/workflow/mod.rs +460 -384
  57. data/bridge/sdk-core/core/src/worker/workflow/run_cache.rs +40 -57
  58. data/bridge/sdk-core/core/src/worker/workflow/wft_extraction.rs +125 -0
  59. data/bridge/sdk-core/core/src/worker/workflow/wft_poller.rs +1 -4
  60. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +117 -0
  61. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +24 -0
  62. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream.rs +448 -718
  63. data/bridge/sdk-core/core-api/Cargo.toml +2 -1
  64. data/bridge/sdk-core/core-api/src/errors.rs +1 -34
  65. data/bridge/sdk-core/core-api/src/lib.rs +6 -2
  66. data/bridge/sdk-core/core-api/src/telemetry.rs +0 -6
  67. data/bridge/sdk-core/core-api/src/worker.rs +14 -1
  68. data/bridge/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +18 -15
  69. data/bridge/sdk-core/fsm/rustfsm_trait/src/lib.rs +8 -3
  70. data/bridge/sdk-core/histories/evict_while_la_running_no_interference-16_history.bin +0 -0
  71. data/bridge/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +5 -17
  72. data/bridge/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +11 -0
  73. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +1 -6
  74. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +6 -6
  75. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +5 -0
  76. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +22 -6
  77. data/bridge/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +48 -19
  78. data/bridge/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +2 -0
  79. data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +3 -0
  80. data/bridge/sdk-core/protos/api_upstream/temporal/api/{enums/v1/interaction_type.proto → protocol/v1/message.proto} +29 -11
  81. data/bridge/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
  82. data/bridge/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +111 -0
  83. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +59 -28
  84. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +2 -2
  85. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +1 -0
  86. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +1 -0
  87. data/bridge/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +1 -0
  88. data/bridge/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
  89. data/bridge/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
  90. data/bridge/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +1 -0
  91. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +7 -0
  92. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +1 -0
  93. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +6 -0
  94. data/bridge/sdk-core/sdk/Cargo.toml +3 -2
  95. data/bridge/sdk-core/sdk/src/lib.rs +87 -20
  96. data/bridge/sdk-core/sdk/src/workflow_future.rs +9 -8
  97. data/bridge/sdk-core/sdk-core-protos/Cargo.toml +5 -2
  98. data/bridge/sdk-core/sdk-core-protos/build.rs +36 -1
  99. data/bridge/sdk-core/sdk-core-protos/src/history_builder.rs +100 -87
  100. data/bridge/sdk-core/sdk-core-protos/src/history_info.rs +5 -1
  101. data/bridge/sdk-core/sdk-core-protos/src/lib.rs +175 -57
  102. data/bridge/sdk-core/sdk-core-protos/src/task_token.rs +12 -2
  103. data/bridge/sdk-core/test-utils/Cargo.toml +3 -1
  104. data/bridge/sdk-core/test-utils/src/canned_histories.rs +106 -296
  105. data/bridge/sdk-core/test-utils/src/histfetch.rs +1 -1
  106. data/bridge/sdk-core/test-utils/src/lib.rs +82 -23
  107. data/bridge/sdk-core/test-utils/src/wf_input_saver.rs +50 -0
  108. data/bridge/sdk-core/test-utils/src/workflows.rs +29 -0
  109. data/bridge/sdk-core/tests/fuzzy_workflow.rs +130 -0
  110. data/bridge/sdk-core/tests/{load_tests.rs → heavy_tests.rs} +125 -51
  111. data/bridge/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
  112. data/bridge/sdk-core/tests/integ_tests/heartbeat_tests.rs +5 -3
  113. data/bridge/sdk-core/tests/integ_tests/metrics_tests.rs +218 -16
  114. data/bridge/sdk-core/tests/integ_tests/polling_tests.rs +4 -47
  115. data/bridge/sdk-core/tests/integ_tests/queries_tests.rs +5 -128
  116. data/bridge/sdk-core/tests/integ_tests/visibility_tests.rs +83 -25
  117. data/bridge/sdk-core/tests/integ_tests/workflow_tests/activities.rs +93 -69
  118. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
  119. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +6 -13
  120. data/bridge/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +1 -0
  121. data/bridge/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +6 -2
  122. data/bridge/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -10
  123. data/bridge/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +72 -191
  124. data/bridge/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +1 -0
  125. data/bridge/sdk-core/tests/integ_tests/workflow_tests/patches.rs +7 -28
  126. data/bridge/sdk-core/tests/integ_tests/workflow_tests/replay.rs +12 -7
  127. data/bridge/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
  128. data/bridge/sdk-core/tests/integ_tests/workflow_tests/signals.rs +18 -14
  129. data/bridge/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +6 -20
  130. data/bridge/sdk-core/tests/integ_tests/workflow_tests/timers.rs +10 -21
  131. data/bridge/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +6 -4
  132. data/bridge/sdk-core/tests/integ_tests/workflow_tests.rs +10 -11
  133. data/bridge/sdk-core/tests/main.rs +3 -13
  134. data/bridge/sdk-core/tests/runner.rs +75 -36
  135. data/bridge/sdk-core/tests/wf_input_replay.rs +32 -0
  136. data/bridge/src/connection.rs +41 -25
  137. data/bridge/src/lib.rs +269 -14
  138. data/bridge/src/runtime.rs +1 -1
  139. data/bridge/src/test_server.rs +153 -0
  140. data/bridge/src/worker.rs +89 -16
  141. data/lib/gen/temporal/api/command/v1/message_pb.rb +4 -18
  142. data/lib/gen/temporal/api/common/v1/message_pb.rb +4 -0
  143. data/lib/gen/temporal/api/enums/v1/command_type_pb.rb +1 -3
  144. data/lib/gen/temporal/api/enums/v1/event_type_pb.rb +3 -3
  145. data/lib/gen/temporal/api/enums/v1/failed_cause_pb.rb +2 -0
  146. data/lib/gen/temporal/api/enums/v1/update_pb.rb +6 -4
  147. data/lib/gen/temporal/api/history/v1/message_pb.rb +27 -19
  148. data/lib/gen/temporal/api/namespace/v1/message_pb.rb +1 -0
  149. data/lib/gen/temporal/api/operatorservice/v1/request_response_pb.rb +3 -0
  150. data/lib/gen/temporal/api/protocol/v1/message_pb.rb +30 -0
  151. data/lib/gen/temporal/api/sdk/v1/task_complete_metadata_pb.rb +23 -0
  152. data/lib/gen/temporal/api/testservice/v1/request_response_pb.rb +49 -0
  153. data/lib/gen/temporal/api/testservice/v1/service_pb.rb +21 -0
  154. data/lib/gen/temporal/api/update/v1/message_pb.rb +72 -0
  155. data/lib/gen/temporal/api/workflowservice/v1/request_response_pb.rb +26 -16
  156. data/lib/gen/temporal/sdk/core/activity_result/activity_result_pb.rb +13 -9
  157. data/lib/gen/temporal/sdk/core/activity_task/activity_task_pb.rb +10 -6
  158. data/lib/gen/temporal/sdk/core/child_workflow/child_workflow_pb.rb +13 -9
  159. data/lib/gen/temporal/sdk/core/common/common_pb.rb +7 -3
  160. data/lib/gen/temporal/sdk/core/core_interface_pb.rb +9 -3
  161. data/lib/gen/temporal/sdk/core/external_data/external_data_pb.rb +7 -3
  162. data/lib/gen/temporal/sdk/core/workflow_activation/workflow_activation_pb.rb +27 -21
  163. data/lib/gen/temporal/sdk/core/workflow_commands/workflow_commands_pb.rb +28 -24
  164. data/lib/gen/temporal/sdk/core/workflow_completion/workflow_completion_pb.rb +12 -5
  165. data/lib/temporalio/activity/context.rb +13 -8
  166. data/lib/temporalio/activity/info.rb +1 -1
  167. data/lib/temporalio/bridge/connect_options.rb +15 -0
  168. data/lib/temporalio/bridge/retry_config.rb +24 -0
  169. data/lib/temporalio/bridge/tls_options.rb +19 -0
  170. data/lib/temporalio/client/implementation.rb +8 -8
  171. data/lib/temporalio/connection/retry_config.rb +44 -0
  172. data/lib/temporalio/connection/service.rb +20 -0
  173. data/lib/temporalio/connection/test_service.rb +92 -0
  174. data/lib/temporalio/connection/tls_options.rb +51 -0
  175. data/lib/temporalio/connection/workflow_service.rb +731 -0
  176. data/lib/temporalio/connection.rb +55 -720
  177. data/lib/temporalio/interceptor/activity_inbound.rb +22 -0
  178. data/lib/temporalio/interceptor/activity_outbound.rb +24 -0
  179. data/lib/temporalio/interceptor/chain.rb +5 -5
  180. data/lib/temporalio/interceptor/client.rb +8 -4
  181. data/lib/temporalio/interceptor.rb +22 -0
  182. data/lib/temporalio/retry_policy.rb +13 -3
  183. data/lib/temporalio/testing/time_skipping_handle.rb +32 -0
  184. data/lib/temporalio/testing/time_skipping_interceptor.rb +23 -0
  185. data/lib/temporalio/testing/workflow_environment.rb +112 -0
  186. data/lib/temporalio/testing.rb +175 -0
  187. data/lib/temporalio/version.rb +1 -1
  188. data/lib/temporalio/worker/activity_runner.rb +26 -4
  189. data/lib/temporalio/worker/activity_worker.rb +44 -18
  190. data/lib/temporalio/worker/sync_worker.rb +47 -11
  191. data/lib/temporalio/worker.rb +27 -21
  192. data/lib/temporalio/workflow/async.rb +46 -0
  193. data/lib/temporalio/workflow/future.rb +138 -0
  194. data/lib/temporalio/workflow/info.rb +76 -0
  195. data/temporalio.gemspec +4 -3
  196. metadata +67 -17
  197. data/bridge/sdk-core/Cargo.lock +0 -2606
  198. data/bridge/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +0 -87
  199. data/lib/bridge.so +0 -0
  200. data/lib/gen/temporal/api/enums/v1/interaction_type_pb.rb +0 -25
  201. data/lib/gen/temporal/api/interaction/v1/message_pb.rb +0 -49
  202. data/lib/gen/temporal/sdk/core/bridge/bridge_pb.rb +0 -222
@@ -190,9 +190,7 @@ async fn complete_with_task_not_found_during_shutdown() {
190
190
  complete_order.borrow_mut().push(1);
191
191
  };
192
192
  tokio::join!(shutdown_fut, poll_fut, complete_fut);
193
- // Shutdown will currently complete first before the actual eviction reply since the
194
- // workflow task is marked complete as soon as we get not found back from the server.
195
- assert_eq!(&complete_order.into_inner(), &[1, 3, 2])
193
+ assert_eq!(&complete_order.into_inner(), &[1, 2, 3])
196
194
  }
197
195
 
198
196
  #[tokio::test]
@@ -16,7 +16,7 @@ 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,
@@ -37,20 +37,25 @@ use temporal_sdk_core_protos::{
37
37
  },
38
38
  workflow_completion::WorkflowActivationCompletion,
39
39
  },
40
- default_wes_attribs,
40
+ default_act_sched, default_wes_attribs,
41
41
  temporal::api::{
42
42
  command::v1::command::Attributes,
43
43
  common::v1::{Payload, RetryPolicy},
44
44
  enums::v1::{EventType, WorkflowTaskFailedCause},
45
45
  failure::v1::Failure,
46
- history::v1::{history_event, TimerFiredEventAttributes},
46
+ history::v1::{
47
+ history_event, TimerFiredEventAttributes,
48
+ WorkflowPropertiesModifiedExternallyEventAttributes,
49
+ },
47
50
  workflowservice::v1::{
48
51
  GetWorkflowExecutionHistoryResponse, RespondWorkflowTaskCompletedResponse,
49
52
  },
50
53
  },
51
- DEFAULT_WORKFLOW_TYPE,
54
+ DEFAULT_ACTIVITY_TYPE, DEFAULT_WORKFLOW_TYPE,
55
+ };
56
+ use temporal_sdk_core_test_utils::{
57
+ fanout_tasks, schedule_activity_cmd, start_timer_cmd, WorkerTestHelpers,
52
58
  };
53
- use temporal_sdk_core_test_utils::{fanout_tasks, start_timer_cmd};
54
59
  use tokio::{
55
60
  join,
56
61
  sync::{Barrier, Semaphore},
@@ -120,7 +125,7 @@ async fn single_activity_completion(worker: Worker) {
120
125
  &job_assert!(workflow_activation_job::Variant::StartWorkflow(_)),
121
126
  vec![ScheduleActivity {
122
127
  activity_id: "fake_activity".to_string(),
123
- ..Default::default()
128
+ ..default_act_sched()
124
129
  }
125
130
  .into()],
126
131
  ),
@@ -245,7 +250,7 @@ async fn scheduled_activity_cancellation_try_cancel(hist_batches: &'static [usiz
245
250
  seq: activity_seq,
246
251
  activity_id: activity_id.to_string(),
247
252
  cancellation_type: ActivityCancellationType::TryCancel as i32,
248
- ..Default::default()
253
+ ..default_act_sched()
249
254
  }
250
255
  .into()],
251
256
  ),
@@ -281,7 +286,7 @@ async fn scheduled_activity_timeout(hist_batches: &'static [usize]) {
281
286
  vec![ScheduleActivity {
282
287
  seq: activity_seq,
283
288
  activity_id: activity_id.to_string(),
284
- ..Default::default()
289
+ ..default_act_sched()
285
290
  }
286
291
  .into()],
287
292
  ),
@@ -334,7 +339,7 @@ async fn started_activity_timeout(hist_batches: &'static [usize]) {
334
339
  vec![ScheduleActivity {
335
340
  seq: activity_seq,
336
341
  activity_id: activity_seq.to_string(),
337
- ..Default::default()
342
+ ..default_act_sched()
338
343
  }
339
344
  .into()],
340
345
  ),
@@ -389,7 +394,7 @@ async fn cancelled_activity_timeout(hist_batches: &'static [usize]) {
389
394
  vec![ScheduleActivity {
390
395
  seq: activity_seq,
391
396
  activity_id: activity_id.to_string(),
392
- ..Default::default()
397
+ ..default_act_sched()
393
398
  }
394
399
  .into()],
395
400
  ),
@@ -457,10 +462,10 @@ async fn abandoned_activities_ignore_start_and_complete(hist_batches: &'static [
457
462
  t.add_by_type(EventType::WorkflowExecutionStarted);
458
463
  t.add_full_wf_task();
459
464
  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);
465
+ let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
461
466
  t.add_timer_fired(timer_started_event_id, "1".to_string());
462
467
  t.add_full_wf_task();
463
- let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
468
+ let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
464
469
  let act_started_event_id = t.add_activity_task_started(act_scheduled_event_id);
465
470
  t.add_activity_task_completed(
466
471
  act_scheduled_event_id,
@@ -476,7 +481,7 @@ async fn abandoned_activities_ignore_start_and_complete(hist_batches: &'static [
476
481
 
477
482
  worker.register_wf(wf_type.to_owned(), |ctx: WfContext| async move {
478
483
  let act_fut = ctx.activity(ActivityOptions {
479
- activity_type: "echo_activity".to_string(),
484
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
480
485
  start_to_close_timeout: Some(Duration::from_secs(5)),
481
486
  cancellation_type: ActivityCancellationType::Abandon,
482
487
  ..Default::default()
@@ -542,7 +547,7 @@ async fn verify_activity_cancellation(
542
547
  seq: activity_seq,
543
548
  activity_id: activity_seq.to_string(),
544
549
  cancellation_type: cancel_type as i32,
545
- ..Default::default()
550
+ ..default_act_sched()
546
551
  }
547
552
  .into()],
548
553
  ),
@@ -610,7 +615,7 @@ async fn verify_activity_cancellation_wait_for_cancellation(activity_id: u32, wo
610
615
  seq: activity_id,
611
616
  activity_id: activity_id.to_string(),
612
617
  cancellation_type: ActivityCancellationType::WaitCancellationCompleted as i32,
613
- ..Default::default()
618
+ ..default_act_sched()
614
619
  }
615
620
  .into()],
616
621
  ),
@@ -892,7 +897,7 @@ async fn max_wft_respected() {
892
897
  let total_wfs = 100;
893
898
  let wf_ids: Vec<_> = (0..total_wfs)
894
899
  .into_iter()
895
- .map(|i| format!("fake-wf-{}", i))
900
+ .map(|i| format!("fake-wf-{i}"))
896
901
  .collect();
897
902
  let hists = wf_ids.iter().map(|wf_id| {
898
903
  let hist = canned_histories::single_timer("1");
@@ -947,7 +952,7 @@ async fn activity_not_canceled_on_replay_repro(hist_batches: &'static [usize]) {
947
952
  seq: activity_id,
948
953
  activity_id: activity_id.to_string(),
949
954
  cancellation_type: ActivityCancellationType::TryCancel as i32,
950
- ..Default::default()
955
+ ..default_act_sched()
951
956
  }
952
957
  .into(),
953
958
  start_timer_cmd(1, Duration::from_secs(1)),
@@ -989,9 +994,9 @@ async fn activity_not_canceled_when_also_completed_repro(hist_batches: &'static
989
994
  &job_assert!(workflow_activation_job::Variant::StartWorkflow(_)),
990
995
  vec![ScheduleActivity {
991
996
  seq: activity_id,
992
- activity_id: activity_id.to_string(),
997
+ activity_id: "act-1".to_string(),
993
998
  cancellation_type: ActivityCancellationType::TryCancel as i32,
994
- ..Default::default()
999
+ ..default_act_sched()
995
1000
  }
996
1001
  .into()],
997
1002
  ),
@@ -1022,7 +1027,7 @@ async fn activity_not_canceled_when_also_completed_repro(hist_batches: &'static
1022
1027
  async fn lots_of_workflows() {
1023
1028
  let total_wfs = 500;
1024
1029
  let hists = (0..total_wfs).into_iter().map(|i| {
1025
- let wf_id = format!("fake-wf-{}", i);
1030
+ let wf_id = format!("fake-wf-{i}");
1026
1031
  let hist = canned_histories::single_timer("1");
1027
1032
  FakeWfResponses {
1028
1033
  wf_id,
@@ -1092,7 +1097,7 @@ async fn wft_timeout_repro(hist_batches: &'static [usize]) {
1092
1097
  seq: activity_id,
1093
1098
  activity_id: activity_id.to_string(),
1094
1099
  cancellation_type: ActivityCancellationType::TryCancel as i32,
1095
- ..Default::default()
1100
+ ..default_act_sched()
1096
1101
  }
1097
1102
  .into()],
1098
1103
  ),
@@ -1225,14 +1230,13 @@ async fn buffered_work_drained_on_shutdown() {
1225
1230
  let resp_1 = hist_to_poll_resp(&t, wfid.to_owned(), 1.into()).resp;
1226
1231
  t.add_workflow_task_timed_out();
1227
1232
  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 {
1233
+ let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
1234
+ t.add(history_event::Attributes::TimerFiredEventAttributes(
1235
+ TimerFiredEventAttributes {
1232
1236
  started_event_id: timer_started_event_id,
1233
1237
  timer_id: "1".to_string(),
1234
- }),
1235
- );
1238
+ },
1239
+ ));
1236
1240
  t.add_full_wf_task();
1237
1241
  t.add_workflow_execution_completed();
1238
1242
 
@@ -1264,6 +1268,8 @@ async fn buffered_work_drained_on_shutdown() {
1264
1268
  .unwrap();
1265
1269
  };
1266
1270
  let complete_first = async move {
1271
+ // If the first complete is sent too fast, we may not have had a chance to buffer work.
1272
+ tokio::time::sleep(Duration::from_millis(50)).await;
1267
1273
  core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
1268
1274
  act1.run_id,
1269
1275
  start_timer_cmd(1, Duration::from_secs(1)),
@@ -1272,8 +1278,6 @@ async fn buffered_work_drained_on_shutdown() {
1272
1278
  .unwrap();
1273
1279
  };
1274
1280
  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
1281
  core.shutdown().await;
1278
1282
  });
1279
1283
  }
@@ -1303,7 +1307,7 @@ async fn fail_wft_then_recover() {
1303
1307
  act.run_id.clone(),
1304
1308
  vec![ScheduleActivity {
1305
1309
  activity_id: "fake_activity".to_string(),
1306
- ..Default::default()
1310
+ ..default_act_sched()
1307
1311
  }
1308
1312
  .into()],
1309
1313
  ))
@@ -1355,12 +1359,17 @@ async fn poll_response_triggers_wf_error() {
1355
1359
  t.add_full_wf_task();
1356
1360
  t.add_workflow_execution_completed();
1357
1361
 
1358
- let mh = MockPollCfg::from_resp_batches(
1362
+ let mut mh = MockPollCfg::from_resp_batches(
1359
1363
  "fake_wf_id",
1360
1364
  t,
1361
1365
  [ResponseType::AllHistory],
1362
1366
  mock_workflow_client(),
1363
1367
  );
1368
+ // Fail wft will be called when auto-failing.
1369
+ mh.num_expected_fails = 1;
1370
+ mh.expect_fail_wft_matcher = Box::new(move |_, cause, _| {
1371
+ matches!(cause, WorkflowTaskFailedCause::NonDeterministicError)
1372
+ });
1364
1373
  let mock = build_mock_pollers(mh);
1365
1374
  let core = mock_worker(mock);
1366
1375
  // Poll for first WFT, which is immediately an eviction
@@ -1453,7 +1462,7 @@ async fn tries_cancel_of_completed_activity() {
1453
1462
  ScheduleActivity {
1454
1463
  seq: 1,
1455
1464
  activity_id: "1".to_string(),
1456
- ..Default::default()
1465
+ ..default_act_sched()
1457
1466
  }
1458
1467
  .into(),
1459
1468
  ))
@@ -1546,9 +1555,8 @@ async fn failing_wft_doesnt_eat_permit_forever() {
1546
1555
  ))
1547
1556
  .await
1548
1557
  .unwrap();
1549
- assert_eq!(worker.available_wft_permits().await, 2);
1550
-
1551
1558
  worker.shutdown().await;
1559
+ assert_eq!(worker.available_wft_permits().await, 2);
1552
1560
  }
1553
1561
 
1554
1562
  #[tokio::test]
@@ -1574,6 +1582,8 @@ async fn cache_miss_will_fetch_history() {
1574
1582
  let mut mock = build_mock_pollers(mh);
1575
1583
  mock.worker_cfg(|cfg| {
1576
1584
  cfg.max_cached_workflows = 1;
1585
+ // Also verifies tying the WFT permit to the fetch request doesn't get us stuck
1586
+ cfg.max_outstanding_workflow_tasks = 1;
1577
1587
  });
1578
1588
  let worker = mock_worker(mock);
1579
1589
 
@@ -1687,12 +1697,63 @@ async fn tasks_from_completion_are_delivered() {
1687
1697
  core.shutdown().await;
1688
1698
  }
1689
1699
 
1700
+ #[tokio::test]
1701
+ async fn pagination_works_with_tasks_from_completion() {
1702
+ let wfid = "fake_wf_id";
1703
+ let mut t = TestHistoryBuilder::default();
1704
+ t.add_by_type(EventType::WorkflowExecutionStarted);
1705
+ t.add_full_wf_task();
1706
+ t.add_we_signaled("sig", vec![]);
1707
+ t.add_full_wf_task();
1708
+ t.add_workflow_execution_completed();
1709
+ let get_exec_resp: GetWorkflowExecutionHistoryResponse = t.get_history_info(2).unwrap().into();
1710
+
1711
+ let mut mock = mock_workflow_client();
1712
+ let mut needs_pag_resp = hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::OneTask(2)).resp;
1713
+ needs_pag_resp.next_page_token = vec![1];
1714
+ let complete_resp = RespondWorkflowTaskCompletedResponse {
1715
+ workflow_task: Some(needs_pag_resp),
1716
+ ..Default::default()
1717
+ };
1718
+ mock.expect_complete_workflow_task()
1719
+ .times(1)
1720
+ .returning(move |_| Ok(complete_resp.clone()));
1721
+ mock.expect_complete_workflow_task()
1722
+ .times(1)
1723
+ .returning(|_| Ok(Default::default()));
1724
+ mock.expect_get_workflow_execution_history()
1725
+ .returning(move |_, _, _| Ok(get_exec_resp.clone()))
1726
+ .times(1);
1727
+ let mut mock = single_hist_mock_sg(wfid, t, [1], mock, true);
1728
+ mock.worker_cfg(|wc| wc.max_cached_workflows = 2);
1729
+ let core = mock_worker(mock);
1730
+
1731
+ let wf_task = core.poll_workflow_activation().await.unwrap();
1732
+ core.complete_workflow_activation(WorkflowActivationCompletion::empty(wf_task.run_id))
1733
+ .await
1734
+ .unwrap();
1735
+ let wf_task = core.poll_workflow_activation().await.unwrap();
1736
+ assert_matches!(
1737
+ wf_task.jobs.as_slice(),
1738
+ [WorkflowActivationJob {
1739
+ variant: Some(workflow_activation_job::Variant::SignalWorkflow(_)),
1740
+ },]
1741
+ );
1742
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
1743
+ wf_task.run_id,
1744
+ vec![CompleteWorkflowExecution { result: None }.into()],
1745
+ ))
1746
+ .await
1747
+ .unwrap();
1748
+ core.shutdown().await;
1749
+ }
1750
+
1690
1751
  #[tokio::test]
1691
1752
  async fn poll_faster_than_complete_wont_overflow_cache() {
1692
1753
  // Make workflow tasks for 5 different runs
1693
1754
  let tasks: Vec<_> = (1..=5)
1694
1755
  .map(|i| FakeWfResponses {
1695
- wf_id: format!("wf-{}", i),
1756
+ wf_id: format!("wf-{i}"),
1696
1757
  hist: canned_histories::single_timer("1"),
1697
1758
  response_batches: vec![ResponseType::ToTaskNum(1)],
1698
1759
  })
@@ -1901,7 +1962,7 @@ async fn autocompletes_wft_no_work() {
1901
1962
  seq: 1,
1902
1963
  activity_id: activity_id.to_string(),
1903
1964
  cancellation_type: ActivityCancellationType::Abandon as i32,
1904
- ..Default::default()
1965
+ ..default_act_sched()
1905
1966
  }
1906
1967
  .into(),
1907
1968
  ))
@@ -2014,10 +2075,7 @@ async fn continue_as_new_preserves_some_values() {
2014
2075
  let mut mock_client = mock_workflow_client();
2015
2076
  let hist = {
2016
2077
  let mut t = TestHistoryBuilder::default();
2017
- t.add(
2018
- EventType::WorkflowExecutionStarted,
2019
- wes_attrs.clone().into(),
2020
- );
2078
+ t.add(wes_attrs.clone());
2021
2079
  t.add_full_wf_task();
2022
2080
  t
2023
2081
  };
@@ -2061,21 +2119,19 @@ async fn continue_as_new_preserves_some_values() {
2061
2119
  async fn ignorable_events_are_ok(#[values(true, false)] attribs_unset: bool) {
2062
2120
  let mut t = TestHistoryBuilder::default();
2063
2121
  t.add_by_type(EventType::WorkflowExecutionStarted);
2064
- let id = t.add_get_event_id(
2065
- EventType::Unspecified,
2066
- Some(
2067
- history_event::Attributes::WorkflowPropertiesModifiedExternallyEventAttributes(
2068
- Default::default(),
2069
- ),
2070
- ),
2071
- );
2072
- t.modify_event(id, |e| e.worker_may_ignore = true);
2073
- if attribs_unset {
2074
- t.modify_event(id, |e| {
2075
- e.event_type = EventType::WorkflowPropertiesModifiedExternally as i32;
2122
+ let id = t.add(WorkflowPropertiesModifiedExternallyEventAttributes::default());
2123
+ t.modify_event(id, |e| {
2124
+ e.worker_may_ignore = true;
2125
+ // Ignorable events are ignored if we can't interpret the proto of either the event attribs
2126
+ // or proto - otherwise (this is the _may_ part of may ignore), we'll still try to process
2127
+ // it. That processing may ultimately still choose to do nothing, if we want to _explicitly_
2128
+ // ignore it.
2129
+ if attribs_unset {
2076
2130
  e.attributes = None;
2077
- });
2078
- }
2131
+ } else {
2132
+ e.event_type = EventType::Unspecified as i32;
2133
+ }
2134
+ });
2079
2135
  t.add_workflow_task_scheduled_and_started();
2080
2136
 
2081
2137
  let mock = mock_workflow_client();
@@ -2088,3 +2144,290 @@ async fn ignorable_events_are_ok(#[values(true, false)] attribs_unset: bool) {
2088
2144
  Some(workflow_activation_job::Variant::StartWorkflow(_))
2089
2145
  );
2090
2146
  }
2147
+
2148
+ #[tokio::test]
2149
+ async fn fetching_to_continue_replay_works() {
2150
+ let mut mock_client = mock_workflow_client();
2151
+ let mut t = TestHistoryBuilder::default();
2152
+ t.add_by_type(EventType::WorkflowExecutionStarted);
2153
+ t.add_full_wf_task();
2154
+ t.add_full_wf_task(); // ends 7
2155
+ let mut need_fetch_resp =
2156
+ hist_to_poll_resp(&t, "wfid".to_owned(), ResponseType::AllHistory).resp;
2157
+ need_fetch_resp.next_page_token = vec![1];
2158
+
2159
+ t.add_full_wf_task();
2160
+ t.add_we_signaled("hi", vec![]); // Need to make there be two complete WFTs
2161
+ t.add_full_wf_task(); // end 14
2162
+ let mut fetch_resp: GetWorkflowExecutionHistoryResponse =
2163
+ t.get_full_history_info().unwrap().into();
2164
+ // Should only contain events after 7
2165
+ if let Some(ref mut h) = fetch_resp.history {
2166
+ h.events.retain(|e| e.event_id >= 8);
2167
+ }
2168
+ // And indicate that even *more* needs to be fetched after this, so we see a request for the
2169
+ // next page happen.
2170
+ fetch_resp.next_page_token = vec![2];
2171
+
2172
+ let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
2173
+ t.add_timer_fired(timer_started_event_id, "1".to_string());
2174
+ t.add_full_wf_task();
2175
+ let mut final_fetch_resp: GetWorkflowExecutionHistoryResponse =
2176
+ t.get_full_history_info().unwrap().into();
2177
+ // Should have only the final event
2178
+ if let Some(ref mut h) = final_fetch_resp.history {
2179
+ h.events.retain(|e| e.event_id >= 15);
2180
+ }
2181
+
2182
+ let tasks = vec![
2183
+ ResponseType::ToTaskNum(1),
2184
+ ResponseType::Raw(need_fetch_resp),
2185
+ ];
2186
+ mock_client
2187
+ .expect_get_workflow_execution_history()
2188
+ .returning(move |_, _, _| Ok(fetch_resp.clone()))
2189
+ .times(1);
2190
+ mock_client
2191
+ .expect_get_workflow_execution_history()
2192
+ .returning(move |_, _, _| Ok(final_fetch_resp.clone()))
2193
+ .times(1);
2194
+ let mut mock = single_hist_mock_sg("wfid", t, tasks, mock_client, true);
2195
+ mock.worker_cfg(|wc| wc.max_cached_workflows = 10);
2196
+ let core = mock_worker(mock);
2197
+ let act = core.poll_workflow_activation().await.unwrap();
2198
+ assert_matches!(
2199
+ act.jobs[0].variant,
2200
+ Some(workflow_activation_job::Variant::StartWorkflow(_))
2201
+ );
2202
+ core.complete_workflow_activation(WorkflowActivationCompletion::empty(act.run_id))
2203
+ .await
2204
+ .unwrap();
2205
+ let act = core.poll_workflow_activation().await.unwrap();
2206
+ assert_matches!(
2207
+ act.jobs.as_slice(),
2208
+ [WorkflowActivationJob {
2209
+ variant: Some(workflow_activation_job::Variant::SignalWorkflow(_)),
2210
+ }]
2211
+ );
2212
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
2213
+ act.run_id,
2214
+ start_timer_cmd(1, Duration::from_secs(1)),
2215
+ ))
2216
+ .await
2217
+ .unwrap();
2218
+ let act = core.poll_workflow_activation().await.unwrap();
2219
+ assert_matches!(
2220
+ act.jobs.as_slice(),
2221
+ [WorkflowActivationJob {
2222
+ variant: Some(workflow_activation_job::Variant::FireTimer(_)),
2223
+ }]
2224
+ );
2225
+ }
2226
+
2227
+ #[tokio::test]
2228
+ async fn fetching_error_evicts_wf() {
2229
+ let mut mock_client = mock_workflow_client();
2230
+ let mut t = TestHistoryBuilder::default();
2231
+ t.add_by_type(EventType::WorkflowExecutionStarted);
2232
+ t.add_workflow_task_scheduled_and_started();
2233
+ t.add_workflow_task_completed();
2234
+ let mut need_fetch_resp =
2235
+ hist_to_poll_resp(&t, "wfid".to_owned(), ResponseType::AllHistory).resp;
2236
+ need_fetch_resp.next_page_token = vec![1];
2237
+ let tasks = vec![
2238
+ ResponseType::ToTaskNum(1),
2239
+ ResponseType::Raw(need_fetch_resp),
2240
+ ];
2241
+ mock_client
2242
+ .expect_get_workflow_execution_history()
2243
+ .returning(move |_, _, _| Err(tonic::Status::not_found("Ahh broken")))
2244
+ .times(1);
2245
+ let mut mock = single_hist_mock_sg("wfid", t, tasks, mock_client, true);
2246
+ mock.worker_cfg(|wc| wc.max_cached_workflows = 10);
2247
+ let core = mock_worker(mock);
2248
+ let act = core.poll_workflow_activation().await.unwrap();
2249
+ assert_matches!(
2250
+ act.jobs[0].variant,
2251
+ Some(workflow_activation_job::Variant::StartWorkflow(_))
2252
+ );
2253
+ core.complete_workflow_activation(WorkflowActivationCompletion::empty(act.run_id))
2254
+ .await
2255
+ .unwrap();
2256
+ let evict_act = core.poll_workflow_activation().await.unwrap();
2257
+ assert_matches!(
2258
+ evict_act.jobs.as_slice(),
2259
+ [WorkflowActivationJob {
2260
+ variant: Some(workflow_activation_job::Variant::RemoveFromCache(r)),
2261
+ }] => r.message.contains("Fetching history failed")
2262
+ );
2263
+ }
2264
+
2265
+ /// This test verifies that if we fail to fetch a page during a completion, that we don't get stuck
2266
+ /// in the complete waiting for the completion to finish.
2267
+ #[tokio::test]
2268
+ async fn ensure_fetching_fail_during_complete_sends_task_failure() {
2269
+ let wfid = "fake_wf_id";
2270
+ let mut t = TestHistoryBuilder::default();
2271
+ t.add_by_type(EventType::WorkflowExecutionStarted);
2272
+ t.add_full_wf_task(); // started 3
2273
+ t.add_we_signaled("sig1", vec![]);
2274
+ t.add_full_wf_task(); // started 7
2275
+ t.add_we_signaled("sig2", vec![]);
2276
+ t.add_full_wf_task(); // started 11
2277
+ t.add_workflow_execution_completed();
2278
+
2279
+ let mut first_poll = hist_to_poll_resp(&t, wfid, ResponseType::ToTaskNum(1)).resp;
2280
+ first_poll.next_page_token = vec![1];
2281
+ first_poll.previous_started_event_id = 3;
2282
+
2283
+ let mut next_page: GetWorkflowExecutionHistoryResponse = t.get_history_info(2).unwrap().into();
2284
+ next_page.next_page_token = vec![2];
2285
+
2286
+ let mut mock = mock_workflow_client();
2287
+ mock.expect_get_workflow_execution_history()
2288
+ .returning(move |_, _, _| {
2289
+ error!("Called fetch!");
2290
+ Ok(next_page.clone())
2291
+ })
2292
+ .times(1);
2293
+ let mut really_empty_fetch_resp: GetWorkflowExecutionHistoryResponse =
2294
+ t.get_history_info(1).unwrap().into();
2295
+ really_empty_fetch_resp.history = Some(Default::default());
2296
+ mock.expect_get_workflow_execution_history()
2297
+ .returning(move |_, _, _| {
2298
+ error!("Called fetch second time!");
2299
+ Ok(really_empty_fetch_resp.clone())
2300
+ })
2301
+ .times(1);
2302
+ mock.expect_fail_workflow_task()
2303
+ .returning(|_, _, _| Ok(Default::default()))
2304
+ .times(1);
2305
+
2306
+ let mut mock = single_hist_mock_sg(wfid, t, [ResponseType::Raw(first_poll)], mock, true);
2307
+ mock.make_wft_stream_interminable();
2308
+ mock.worker_cfg(|wc| wc.max_cached_workflows = 2);
2309
+ let core = mock_worker(mock);
2310
+
2311
+ let wf_task = core.poll_workflow_activation().await.unwrap();
2312
+ core.complete_workflow_activation(WorkflowActivationCompletion::empty(wf_task.run_id))
2313
+ .await
2314
+ .unwrap();
2315
+
2316
+ let wf_task = core.poll_workflow_activation().await.unwrap();
2317
+ assert_matches!(
2318
+ wf_task.jobs.as_slice(),
2319
+ [WorkflowActivationJob {
2320
+ variant: Some(workflow_activation_job::Variant::SignalWorkflow(_)),
2321
+ },]
2322
+ );
2323
+ core.complete_workflow_activation(WorkflowActivationCompletion::empty(wf_task.run_id))
2324
+ .await
2325
+ .unwrap();
2326
+
2327
+ // Expect to see eviction b/c of history fetching error here.
2328
+ let wf_task = core.poll_workflow_activation().await.unwrap();
2329
+ assert_matches!(
2330
+ wf_task.jobs.as_slice(),
2331
+ [WorkflowActivationJob {
2332
+ variant: Some(workflow_activation_job::Variant::RemoveFromCache(_)),
2333
+ },]
2334
+ );
2335
+
2336
+ core.shutdown().await;
2337
+ }
2338
+
2339
+ #[tokio::test]
2340
+ async fn lang_internal_flags() {
2341
+ let mut t = TestHistoryBuilder::default();
2342
+ t.add_by_type(EventType::WorkflowExecutionStarted);
2343
+ t.add_full_wf_task();
2344
+ t.set_flags_first_wft(&[], &[1]);
2345
+ t.add_we_signaled("sig1", vec![]);
2346
+ t.add_full_wf_task();
2347
+ t.set_flags_last_wft(&[], &[2]);
2348
+ t.add_we_signaled("sig2", vec![]);
2349
+ t.add_full_wf_task();
2350
+ t.add_workflow_execution_completed();
2351
+
2352
+ let mut mh = MockPollCfg::from_resp_batches(
2353
+ "fake_wf_id",
2354
+ t,
2355
+ [ResponseType::ToTaskNum(2), ResponseType::AllHistory],
2356
+ mock_workflow_client(),
2357
+ );
2358
+ mh.completion_asserts = Some(Box::new(|c| {
2359
+ assert_matches!(c.sdk_metadata.lang_used_flags.as_slice(), &[2]);
2360
+ }));
2361
+ let mut mock = build_mock_pollers(mh);
2362
+ mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
2363
+ let core = mock_worker(mock);
2364
+
2365
+ let act = core.poll_workflow_activation().await.unwrap();
2366
+ assert_matches!(act.available_internal_flags.as_slice(), [1]);
2367
+ core.complete_workflow_activation(WorkflowActivationCompletion::empty(act.run_id))
2368
+ .await
2369
+ .unwrap();
2370
+
2371
+ let act = core.poll_workflow_activation().await.unwrap();
2372
+ let mut completion = WorkflowActivationCompletion::empty(act.run_id);
2373
+ completion.add_internal_flags(2);
2374
+ core.complete_workflow_activation(completion).await.unwrap();
2375
+
2376
+ let act = core.poll_workflow_activation().await.unwrap();
2377
+ assert_matches!(act.available_internal_flags.as_slice(), [1, 2]);
2378
+ core.complete_execution(&act.run_id).await;
2379
+ core.shutdown().await;
2380
+ }
2381
+
2382
+ // Verify we send flags to server when they're used
2383
+ #[tokio::test]
2384
+ async fn core_internal_flags() {
2385
+ let mut t = TestHistoryBuilder::default();
2386
+ t.add_by_type(EventType::WorkflowExecutionStarted);
2387
+ t.add_full_wf_task();
2388
+ let act_scheduled_event_id = t.add_activity_task_scheduled("act-id");
2389
+ let act_started_event_id = t.add_activity_task_started(act_scheduled_event_id);
2390
+ t.add_activity_task_completed(
2391
+ act_scheduled_event_id,
2392
+ act_started_event_id,
2393
+ Default::default(),
2394
+ );
2395
+ t.add_full_wf_task();
2396
+ t.add_workflow_execution_completed();
2397
+
2398
+ let mut mh = MockPollCfg::from_resp_batches(
2399
+ "fake_wf_id",
2400
+ t,
2401
+ [ResponseType::ToTaskNum(1), ResponseType::ToTaskNum(2)],
2402
+ mock_workflow_client(),
2403
+ );
2404
+ let first_poll = AtomicBool::new(true);
2405
+ mh.completion_asserts = Some(Box::new(move |c| {
2406
+ if !first_poll.load(Ordering::Acquire) {
2407
+ assert_matches!(c.sdk_metadata.core_used_flags.as_slice(), &[1]);
2408
+ }
2409
+ first_poll.store(false, Ordering::Release);
2410
+ }));
2411
+ let mut mock = build_mock_pollers(mh);
2412
+ mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
2413
+ let core = mock_worker(mock);
2414
+
2415
+ let act = core.poll_workflow_activation().await.unwrap();
2416
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
2417
+ act.run_id,
2418
+ schedule_activity_cmd(
2419
+ 1,
2420
+ "whatever",
2421
+ "act-id",
2422
+ ActivityCancellationType::TryCancel,
2423
+ Duration::from_secs(60),
2424
+ Duration::from_secs(60),
2425
+ ),
2426
+ ))
2427
+ .await
2428
+ .unwrap();
2429
+
2430
+ let act = core.poll_workflow_activation().await.unwrap();
2431
+ core.complete_execution(&act.run_id).await;
2432
+ core.shutdown().await;
2433
+ }