@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
@@ -4,12 +4,11 @@ use crate::{
4
4
  job_assert,
5
5
  replay::TestHistoryBuilder,
6
6
  test_help::{
7
- FakeWfResponses, MockPollCfg, MocksHolder, ResponseType, WorkerExt,
7
+ FakeWfResponses, MockPollCfg, MocksHolder, ResponseType, WorkerExt, WorkerTestHelpers,
8
8
  WorkflowCachingPolicy::{self, AfterEveryReply, NonSticky},
9
- build_fake_worker, build_mock_pollers, build_multihist_mock_sg, canned_histories,
10
- gen_assert_and_fail, gen_assert_and_reply, hist_to_poll_resp, mock_sdk, mock_sdk_cfg,
11
- mock_worker, poll_and_reply, poll_and_reply_clears_outstanding_evicts, single_hist_mock_sg,
12
- test_worker_cfg,
9
+ build_fake_worker, build_mock_pollers, build_multihist_mock_sg, fanout_tasks,
10
+ gen_assert_and_fail, gen_assert_and_reply, hist_to_poll_resp, mock_worker, poll_and_reply,
11
+ poll_and_reply_clears_outstanding_evicts, single_hist_mock_sg, test_worker_cfg,
13
12
  },
14
13
  worker::{
15
14
  TunerBuilder,
@@ -28,18 +27,16 @@ use std::{
28
27
  },
29
28
  time::Duration,
30
29
  };
31
- use temporal_client::WorkflowOptions;
32
- use temporal_sdk::{ActivityOptions, CancellableFuture, TimerOptions, WfContext};
33
30
  use temporal_sdk_core_api::{
34
31
  Worker as WorkerTrait,
35
32
  errors::PollError,
36
33
  worker::{
37
34
  PollerBehavior, SlotMarkUsedContext, SlotReleaseContext, SlotReservationContext,
38
- SlotSupplier, SlotSupplierPermit, WorkerVersioningStrategy, WorkflowSlotKind,
35
+ SlotSupplier, SlotSupplierPermit, WorkflowSlotKind,
39
36
  },
40
37
  };
41
38
  use temporal_sdk_core_protos::{
42
- DEFAULT_ACTIVITY_TYPE, DEFAULT_WORKFLOW_TYPE,
39
+ canned_histories,
43
40
  coresdk::{
44
41
  activity_result::{self as ar, ActivityResolution, activity_resolution},
45
42
  common::VersioningIntent,
@@ -58,20 +55,19 @@ use temporal_sdk_core_protos::{
58
55
  default_act_sched, default_wes_attribs,
59
56
  temporal::api::{
60
57
  command::v1::command::Attributes,
61
- common::v1::{Payload, RetryPolicy, WorkerVersionStamp},
58
+ common::v1::{Payload, RetryPolicy},
62
59
  enums::v1::{CommandType, EventType, WorkflowTaskFailedCause},
63
60
  failure::v1::Failure,
64
61
  history::v1::{
65
62
  TimerFiredEventAttributes, WorkflowPropertiesModifiedExternallyEventAttributes,
66
63
  history_event,
67
64
  },
68
- sdk::v1::UserMetadata,
69
65
  workflowservice::v1::{
70
66
  GetWorkflowExecutionHistoryResponse, RespondWorkflowTaskCompletedResponse,
71
67
  },
72
68
  },
69
+ test_utils::start_timer_cmd,
73
70
  };
74
- use temporal_sdk_core_test_utils::{WorkerTestHelpers, fanout_tasks, start_timer_cmd};
75
71
  use tokio::{
76
72
  join,
77
73
  sync::{Barrier, Semaphore},
@@ -474,54 +470,6 @@ async fn started_activity_cancellation_abandon(hist_batches: &'static [usize]) {
474
470
  verify_activity_cancellation(&core, activity_id, ActivityCancellationType::Abandon).await;
475
471
  }
476
472
 
477
- #[rstest(hist_batches, case::incremental(&[1, 2, 3, 4]), case::replay(&[4]))]
478
- #[tokio::test]
479
- async fn abandoned_activities_ignore_start_and_complete(hist_batches: &'static [usize]) {
480
- let wfid = "fake_wf_id";
481
- let wf_type = DEFAULT_WORKFLOW_TYPE;
482
- let activity_id = "1";
483
-
484
- let mut t = TestHistoryBuilder::default();
485
- t.add_by_type(EventType::WorkflowExecutionStarted);
486
- t.add_full_wf_task();
487
- let act_scheduled_event_id = t.add_activity_task_scheduled(activity_id);
488
- let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
489
- t.add_timer_fired(timer_started_event_id, "1".to_string());
490
- t.add_full_wf_task();
491
- let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
492
- let act_started_event_id = t.add_activity_task_started(act_scheduled_event_id);
493
- t.add_activity_task_completed(
494
- act_scheduled_event_id,
495
- act_started_event_id,
496
- Default::default(),
497
- );
498
- t.add_full_wf_task();
499
- t.add_timer_fired(timer_started_event_id, "2".to_string());
500
- t.add_full_wf_task();
501
- t.add_workflow_execution_completed();
502
- let mock = mock_worker_client();
503
- let mut worker = mock_sdk(MockPollCfg::from_resp_batches(wfid, t, hist_batches, mock));
504
-
505
- worker.register_wf(wf_type.to_owned(), |ctx: WfContext| async move {
506
- let act_fut = ctx.activity(ActivityOptions {
507
- activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
508
- start_to_close_timeout: Some(Duration::from_secs(5)),
509
- cancellation_type: ActivityCancellationType::Abandon,
510
- ..Default::default()
511
- });
512
- ctx.timer(Duration::from_secs(1)).await;
513
- act_fut.cancel(&ctx);
514
- ctx.timer(Duration::from_secs(3)).await;
515
- act_fut.await;
516
- Ok(().into())
517
- });
518
- worker
519
- .submit_wf(wfid, wf_type, vec![], Default::default())
520
- .await
521
- .unwrap();
522
- worker.run_until_done().await.unwrap();
523
- }
524
-
525
473
  #[rstest(hist_batches, case::incremental(&[1, 3]), case::replay(&[3]))]
526
474
  #[tokio::test]
527
475
  async fn scheduled_activity_cancellation_try_cancel_task_canceled(hist_batches: &'static [usize]) {
@@ -924,43 +872,6 @@ async fn workflow_failures_only_reported_once() {
924
872
  .await;
925
873
  }
926
874
 
927
- #[tokio::test]
928
- async fn max_wft_respected() {
929
- let total_wfs = 100;
930
- let wf_ids: Vec<_> = (0..total_wfs).map(|i| format!("fake-wf-{i}")).collect();
931
- let hists = wf_ids.iter().map(|wf_id| {
932
- let hist = canned_histories::single_timer("1");
933
- FakeWfResponses {
934
- wf_id: wf_id.to_string(),
935
- hist,
936
- response_batches: vec![1.into(), 2.into()],
937
- }
938
- });
939
- let mh = MockPollCfg::new(hists.into_iter().collect(), true, 0);
940
- let mut worker = mock_sdk_cfg(mh, |cfg| {
941
- cfg.max_cached_workflows = total_wfs as usize;
942
- cfg.max_outstanding_workflow_tasks = Some(1);
943
- });
944
- let active_count: &'static _ = Box::leak(Box::new(Semaphore::new(1)));
945
- worker.register_wf(DEFAULT_WORKFLOW_TYPE, move |ctx: WfContext| async move {
946
- drop(
947
- active_count
948
- .try_acquire()
949
- .expect("No multiple concurrent workflow tasks!"),
950
- );
951
- ctx.timer(Duration::from_secs(1)).await;
952
- Ok(().into())
953
- });
954
-
955
- for wf_id in wf_ids {
956
- worker
957
- .submit_wf(wf_id, DEFAULT_WORKFLOW_TYPE, vec![], Default::default())
958
- .await
959
- .unwrap();
960
- }
961
- worker.run_until_done().await.unwrap();
962
- }
963
-
964
875
  #[rstest(hist_batches, case::incremental(&[1, 2]), case::replay(&[3]))]
965
876
  #[tokio::test]
966
877
  async fn activity_not_canceled_on_replay_repro(hist_batches: &'static [usize]) {
@@ -2058,6 +1969,7 @@ async fn no_race_acquiring_permits() {
2058
1969
  let task_barr: &'static Barrier = Box::leak(Box::new(Barrier::new(2)));
2059
1970
  mock_client
2060
1971
  .expect_poll_workflow_task()
1972
+ .times(2)
2061
1973
  .returning(move |_, _| {
2062
1974
  let t = canned_histories::single_timer("1");
2063
1975
  let poll_resp = hist_to_poll_resp(&t, wfid.to_owned(), 2.into()).resp;
@@ -2067,6 +1979,9 @@ async fn no_race_acquiring_permits() {
2067
1979
  }
2068
1980
  .boxed()
2069
1981
  });
1982
+ mock_client
1983
+ .expect_poll_workflow_task()
1984
+ .returning(move |_, _| async move { Ok(Default::default()) }.boxed());
2070
1985
  mock_client
2071
1986
  .expect_complete_workflow_task()
2072
1987
  .returning(|_| async move { Ok(Default::default()) }.boxed());
@@ -2075,6 +1990,7 @@ async fn no_race_acquiring_permits() {
2075
1990
  test_worker_cfg()
2076
1991
  .max_outstanding_workflow_tasks(2_usize)
2077
1992
  .max_cached_workflows(0_usize)
1993
+ .ignore_evicts_on_shutdown(false)
2078
1994
  .build()
2079
1995
  .unwrap(),
2080
1996
  mock_client,
@@ -2111,6 +2027,21 @@ async fn no_race_acquiring_permits() {
2111
2027
  task_barr.wait().await;
2112
2028
  };
2113
2029
  join!(poll_1_f, poll_2_f, other_f);
2030
+ // Deal with eviction due to cache being full
2031
+ worker.handle_eviction().await;
2032
+ // Complete workflow (otherwise, this test can encounter a rare shutdown-related race that is
2033
+ // only possible with the `ignore_evicts_on_shutdown` flag set true, as it is to make tests
2034
+ // more convenient).
2035
+ let r = worker.poll_workflow_activation().await.unwrap();
2036
+ worker
2037
+ .complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
2038
+ r.run_id,
2039
+ start_timer_cmd(1, Duration::from_secs(1)),
2040
+ ))
2041
+ .await
2042
+ .unwrap();
2043
+ let r = worker.poll_workflow_activation().await.unwrap();
2044
+ worker.complete_execution(&r.run_id).await;
2114
2045
  worker.drain_pollers_and_shutdown().await;
2115
2046
  }
2116
2047
 
@@ -2679,89 +2610,6 @@ async fn jobs_are_in_appropriate_order() {
2679
2610
  );
2680
2611
  }
2681
2612
 
2682
- #[rstest]
2683
- #[tokio::test]
2684
- async fn history_length_with_fail_and_timeout(
2685
- #[values(true, false)] use_cache: bool,
2686
- #[values(1, 2, 3)] history_responses_case: u8,
2687
- ) {
2688
- let wfid = "fake_wf_id";
2689
- let mut t = TestHistoryBuilder::default();
2690
- t.add_by_type(EventType::WorkflowExecutionStarted);
2691
- t.add_full_wf_task();
2692
- let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
2693
- t.add_timer_fired(timer_started_event_id, "1".to_string());
2694
- t.add_workflow_task_scheduled_and_started();
2695
- t.add_workflow_task_failed_with_failure(WorkflowTaskFailedCause::Unspecified, "ahh".into());
2696
- t.add_workflow_task_scheduled_and_started();
2697
- t.add_workflow_task_timed_out();
2698
- t.add_full_wf_task();
2699
- let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
2700
- t.add_timer_fired(timer_started_event_id, "2".to_string());
2701
- t.add_full_wf_task();
2702
- t.add_workflow_execution_completed();
2703
-
2704
- let mut mock_client = mock_worker_client();
2705
- let history_responses = match history_responses_case {
2706
- 1 => vec![ResponseType::AllHistory],
2707
- 2 => vec![
2708
- ResponseType::ToTaskNum(1),
2709
- ResponseType::ToTaskNum(2),
2710
- ResponseType::AllHistory,
2711
- ],
2712
- 3 => {
2713
- let mut needs_fetch = hist_to_poll_resp(&t, wfid, ResponseType::ToTaskNum(2)).resp;
2714
- needs_fetch.next_page_token = vec![1];
2715
- // Truncate the history a bit in order to force incomplete WFT
2716
- needs_fetch.history.as_mut().unwrap().events.truncate(6);
2717
- let needs_fetch_resp = ResponseType::Raw(needs_fetch);
2718
- let mut empty_fetch_resp: GetWorkflowExecutionHistoryResponse =
2719
- t.get_history_info(1).unwrap().into();
2720
- empty_fetch_resp.history.as_mut().unwrap().events = vec![];
2721
- mock_client
2722
- .expect_get_workflow_execution_history()
2723
- .returning(move |_, _, _| Ok(empty_fetch_resp.clone()))
2724
- .times(1);
2725
- vec![
2726
- ResponseType::ToTaskNum(1),
2727
- needs_fetch_resp,
2728
- ResponseType::ToTaskNum(2),
2729
- ResponseType::AllHistory,
2730
- ]
2731
- }
2732
- _ => unreachable!(),
2733
- };
2734
-
2735
- let mut mh = MockPollCfg::from_resp_batches(wfid, t, history_responses, mock_client);
2736
- if history_responses_case == 3 {
2737
- // Expect the failed pagination fetch
2738
- mh.num_expected_fails = 1;
2739
- }
2740
- let mut worker = mock_sdk_cfg(mh, |wc| {
2741
- if use_cache {
2742
- wc.max_cached_workflows = 1;
2743
- }
2744
- });
2745
- worker.register_wf(DEFAULT_WORKFLOW_TYPE, |ctx: WfContext| async move {
2746
- assert_eq!(ctx.history_length(), 3);
2747
- ctx.timer(Duration::from_secs(1)).await;
2748
- assert_eq!(ctx.history_length(), 14);
2749
- ctx.timer(Duration::from_secs(1)).await;
2750
- assert_eq!(ctx.history_length(), 19);
2751
- Ok(().into())
2752
- });
2753
- worker
2754
- .submit_wf(
2755
- wfid.to_owned(),
2756
- DEFAULT_WORKFLOW_TYPE.to_owned(),
2757
- vec![],
2758
- WorkflowOptions::default(),
2759
- )
2760
- .await
2761
- .unwrap();
2762
- worker.run_until_done().await.unwrap();
2763
- }
2764
-
2765
2613
  #[tokio::test]
2766
2614
  async fn poller_wont_run_ahead_of_task_slots() {
2767
2615
  let popped_tasks = Arc::new(AtomicUsize::new(0));
@@ -2946,70 +2794,6 @@ async fn use_compatible_version_flag(
2946
2794
  worker.shutdown().await;
2947
2795
  }
2948
2796
 
2949
- #[allow(deprecated)]
2950
- #[tokio::test]
2951
- async fn sets_build_id_from_wft_complete() {
2952
- let wfid = "fake_wf_id";
2953
-
2954
- let mut t = TestHistoryBuilder::default();
2955
- t.add_by_type(EventType::WorkflowExecutionStarted);
2956
- t.add_full_wf_task();
2957
- let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
2958
- t.add_timer_fired(timer_started_event_id, "1".to_string());
2959
- t.add_full_wf_task();
2960
- t.modify_event(t.current_event_id(), |he| {
2961
- if let history_event::Attributes::WorkflowTaskCompletedEventAttributes(a) =
2962
- he.attributes.as_mut().unwrap()
2963
- {
2964
- a.worker_version = Some(WorkerVersionStamp {
2965
- build_id: "enchi-cat".to_string(),
2966
- ..Default::default()
2967
- });
2968
- }
2969
- });
2970
- let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
2971
- t.add_timer_fired(timer_started_event_id, "2".to_string());
2972
- t.add_workflow_task_scheduled_and_started();
2973
-
2974
- let mock = mock_worker_client();
2975
- let mut worker = mock_sdk_cfg(
2976
- MockPollCfg::from_resp_batches(wfid, t, [ResponseType::AllHistory], mock),
2977
- |cfg| {
2978
- cfg.versioning_strategy = WorkerVersioningStrategy::None {
2979
- build_id: "fierce-predator".to_string(),
2980
- };
2981
- cfg.max_cached_workflows = 1;
2982
- },
2983
- );
2984
-
2985
- worker.register_wf(DEFAULT_WORKFLOW_TYPE, |ctx: WfContext| async move {
2986
- // First task, it should be empty, since replaying and nothing in first WFT completed
2987
- assert_eq!(ctx.current_deployment_version(), None);
2988
- ctx.timer(Duration::from_secs(1)).await;
2989
- assert_eq!(
2990
- ctx.current_deployment_version().unwrap().build_id,
2991
- "enchi-cat"
2992
- );
2993
- ctx.timer(Duration::from_secs(1)).await;
2994
- // Not replaying at this point, so we should see the worker's build id
2995
- assert_eq!(
2996
- ctx.current_deployment_version().unwrap().build_id,
2997
- "fierce-predator"
2998
- );
2999
- ctx.timer(Duration::from_secs(1)).await;
3000
- assert_eq!(
3001
- ctx.current_deployment_version().unwrap().build_id,
3002
- "fierce-predator"
3003
- );
3004
- Ok(().into())
3005
- });
3006
- worker
3007
- .submit_wf(wfid, DEFAULT_WORKFLOW_TYPE, vec![], Default::default())
3008
- .await
3009
- .unwrap();
3010
- worker.run_until_done().await.unwrap();
3011
- }
3012
-
3013
2797
  #[tokio::test]
3014
2798
  async fn slot_provider_cant_hand_out_more_permits_than_cache_size() {
3015
2799
  let popped_tasks = Arc::new(AtomicUsize::new(0));
@@ -3101,53 +2885,6 @@ async fn slot_provider_cant_hand_out_more_permits_than_cache_size() {
3101
2885
  assert_eq!(popped_tasks.load(Ordering::Relaxed), 10);
3102
2886
  }
3103
2887
 
3104
- #[tokio::test]
3105
- async fn pass_timer_summary_to_metadata() {
3106
- let t = canned_histories::single_timer("1");
3107
- let mut mock_cfg = MockPollCfg::from_hist_builder(t);
3108
- let wf_id = mock_cfg.hists[0].wf_id.clone();
3109
- let wf_type = DEFAULT_WORKFLOW_TYPE;
3110
- let expected_user_metadata = Some(UserMetadata {
3111
- summary: Some(b"timer summary".into()),
3112
- details: None,
3113
- });
3114
- mock_cfg.completion_asserts_from_expectations(|mut asserts| {
3115
- asserts
3116
- .then(move |wft| {
3117
- assert_eq!(wft.commands.len(), 1);
3118
- assert_eq!(wft.commands[0].command_type(), CommandType::StartTimer);
3119
- assert_eq!(wft.commands[0].user_metadata, expected_user_metadata)
3120
- })
3121
- .then(move |wft| {
3122
- assert_eq!(wft.commands.len(), 1);
3123
- assert_eq!(
3124
- wft.commands[0].command_type(),
3125
- CommandType::CompleteWorkflowExecution
3126
- );
3127
- });
3128
- });
3129
-
3130
- let mut worker = mock_sdk_cfg(mock_cfg, |_| {});
3131
- worker.register_wf(wf_type, |ctx: WfContext| async move {
3132
- ctx.timer(TimerOptions {
3133
- duration: Duration::from_secs(1),
3134
- summary: Some("timer summary".to_string()),
3135
- })
3136
- .await;
3137
- Ok(().into())
3138
- });
3139
- worker
3140
- .submit_wf(
3141
- wf_id.to_owned(),
3142
- wf_type.to_owned(),
3143
- vec![],
3144
- WorkflowOptions::default(),
3145
- )
3146
- .await
3147
- .unwrap();
3148
- worker.run_until_done().await.unwrap();
3149
- }
3150
-
3151
2888
  #[tokio::test]
3152
2889
  async fn both_normal_and_sticky_pollers_poll_concurrently() {
3153
2890
  struct Counters {
@@ -241,8 +241,7 @@ impl EphemeralServer {
241
241
  }
242
242
  }
243
243
  Err(anyhow!(
244
- "Failed connecting to test server after 5 seconds, last error: {:?}",
245
- last_error
244
+ "Failed connecting to test server after 5 seconds, last error: {last_error:?}"
246
245
  ))
247
246
  }
248
247
 
@@ -282,6 +281,19 @@ pub enum EphemeralExe {
282
281
  },
283
282
  }
284
283
 
284
+ /// Return the default cached download for test usage inside this repo
285
+ pub fn default_cached_download() -> EphemeralExe {
286
+ EphemeralExe::CachedDownload {
287
+ version: EphemeralExeVersion::SDKDefault {
288
+ sdk_name: "sdk-rust".to_string(),
289
+ sdk_version: "0.1.0".to_string(),
290
+ },
291
+ dest_dir: None,
292
+ // 15 days
293
+ ttl: Some(Duration::from_secs(60 * 60 * 24 * 15)),
294
+ }
295
+ }
296
+
285
297
  /// Which version of the exe to download.
286
298
  #[derive(Debug, Clone)]
287
299
  pub enum EphemeralExeVersion {
@@ -355,7 +367,7 @@ impl EphemeralExe {
355
367
  let arch = match std::env::consts::ARCH {
356
368
  "x86_64" => "amd64",
357
369
  "arm" | "aarch64" => "arm64",
358
- other => return Err(anyhow!("Unsupported arch: {}", other)),
370
+ other => return Err(anyhow!("Unsupported arch: {other}")),
359
371
  };
360
372
  let mut get_info_params = vec![("arch", arch), ("platform", platform)];
361
373
  if let Some(format) = preferred_format {
@@ -18,9 +18,10 @@ use temporal_sdk_core_protos::temporal::api::{
18
18
  /// may be removed from the enum. *Importantly*, all variants must be given explicit values, such
19
19
  /// that removing older variants does not create any change in existing values. Removed flag
20
20
  /// variants must be reserved forever (a-la protobuf), and should be called out in a comment.
21
+ #[allow(unreachable_pub)] // re-exported in test_help::integ_helpers
21
22
  #[repr(u32)]
22
23
  #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone, Debug, enum_iterator::Sequence)]
23
- pub(crate) enum CoreInternalFlags {
24
+ pub enum CoreInternalFlags {
24
25
  /// In this flag additional checks were added to a number of state machines to ensure that
25
26
  /// the ID and type of activities, local activities, and child workflows match during replay.
26
27
  IdAndTypeDeterminismChecks = 1,
@@ -202,6 +203,15 @@ impl InternalFlags {
202
203
  Self::Disabled => Either::Right(iter::empty()),
203
204
  }
204
205
  }
206
+
207
+ pub(crate) fn last_sdk_version(&self) -> Option<&str> {
208
+ match self {
209
+ InternalFlags::Enabled {
210
+ last_sdk_version, ..
211
+ } if !last_sdk_version.is_empty() => Some(last_sdk_version),
212
+ InternalFlags::Enabled { .. } | InternalFlags::Disabled => None,
213
+ }
214
+ }
205
215
  }
206
216
 
207
217
  impl CoreInternalFlags {
@@ -26,9 +26,9 @@ mod worker;
26
26
 
27
27
  #[cfg(test)]
28
28
  mod core_tests;
29
- #[cfg(test)]
29
+ #[cfg(any(feature = "test-utilities", test))]
30
30
  #[macro_use]
31
- mod test_help;
31
+ pub mod test_help;
32
32
 
33
33
  pub(crate) use temporal_sdk_core_api::errors;
34
34
 
@@ -62,7 +62,7 @@ use crate::{
62
62
  use anyhow::bail;
63
63
  use futures_util::Stream;
64
64
  use std::sync::{Arc, OnceLock};
65
- use temporal_client::{ConfiguredClient, NamespacedClient, TemporalServiceClientWithMetrics};
65
+ use temporal_client::{ConfiguredClient, NamespacedClient, SharedReplaceableClient};
66
66
  use temporal_sdk_core_api::{
67
67
  Worker as WorkerTrait,
68
68
  errors::{CompleteActivityError, PollError},
@@ -89,14 +89,15 @@ pub fn init_worker<CT>(
89
89
  where
90
90
  CT: Into<sealed::AnyClient>,
91
91
  {
92
- let client = init_worker_client(&worker_config, *client.into().into_inner());
93
- if client.namespace() != worker_config.namespace {
94
- bail!("Passed in client is not bound to the same namespace as the worker");
95
- }
96
- if client.namespace() == "" {
97
- bail!("Client namespace cannot be empty");
92
+ if worker_config.namespace.is_empty() {
93
+ bail!("Worker namespace cannot be empty");
98
94
  }
99
- let client_ident = client.get_identity().to_owned();
95
+
96
+ let client = RetryClient::new(
97
+ SharedReplaceableClient::new(init_worker_client(&worker_config, client)),
98
+ RetryConfig::default(),
99
+ );
100
+ let client_ident = client.identity();
100
101
  let sticky_q = sticky_q_name_for_worker(&client_ident, &worker_config);
101
102
 
102
103
  if client_ident.is_empty() {
@@ -141,15 +142,15 @@ where
141
142
  rwi.into_core_worker()
142
143
  }
143
144
 
144
- pub(crate) fn init_worker_client(
145
- config: &WorkerConfig,
146
- client: ConfiguredClient<TemporalServiceClientWithMetrics>,
147
- ) -> RetryClient<Client> {
148
- let mut client = Client::new(client, config.namespace.clone());
145
+ pub(crate) fn init_worker_client<CT>(config: &WorkerConfig, client: CT) -> Client
146
+ where
147
+ CT: Into<sealed::AnyClient>,
148
+ {
149
+ let mut client = Client::new(*client.into().into_inner(), config.namespace.clone());
149
150
  if let Some(ref id_override) = config.client_identity_override {
150
151
  client.options_mut().identity.clone_from(id_override);
151
152
  }
152
- RetryClient::new(client, RetryConfig::default())
153
+ client
153
154
  }
154
155
 
155
156
  /// Creates a unique sticky queue name for a worker, iff the config allows for 1 or more cached
@@ -171,44 +172,57 @@ pub(crate) fn sticky_q_name_for_worker(
171
172
 
172
173
  mod sealed {
173
174
  use super::*;
175
+ use temporal_client::{SharedReplaceableClient, TemporalServiceClient};
174
176
 
175
177
  /// Allows passing different kinds of clients into things that want to be flexible. Motivating
176
178
  /// use-case was worker initialization.
177
179
  ///
178
180
  /// Needs to exist in this crate to avoid blanket impl conflicts.
179
181
  pub struct AnyClient {
180
- pub(crate) inner: Box<ConfiguredClient<TemporalServiceClientWithMetrics>>,
182
+ pub(crate) inner: Box<ConfiguredClient<TemporalServiceClient>>,
181
183
  }
182
184
  impl AnyClient {
183
- pub(crate) fn into_inner(self) -> Box<ConfiguredClient<TemporalServiceClientWithMetrics>> {
185
+ pub(crate) fn into_inner(self) -> Box<ConfiguredClient<TemporalServiceClient>> {
184
186
  self.inner
185
187
  }
186
188
  }
187
189
 
188
- impl From<RetryClient<ConfiguredClient<TemporalServiceClientWithMetrics>>> for AnyClient {
189
- fn from(c: RetryClient<ConfiguredClient<TemporalServiceClientWithMetrics>>) -> Self {
190
- Self {
191
- inner: Box::new(c.into_inner()),
192
- }
190
+ impl From<ConfiguredClient<TemporalServiceClient>> for AnyClient {
191
+ fn from(c: ConfiguredClient<TemporalServiceClient>) -> Self {
192
+ Self { inner: Box::new(c) }
193
+ }
194
+ }
195
+
196
+ impl From<Client> for AnyClient {
197
+ fn from(c: Client) -> Self {
198
+ c.into_inner().into()
193
199
  }
194
200
  }
195
- impl From<RetryClient<Client>> for AnyClient {
196
- fn from(c: RetryClient<Client>) -> Self {
197
- Self {
198
- inner: Box::new(c.into_inner().into_inner()),
199
- }
201
+
202
+ impl<T> From<RetryClient<T>> for AnyClient
203
+ where
204
+ T: Into<AnyClient>,
205
+ {
206
+ fn from(c: RetryClient<T>) -> Self {
207
+ c.into_inner().into()
200
208
  }
201
209
  }
202
- impl From<Arc<RetryClient<Client>>> for AnyClient {
203
- fn from(c: Arc<RetryClient<Client>>) -> Self {
204
- Self {
205
- inner: Box::new(c.get_client().inner().clone()),
206
- }
210
+
211
+ impl<T> From<SharedReplaceableClient<T>> for AnyClient
212
+ where
213
+ T: Into<AnyClient> + Clone + Send + Sync,
214
+ {
215
+ fn from(c: SharedReplaceableClient<T>) -> Self {
216
+ c.inner_clone().into()
207
217
  }
208
218
  }
209
- impl From<ConfiguredClient<TemporalServiceClientWithMetrics>> for AnyClient {
210
- fn from(c: ConfiguredClient<TemporalServiceClientWithMetrics>) -> Self {
211
- Self { inner: Box::new(c) }
219
+
220
+ impl<T> From<Arc<T>> for AnyClient
221
+ where
222
+ T: Into<AnyClient> + Clone,
223
+ {
224
+ fn from(c: Arc<T>) -> Self {
225
+ Arc::unwrap_or_clone(c).into()
212
226
  }
213
227
  }
214
228
  }
@@ -22,16 +22,16 @@ use temporal_sdk_core_protos::temporal::api::workflowservice::v1::{
22
22
  use tokio::select;
23
23
  use tokio_util::sync::CancellationToken;
24
24
 
25
- #[cfg(test)]
25
+ #[cfg(any(feature = "test-utilities", test))]
26
26
  use futures_util::Future;
27
- #[cfg(test)]
27
+ #[cfg(any(feature = "test-utilities", test))]
28
28
  pub(crate) use poll_buffer::MockPermittedPollBuffer;
29
29
 
30
30
  pub(crate) type Result<T, E = tonic::Status> = std::result::Result<T, E>;
31
31
 
32
32
  /// A trait for things that long poll the server.
33
- #[cfg_attr(test, mockall::automock)]
34
- #[cfg_attr(test, allow(unused))]
33
+ #[cfg_attr(any(feature = "test-utilities", test), mockall::automock)]
34
+ #[cfg_attr(any(feature = "test-utilities", test), allow(unused))]
35
35
  #[async_trait::async_trait]
36
36
  pub(crate) trait Poller<PollResult>
37
37
  where
@@ -79,7 +79,7 @@ where
79
79
  }
80
80
  }
81
81
 
82
- #[cfg(test)]
82
+ #[cfg(any(feature = "test-utilities", test))]
83
83
  mockall::mock! {
84
84
  pub ManualPoller<T: Send + Sync + 'static> {}
85
85
  #[allow(unused)]
@@ -666,14 +666,14 @@ impl TaskPollerResult for PollNexusTaskQueueResponse {
666
666
  }
667
667
  }
668
668
 
669
- #[cfg(test)]
669
+ #[cfg(any(feature = "test-utilities", test))]
670
670
  #[derive(derive_more::Constructor)]
671
671
  pub(crate) struct MockPermittedPollBuffer<PT, SK: SlotKind> {
672
672
  sem: Arc<MeteredPermitDealer<SK>>,
673
673
  inner: PT,
674
674
  }
675
675
 
676
- #[cfg(test)]
676
+ #[cfg(any(feature = "test-utilities", test))]
677
677
  #[async_trait::async_trait]
678
678
  impl<T, PT, SK> Poller<(T, OwnedMeteredSemPermit<SK>)> for MockPermittedPollBuffer<PT, SK>
679
679
  where