@temporalio/core-bridge 1.13.0 → 1.13.2

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 (181) hide show
  1. package/Cargo.lock +239 -382
  2. package/Cargo.toml +11 -11
  3. package/lib/native.d.ts +10 -3
  4. package/package.json +3 -3
  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/.cargo/config.toml +71 -11
  11. package/sdk-core/.clippy.toml +1 -0
  12. package/sdk-core/.github/workflows/heavy.yml +2 -0
  13. package/sdk-core/.github/workflows/per-pr.yml +50 -18
  14. package/sdk-core/ARCHITECTURE.md +44 -48
  15. package/sdk-core/Cargo.toml +26 -7
  16. package/sdk-core/README.md +4 -0
  17. package/sdk-core/arch_docs/diagrams/TimerMachine_Coverage.puml +14 -0
  18. package/sdk-core/arch_docs/diagrams/initial_event_history.png +0 -0
  19. package/sdk-core/arch_docs/sdks_intro.md +299 -0
  20. package/sdk-core/client/Cargo.toml +8 -7
  21. package/sdk-core/client/src/callback_based.rs +1 -2
  22. package/sdk-core/client/src/lib.rs +485 -299
  23. package/sdk-core/client/src/metrics.rs +32 -8
  24. package/sdk-core/client/src/proxy.rs +124 -5
  25. package/sdk-core/client/src/raw.rs +598 -307
  26. package/sdk-core/client/src/replaceable.rs +253 -0
  27. package/sdk-core/client/src/retry.rs +9 -6
  28. package/sdk-core/client/src/worker_registry/mod.rs +19 -3
  29. package/sdk-core/client/src/workflow_handle/mod.rs +20 -17
  30. package/sdk-core/core/Cargo.toml +100 -31
  31. package/sdk-core/core/src/core_tests/activity_tasks.rs +55 -225
  32. package/sdk-core/core/src/core_tests/mod.rs +2 -8
  33. package/sdk-core/core/src/core_tests/queries.rs +3 -5
  34. package/sdk-core/core/src/core_tests/replay_flag.rs +3 -62
  35. package/sdk-core/core/src/core_tests/updates.rs +4 -5
  36. package/sdk-core/core/src/core_tests/workers.rs +4 -3
  37. package/sdk-core/core/src/core_tests/workflow_cancels.rs +10 -7
  38. package/sdk-core/core/src/core_tests/workflow_tasks.rs +28 -291
  39. package/sdk-core/core/src/ephemeral_server/mod.rs +15 -3
  40. package/sdk-core/core/src/internal_flags.rs +11 -1
  41. package/sdk-core/core/src/lib.rs +50 -36
  42. package/sdk-core/core/src/pollers/mod.rs +5 -5
  43. package/sdk-core/core/src/pollers/poll_buffer.rs +2 -2
  44. package/sdk-core/core/src/protosext/mod.rs +13 -5
  45. package/sdk-core/core/src/protosext/protocol_messages.rs +4 -11
  46. package/sdk-core/core/src/retry_logic.rs +256 -108
  47. package/sdk-core/core/src/telemetry/metrics.rs +1 -0
  48. package/sdk-core/core/src/telemetry/mod.rs +8 -2
  49. package/sdk-core/core/src/telemetry/prometheus_meter.rs +2 -2
  50. package/sdk-core/core/src/test_help/integ_helpers.rs +971 -0
  51. package/sdk-core/core/src/test_help/mod.rs +10 -1100
  52. package/sdk-core/core/src/test_help/unit_helpers.rs +218 -0
  53. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +42 -6
  54. package/sdk-core/core/src/worker/activities/local_activities.rs +19 -19
  55. package/sdk-core/core/src/worker/activities.rs +10 -3
  56. package/sdk-core/core/src/worker/client/mocks.rs +3 -3
  57. package/sdk-core/core/src/worker/client.rs +130 -93
  58. package/sdk-core/core/src/worker/heartbeat.rs +12 -13
  59. package/sdk-core/core/src/worker/mod.rs +31 -21
  60. package/sdk-core/core/src/worker/nexus.rs +14 -3
  61. package/sdk-core/core/src/worker/slot_provider.rs +9 -0
  62. package/sdk-core/core/src/worker/tuner.rs +159 -0
  63. package/sdk-core/core/src/worker/workflow/history_update.rs +3 -265
  64. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +1 -54
  65. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +0 -82
  66. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +0 -67
  67. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +1 -192
  68. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +0 -43
  69. package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +6 -554
  70. package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +0 -71
  71. package/sdk-core/core/src/worker/workflow/machines/nexus_operation_state_machine.rs +102 -3
  72. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +10 -539
  73. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +0 -139
  74. package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +1 -119
  75. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +6 -63
  76. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +9 -4
  77. package/sdk-core/core/src/worker/workflow/mod.rs +5 -1
  78. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +8 -3
  79. package/sdk-core/core-api/Cargo.toml +4 -4
  80. package/sdk-core/core-api/src/envconfig.rs +153 -54
  81. package/sdk-core/core-api/src/lib.rs +68 -0
  82. package/sdk-core/core-api/src/telemetry/metrics.rs +2 -1
  83. package/sdk-core/core-api/src/telemetry.rs +13 -0
  84. package/sdk-core/core-c-bridge/Cargo.toml +13 -8
  85. package/sdk-core/core-c-bridge/include/temporal-sdk-core-c-bridge.h +184 -22
  86. package/sdk-core/core-c-bridge/src/client.rs +462 -184
  87. package/sdk-core/core-c-bridge/src/envconfig.rs +314 -0
  88. package/sdk-core/core-c-bridge/src/lib.rs +1 -0
  89. package/sdk-core/core-c-bridge/src/random.rs +4 -4
  90. package/sdk-core/core-c-bridge/src/runtime.rs +22 -23
  91. package/sdk-core/core-c-bridge/src/testing.rs +1 -4
  92. package/sdk-core/core-c-bridge/src/tests/context.rs +31 -31
  93. package/sdk-core/core-c-bridge/src/tests/mod.rs +32 -28
  94. package/sdk-core/core-c-bridge/src/tests/utils.rs +7 -7
  95. package/sdk-core/core-c-bridge/src/worker.rs +319 -66
  96. package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +6 -1
  97. package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.stderr +5 -5
  98. package/sdk-core/sdk/Cargo.toml +8 -2
  99. package/sdk-core/sdk/src/activity_context.rs +1 -1
  100. package/sdk-core/sdk/src/app_data.rs +1 -1
  101. package/sdk-core/sdk/src/interceptors.rs +1 -4
  102. package/sdk-core/sdk/src/lib.rs +1 -5
  103. package/sdk-core/sdk/src/workflow_context/options.rs +10 -1
  104. package/sdk-core/sdk/src/workflow_future.rs +1 -1
  105. package/sdk-core/sdk-core-protos/Cargo.toml +6 -6
  106. package/sdk-core/sdk-core-protos/build.rs +10 -23
  107. package/sdk-core/sdk-core-protos/protos/api_upstream/.github/workflows/create-release.yml +9 -1
  108. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv2.json +254 -5
  109. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv3.yaml +234 -5
  110. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/common/v1/message.proto +1 -1
  111. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/deployment/v1/message.proto +6 -0
  112. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/namespace/v1/message.proto +6 -2
  113. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +60 -2
  114. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +30 -6
  115. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +2 -0
  116. package/sdk-core/{test-utils → sdk-core-protos}/src/canned_histories.rs +5 -5
  117. package/sdk-core/sdk-core-protos/src/history_builder.rs +2 -2
  118. package/sdk-core/sdk-core-protos/src/lib.rs +25 -9
  119. package/sdk-core/sdk-core-protos/src/test_utils.rs +89 -0
  120. package/sdk-core/sdk-core-protos/src/utilities.rs +14 -5
  121. package/sdk-core/tests/c_bridge_smoke_test.c +10 -0
  122. package/sdk-core/tests/cloud_tests.rs +10 -8
  123. package/sdk-core/tests/common/http_proxy.rs +134 -0
  124. package/sdk-core/{test-utils/src/lib.rs → tests/common/mod.rs} +214 -281
  125. package/sdk-core/{test-utils/src → tests/common}/workflows.rs +4 -3
  126. package/sdk-core/tests/fuzzy_workflow.rs +1 -1
  127. package/sdk-core/tests/global_metric_tests.rs +8 -7
  128. package/sdk-core/tests/heavy_tests.rs +7 -3
  129. package/sdk-core/tests/integ_tests/client_tests.rs +111 -24
  130. package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +14 -9
  131. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +4 -4
  132. package/sdk-core/tests/integ_tests/metrics_tests.rs +114 -14
  133. package/sdk-core/tests/integ_tests/pagination_tests.rs +273 -0
  134. package/sdk-core/tests/integ_tests/polling_tests.rs +311 -93
  135. package/sdk-core/tests/integ_tests/queries_tests.rs +4 -4
  136. package/sdk-core/tests/integ_tests/update_tests.rs +13 -7
  137. package/sdk-core/tests/integ_tests/visibility_tests.rs +26 -9
  138. package/sdk-core/tests/integ_tests/worker_tests.rs +668 -13
  139. package/sdk-core/tests/integ_tests/worker_versioning_tests.rs +40 -24
  140. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +244 -11
  141. package/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +1 -1
  142. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +78 -2
  143. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +61 -2
  144. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +465 -7
  145. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +41 -2
  146. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +315 -3
  147. package/sdk-core/tests/integ_tests/workflow_tests/eager.rs +1 -1
  148. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +1990 -14
  149. package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +65 -2
  150. package/sdk-core/tests/integ_tests/workflow_tests/nexus.rs +123 -23
  151. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +525 -3
  152. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +65 -16
  153. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +32 -23
  154. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +126 -5
  155. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +1 -2
  156. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +124 -8
  157. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +62 -2
  158. package/sdk-core/tests/integ_tests/workflow_tests.rs +67 -8
  159. package/sdk-core/tests/main.rs +26 -17
  160. package/sdk-core/tests/manual_tests.rs +5 -1
  161. package/sdk-core/tests/runner.rs +22 -40
  162. package/sdk-core/tests/shared_tests/mod.rs +1 -1
  163. package/sdk-core/tests/shared_tests/priority.rs +1 -1
  164. package/sdk-core/{core/benches/workflow_replay.rs → tests/workflow_replay_bench.rs} +10 -5
  165. package/src/client.rs +97 -20
  166. package/src/helpers/callbacks.rs +4 -4
  167. package/src/helpers/errors.rs +7 -1
  168. package/src/helpers/handles.rs +1 -0
  169. package/src/helpers/try_from_js.rs +4 -3
  170. package/src/lib.rs +3 -2
  171. package/src/metrics.rs +3 -0
  172. package/src/runtime.rs +5 -2
  173. package/src/worker.rs +9 -12
  174. package/ts/native.ts +13 -3
  175. package/sdk-core/arch_docs/diagrams/workflow_internals.svg +0 -1
  176. package/sdk-core/core/src/core_tests/child_workflows.rs +0 -281
  177. package/sdk-core/core/src/core_tests/determinism.rs +0 -318
  178. package/sdk-core/core/src/core_tests/local_activities.rs +0 -1442
  179. package/sdk-core/test-utils/Cargo.toml +0 -38
  180. package/sdk-core/test-utils/src/histfetch.rs +0 -28
  181. package/sdk-core/test-utils/src/interceptors.rs +0 -46
@@ -38,6 +38,7 @@ use std::{
38
38
  convert::TryFrom,
39
39
  };
40
40
  use temporal_sdk_core_protos::{
41
+ VERSION_SEARCH_ATTR_KEY,
41
42
  constants::PATCH_MARKER_NAME,
42
43
  coresdk::{AsJsonPayloadExt, common::build_has_change_marker_details},
43
44
  temporal::api::{
@@ -45,12 +46,10 @@ use temporal_sdk_core_protos::{
45
46
  RecordMarkerCommandAttributes, UpsertWorkflowSearchAttributesCommandAttributes,
46
47
  },
47
48
  common::v1::SearchAttributes,
48
- enums::v1::CommandType,
49
+ enums::v1::{CommandType, IndexedValueType},
49
50
  },
50
51
  };
51
52
 
52
- pub(crate) const VERSION_SEARCH_ATTR_KEY: &str = "TemporalChangeVersion";
53
-
54
53
  fsm! {
55
54
  pub(super) name PatchMachine;
56
55
  command PatchCommand;
@@ -128,7 +127,7 @@ pub(super) fn has_change<'a>(
128
127
  // Produce an upsert SA command for this patch.
129
128
  let mut all_ids = BTreeSet::from_iter(existing_patch_ids);
130
129
  all_ids.insert(machine.shared_state.patch_id.as_str());
131
- let serialized = all_ids
130
+ let mut serialized = all_ids
132
131
  .as_json_payload()
133
132
  .context("Could not serialize search attribute value for patch machine")
134
133
  .map_err(|e| WFMachinesError::Fatal(e.to_string()))?;
@@ -142,6 +141,13 @@ pub(super) fn has_change<'a>(
142
141
  );
143
142
  vec![]
144
143
  } else {
144
+ serialized.metadata.insert(
145
+ "type".to_string(),
146
+ IndexedValueType::KeywordList
147
+ .as_str_name()
148
+ .as_bytes()
149
+ .to_vec(),
150
+ );
145
151
  let indexed_fields = {
146
152
  let mut m = HashMap::new();
147
153
  m.insert(VERSION_SEARCH_ATTR_KEY.to_string(), serialized);
@@ -264,538 +270,3 @@ impl PatchMachine {
264
270
  self.shared_state.patch_id == id
265
271
  }
266
272
  }
267
-
268
- #[cfg(test)]
269
- mod tests {
270
- use crate::{
271
- internal_flags::CoreInternalFlags,
272
- replay::TestHistoryBuilder,
273
- test_help::{MockPollCfg, ResponseType, build_fake_sdk},
274
- worker::workflow::machines::patch_state_machine::VERSION_SEARCH_ATTR_KEY,
275
- };
276
- use rstest::rstest;
277
- use std::{
278
- collections::{HashSet, VecDeque, hash_map::RandomState},
279
- time::Duration,
280
- };
281
- use temporal_sdk::{ActivityOptions, WfContext};
282
- use temporal_sdk_core_protos::{
283
- DEFAULT_WORKFLOW_TYPE,
284
- constants::PATCH_MARKER_NAME,
285
- coresdk::{
286
- AsJsonPayloadExt, FromJsonPayloadExt,
287
- common::decode_change_marker_details,
288
- workflow_activation::{NotifyHasPatch, WorkflowActivationJob, workflow_activation_job},
289
- },
290
- temporal::api::{
291
- command::v1::{
292
- RecordMarkerCommandAttributes, ScheduleActivityTaskCommandAttributes,
293
- UpsertWorkflowSearchAttributesCommandAttributes, command::Attributes,
294
- },
295
- common::v1::ActivityType,
296
- enums::v1::{CommandType, EventType},
297
- history::v1::{
298
- ActivityTaskCompletedEventAttributes, ActivityTaskScheduledEventAttributes,
299
- ActivityTaskStartedEventAttributes, TimerFiredEventAttributes,
300
- },
301
- },
302
- };
303
- use temporal_sdk_core_test_utils::interceptors::ActivationAssertionsInterceptor;
304
-
305
- const MY_PATCH_ID: &str = "test_patch_id";
306
- #[derive(Eq, PartialEq, Copy, Clone, Debug)]
307
- enum MarkerType {
308
- Deprecated,
309
- NotDeprecated,
310
- NoMarker,
311
- }
312
-
313
- const ONE_SECOND: Duration = Duration::from_secs(1);
314
-
315
- /// EVENT_TYPE_WORKFLOW_EXECUTION_STARTED
316
- /// EVENT_TYPE_WORKFLOW_TASK_SCHEDULED
317
- /// EVENT_TYPE_WORKFLOW_TASK_STARTED
318
- /// EVENT_TYPE_WORKFLOW_TASK_COMPLETED
319
- /// EVENT_TYPE_MARKER_RECORDED (depending on marker_type)
320
- /// EVENT_TYPE_ACTIVITY_TASK_SCHEDULED
321
- /// EVENT_TYPE_ACTIVITY_TASK_STARTED
322
- /// EVENT_TYPE_ACTIVITY_TASK_COMPLETED
323
- /// EVENT_TYPE_WORKFLOW_TASK_SCHEDULED
324
- /// EVENT_TYPE_WORKFLOW_TASK_STARTED
325
- /// EVENT_TYPE_WORKFLOW_TASK_COMPLETED
326
- /// EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED
327
- fn patch_marker_single_activity(
328
- marker_type: MarkerType,
329
- version: usize,
330
- replay: bool,
331
- ) -> TestHistoryBuilder {
332
- let mut t = TestHistoryBuilder::default();
333
- t.add_by_type(EventType::WorkflowExecutionStarted);
334
- t.add_full_wf_task();
335
- t.set_flags_first_wft(
336
- &[CoreInternalFlags::UpsertSearchAttributeOnPatch as u32],
337
- &[],
338
- );
339
- match marker_type {
340
- MarkerType::Deprecated => {
341
- t.add_has_change_marker(MY_PATCH_ID, true);
342
- t.add_upsert_search_attrs_for_patch(&[MY_PATCH_ID.to_string()]);
343
- }
344
- MarkerType::NotDeprecated => {
345
- t.add_has_change_marker(MY_PATCH_ID, false);
346
- t.add_upsert_search_attrs_for_patch(&[MY_PATCH_ID.to_string()]);
347
- }
348
- MarkerType::NoMarker => {}
349
- };
350
-
351
- let activity_id = if replay {
352
- match (marker_type, version) {
353
- (_, 1) => "no_change",
354
- (MarkerType::NotDeprecated, 2) => "had_change",
355
- (MarkerType::Deprecated, 2) => "had_change",
356
- (MarkerType::NoMarker, 2) => "no_change",
357
- (_, 3) => "had_change",
358
- (_, 4) => "had_change",
359
- v => panic!("Nonsense marker / version combo {v:?}"),
360
- }
361
- } else {
362
- // If the workflow isn't replaying (we're creating history here for a workflow which
363
- // wasn't replaying at the time of scheduling the activity, and has done that, and now
364
- // we're feeding back the history it would have produced) then it always has the change,
365
- // except in v1.
366
- if version > 1 {
367
- "had_change"
368
- } else {
369
- "no_change"
370
- }
371
- };
372
-
373
- let scheduled_event_id = t.add(ActivityTaskScheduledEventAttributes {
374
- activity_id: activity_id.to_string(),
375
- ..Default::default()
376
- });
377
- let started_event_id = t.add(ActivityTaskStartedEventAttributes {
378
- scheduled_event_id,
379
- ..Default::default()
380
- });
381
- t.add(ActivityTaskCompletedEventAttributes {
382
- scheduled_event_id,
383
- started_event_id,
384
- ..Default::default()
385
- });
386
- t.add_full_wf_task();
387
- t.add_workflow_execution_completed();
388
- t
389
- }
390
-
391
- async fn v1(ctx: &mut WfContext) {
392
- ctx.activity(ActivityOptions {
393
- activity_id: Some("no_change".to_owned()),
394
- ..Default::default()
395
- })
396
- .await;
397
- }
398
-
399
- async fn v2(ctx: &mut WfContext) -> bool {
400
- if ctx.patched(MY_PATCH_ID) {
401
- ctx.activity(ActivityOptions {
402
- activity_id: Some("had_change".to_owned()),
403
- ..Default::default()
404
- })
405
- .await;
406
- true
407
- } else {
408
- ctx.activity(ActivityOptions {
409
- activity_id: Some("no_change".to_owned()),
410
- ..Default::default()
411
- })
412
- .await;
413
- false
414
- }
415
- }
416
-
417
- async fn v3(ctx: &mut WfContext) {
418
- ctx.deprecate_patch(MY_PATCH_ID);
419
- ctx.activity(ActivityOptions {
420
- activity_id: Some("had_change".to_owned()),
421
- ..Default::default()
422
- })
423
- .await;
424
- }
425
-
426
- async fn v4(ctx: &mut WfContext) {
427
- ctx.activity(ActivityOptions {
428
- activity_id: Some("had_change".to_owned()),
429
- ..Default::default()
430
- })
431
- .await;
432
- }
433
-
434
- fn patch_setup(
435
- replaying: bool,
436
- marker_type: MarkerType,
437
- workflow_version: usize,
438
- ) -> MockPollCfg {
439
- let t = patch_marker_single_activity(marker_type, workflow_version, replaying);
440
- if replaying {
441
- MockPollCfg::from_resps(t, [ResponseType::AllHistory])
442
- } else {
443
- MockPollCfg::from_hist_builder(t)
444
- }
445
- }
446
-
447
- macro_rules! patch_wf {
448
- ($workflow_version:ident) => {
449
- move |mut ctx: WfContext| async move {
450
- match $workflow_version {
451
- 1 => {
452
- v1(&mut ctx).await;
453
- }
454
- 2 => {
455
- v2(&mut ctx).await;
456
- }
457
- 3 => {
458
- v3(&mut ctx).await;
459
- }
460
- 4 => {
461
- v4(&mut ctx).await;
462
- }
463
- _ => panic!("Invalid workflow version for test setup"),
464
- }
465
- Ok(().into())
466
- }
467
- };
468
- }
469
-
470
- #[rstest]
471
- #[case::v1_breaks_on_normal_marker(false, MarkerType::NotDeprecated, 1)]
472
- #[case::v1_accepts_dep_marker(false, MarkerType::Deprecated, 1)]
473
- #[case::v1_replay_breaks_on_normal_marker(true, MarkerType::NotDeprecated, 1)]
474
- #[case::v1_replay_accepts_dep_marker(true, MarkerType::Deprecated, 1)]
475
- #[case::v4_breaks_on_normal_marker(false, MarkerType::NotDeprecated, 4)]
476
- #[case::v4_accepts_dep_marker(false, MarkerType::Deprecated, 4)]
477
- #[case::v4_replay_breaks_on_normal_marker(true, MarkerType::NotDeprecated, 4)]
478
- #[case::v4_replay_accepts_dep_marker(true, MarkerType::Deprecated, 4)]
479
- #[tokio::test]
480
- async fn v1_and_v4_changes(
481
- #[case] replaying: bool,
482
- #[case] marker_type: MarkerType,
483
- #[case] wf_version: usize,
484
- ) {
485
- let mut mock_cfg = patch_setup(replaying, marker_type, wf_version);
486
-
487
- if marker_type != MarkerType::Deprecated {
488
- // should explode b/c non-dep marker is present
489
- mock_cfg.num_expected_fails = 1;
490
- }
491
-
492
- let mut aai = ActivationAssertionsInterceptor::default();
493
- aai.skip_one().then(move |a| {
494
- if marker_type == MarkerType::Deprecated {
495
- // Activity is resolved
496
- assert_matches!(
497
- a.jobs.as_slice(),
498
- [WorkflowActivationJob {
499
- variant: Some(workflow_activation_job::Variant::ResolveActivity(_))
500
- }]
501
- );
502
- }
503
- });
504
-
505
- if !replaying {
506
- mock_cfg.completion_asserts_from_expectations(|mut asserts| {
507
- asserts.then(|wft| {
508
- assert_eq!(wft.commands.len(), 1);
509
- assert_eq!(
510
- wft.commands[0].command_type,
511
- CommandType::ScheduleActivityTask as i32
512
- );
513
- });
514
- });
515
- }
516
-
517
- let mut worker = build_fake_sdk(mock_cfg);
518
- worker.set_worker_interceptor(aai);
519
- worker.register_wf(DEFAULT_WORKFLOW_TYPE, patch_wf!(wf_version));
520
- worker.run().await.unwrap();
521
- }
522
-
523
- // Note that the not-replaying and no-marker cases don't make sense and hence are absent
524
- #[rstest]
525
- #[case::v2_marker_new_path(false, MarkerType::NotDeprecated, 2)]
526
- #[case::v2_dep_marker_new_path(false, MarkerType::Deprecated, 2)]
527
- #[case::v2_replay_no_marker_old_path(true, MarkerType::NoMarker, 2)]
528
- #[case::v2_replay_marker_new_path(true, MarkerType::NotDeprecated, 2)]
529
- #[case::v2_replay_dep_marker_new_path(true, MarkerType::Deprecated, 2)]
530
- #[case::v3_marker_new_path(false, MarkerType::NotDeprecated, 3)]
531
- #[case::v3_dep_marker_new_path(false, MarkerType::Deprecated, 3)]
532
- #[case::v3_replay_no_marker_old_path(true, MarkerType::NoMarker, 3)]
533
- #[case::v3_replay_marker_new_path(true, MarkerType::NotDeprecated, 3)]
534
- #[case::v3_replay_dep_marker_new_path(true, MarkerType::Deprecated, 3)]
535
- #[tokio::test]
536
- async fn v2_and_v3_changes(
537
- #[case] replaying: bool,
538
- #[case] marker_type: MarkerType,
539
- #[case] wf_version: usize,
540
- ) {
541
- let mut mock_cfg = patch_setup(replaying, marker_type, wf_version);
542
-
543
- let mut aai = ActivationAssertionsInterceptor::default();
544
- aai.then(move |act| {
545
- // replaying cases should immediately get a resolve change activation when marker is
546
- // present
547
- if replaying && marker_type != MarkerType::NoMarker {
548
- assert_matches!(
549
- &act.jobs[1],
550
- WorkflowActivationJob {
551
- variant: Some(workflow_activation_job::Variant::NotifyHasPatch(
552
- NotifyHasPatch {
553
- patch_id,
554
- }
555
- ))
556
- } => patch_id == MY_PATCH_ID
557
- );
558
- } else {
559
- assert_eq!(act.jobs.len(), 1);
560
- }
561
- })
562
- .then(move |act| {
563
- assert_matches!(
564
- act.jobs.as_slice(),
565
- [WorkflowActivationJob {
566
- variant: Some(workflow_activation_job::Variant::ResolveActivity(_))
567
- }]
568
- );
569
- });
570
-
571
- if !replaying {
572
- mock_cfg.completion_asserts_from_expectations(|mut asserts| {
573
- asserts.then(move |wft| {
574
- let mut commands = VecDeque::from(wft.commands.clone());
575
- let expected_num_cmds = if marker_type == MarkerType::NoMarker {
576
- 2
577
- } else {
578
- 3
579
- };
580
- assert_eq!(commands.len(), expected_num_cmds);
581
- let dep_flag_expected = wf_version != 2;
582
- assert_matches!(
583
- commands.pop_front().unwrap().attributes.as_ref().unwrap(),
584
- Attributes::RecordMarkerCommandAttributes(
585
- RecordMarkerCommandAttributes { marker_name, details,.. })
586
- if marker_name == PATCH_MARKER_NAME
587
- && decode_change_marker_details(details).unwrap().1 == dep_flag_expected
588
- );
589
- if expected_num_cmds == 3 {
590
- assert_matches!(
591
- commands.pop_front().unwrap().attributes.as_ref().unwrap(),
592
- Attributes::UpsertWorkflowSearchAttributesCommandAttributes(
593
- UpsertWorkflowSearchAttributesCommandAttributes
594
- { search_attributes: Some(attrs) }
595
- )
596
- if attrs.indexed_fields.get(VERSION_SEARCH_ATTR_KEY).unwrap()
597
- == &[MY_PATCH_ID].as_json_payload().unwrap()
598
- );
599
- }
600
- // The only time the "old" timer should fire is in v2, replaying, without a marker.
601
- let expected_activity_id =
602
- if replaying && marker_type == MarkerType::NoMarker && wf_version == 2 {
603
- "no_change"
604
- } else {
605
- "had_change"
606
- };
607
- assert_matches!(
608
- commands.pop_front().unwrap().attributes.as_ref().unwrap(),
609
- Attributes::ScheduleActivityTaskCommandAttributes(
610
- ScheduleActivityTaskCommandAttributes { activity_id, .. }
611
- )
612
- if activity_id == expected_activity_id
613
- );
614
- });
615
- });
616
- }
617
-
618
- let mut worker = build_fake_sdk(mock_cfg);
619
- worker.set_worker_interceptor(aai);
620
- worker.register_wf(DEFAULT_WORKFLOW_TYPE, patch_wf!(wf_version));
621
- worker.run().await.unwrap();
622
- }
623
-
624
- #[rstest]
625
- #[case::has_change_replay(true, true)]
626
- #[case::no_change_replay(false, true)]
627
- #[case::has_change_inc(true, false)]
628
- // The false-false case doesn't make sense, as the incremental cases act as if working against
629
- // a sticky queue, and it'd be impossible for a worker with the call to get an incremental
630
- // history that then suddenly doesn't have the marker.
631
- #[tokio::test]
632
- async fn same_change_multiple_spots(#[case] have_marker_in_hist: bool, #[case] replay: bool) {
633
- let mut t = TestHistoryBuilder::default();
634
- t.add_by_type(EventType::WorkflowExecutionStarted);
635
- t.add_full_wf_task();
636
- t.set_flags_first_wft(
637
- &[CoreInternalFlags::UpsertSearchAttributeOnPatch as u32],
638
- &[],
639
- );
640
- if have_marker_in_hist {
641
- t.add_has_change_marker(MY_PATCH_ID, false);
642
- t.add_upsert_search_attrs_for_patch(&[MY_PATCH_ID.to_string()]);
643
- let scheduled_event_id = t.add(ActivityTaskScheduledEventAttributes {
644
- activity_id: "1".to_owned(),
645
- activity_type: Some(ActivityType {
646
- name: "".to_string(),
647
- }),
648
- ..Default::default()
649
- });
650
- let started_event_id = t.add(ActivityTaskStartedEventAttributes {
651
- scheduled_event_id,
652
- ..Default::default()
653
- });
654
- t.add(ActivityTaskCompletedEventAttributes {
655
- scheduled_event_id,
656
- started_event_id,
657
- ..Default::default()
658
- });
659
- t.add_full_wf_task();
660
- let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
661
- t.add(TimerFiredEventAttributes {
662
- started_event_id: timer_started_event_id,
663
- timer_id: "1".to_owned(),
664
- });
665
- } else {
666
- let started_event_id = t.add_by_type(EventType::TimerStarted);
667
- t.add(TimerFiredEventAttributes {
668
- started_event_id,
669
- timer_id: "1".to_owned(),
670
- });
671
- t.add_full_wf_task();
672
- let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
673
- t.add(TimerFiredEventAttributes {
674
- started_event_id: timer_started_event_id,
675
- timer_id: "2".to_owned(),
676
- });
677
- }
678
- t.add_full_wf_task();
679
-
680
- if have_marker_in_hist {
681
- let scheduled_event_id = t.add(ActivityTaskScheduledEventAttributes {
682
- activity_id: "2".to_string(),
683
- activity_type: Some(ActivityType {
684
- name: "".to_string(),
685
- }),
686
- ..Default::default()
687
- });
688
- let started_event_id = t.add(ActivityTaskStartedEventAttributes {
689
- scheduled_event_id,
690
- ..Default::default()
691
- });
692
- t.add(ActivityTaskCompletedEventAttributes {
693
- scheduled_event_id,
694
- started_event_id,
695
- ..Default::default()
696
- });
697
- } else {
698
- let started_event_id = t.add_by_type(EventType::TimerStarted);
699
- t.add(TimerFiredEventAttributes {
700
- started_event_id,
701
- timer_id: "3".to_owned(),
702
- });
703
- }
704
- t.add_full_wf_task();
705
- t.add_workflow_execution_completed();
706
-
707
- let mock_cfg = if replay {
708
- MockPollCfg::from_resps(t, [ResponseType::AllHistory])
709
- } else {
710
- MockPollCfg::from_hist_builder(t)
711
- };
712
-
713
- // Errors would appear as nondeterminism problems, so just run it.
714
- let mut worker = build_fake_sdk(mock_cfg);
715
- worker.register_wf(DEFAULT_WORKFLOW_TYPE, move |ctx: WfContext| async move {
716
- if ctx.patched(MY_PATCH_ID) {
717
- ctx.activity(ActivityOptions::default()).await;
718
- } else {
719
- ctx.timer(ONE_SECOND).await;
720
- }
721
- ctx.timer(ONE_SECOND).await;
722
- if ctx.patched(MY_PATCH_ID) {
723
- ctx.activity(ActivityOptions::default()).await;
724
- } else {
725
- ctx.timer(ONE_SECOND).await;
726
- }
727
- Ok(().into())
728
- });
729
- worker.run().await.unwrap();
730
- }
731
-
732
- const SIZE_OVERFLOW_PATCH_AMOUNT: usize = 180;
733
- #[rstest]
734
- #[case::happy_path(50)]
735
- // We start exceeding the 2k size limit at 180 patches with this format
736
- #[case::size_overflow(SIZE_OVERFLOW_PATCH_AMOUNT)]
737
- #[tokio::test]
738
- async fn many_patches_combine_in_search_attrib_update(#[case] num_patches: usize) {
739
- let mut t = TestHistoryBuilder::default();
740
- t.add_by_type(EventType::WorkflowExecutionStarted);
741
- t.add_full_wf_task();
742
- t.set_flags_first_wft(
743
- &[CoreInternalFlags::UpsertSearchAttributeOnPatch as u32],
744
- &[],
745
- );
746
- for i in 1..=num_patches {
747
- let id = format!("patch-{i}");
748
- t.add_has_change_marker(&id, false);
749
- if i < SIZE_OVERFLOW_PATCH_AMOUNT {
750
- t.add_upsert_search_attrs_for_patch(&[id]);
751
- }
752
- let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
753
- t.add(TimerFiredEventAttributes {
754
- started_event_id: timer_started_event_id,
755
- timer_id: i.to_string(),
756
- });
757
- t.add_full_wf_task();
758
- }
759
- t.add_workflow_execution_completed();
760
-
761
- let mut mock_cfg = MockPollCfg::from_hist_builder(t);
762
- mock_cfg.completion_asserts_from_expectations(|mut asserts| {
763
- // Iterate through all activations/responses except the final one with complete workflow
764
- for i in 2..=num_patches + 1 {
765
- asserts.then(move |wft| {
766
- let cmds = &wft.commands;
767
- if i > SIZE_OVERFLOW_PATCH_AMOUNT {
768
- assert_eq!(2, cmds.len());
769
- assert_matches!(cmds[1].command_type(), CommandType::StartTimer);
770
- } else {
771
- assert_eq!(3, cmds.len());
772
- let attrs = assert_matches!(
773
- cmds[1].attributes.as_ref().unwrap(),
774
- Attributes::UpsertWorkflowSearchAttributesCommandAttributes(
775
- UpsertWorkflowSearchAttributesCommandAttributes
776
- { search_attributes: Some(attrs) }
777
- ) => attrs
778
- );
779
- let expected_patches: HashSet<String, _> =
780
- (1..i).map(|i| format!("patch-{i}")).collect();
781
- let deserialized = HashSet::<String, RandomState>::from_json_payload(
782
- attrs.indexed_fields.get(VERSION_SEARCH_ATTR_KEY).unwrap(),
783
- )
784
- .unwrap();
785
- assert_eq!(deserialized, expected_patches);
786
- }
787
- });
788
- }
789
- });
790
-
791
- let mut worker = build_fake_sdk(mock_cfg);
792
- worker.register_wf(DEFAULT_WORKFLOW_TYPE, move |ctx: WfContext| async move {
793
- for i in 1..=num_patches {
794
- let _dontcare = ctx.patched(&format!("patch-{i}"));
795
- ctx.timer(ONE_SECOND).await;
796
- }
797
- Ok(().into())
798
- });
799
- worker.run().await.unwrap();
800
- }
801
- }