@temporalio/core-bridge 0.19.2 → 0.20.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 (124) hide show
  1. package/Cargo.lock +90 -157
  2. package/Cargo.toml +1 -0
  3. package/index.d.ts +11 -27
  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/.buildkite/docker/Dockerfile +1 -1
  11. package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
  12. package/sdk-core/.cargo/config.toml +1 -0
  13. package/sdk-core/CODEOWNERS +1 -1
  14. package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +119 -86
  15. package/sdk-core/bridge-ffi/src/lib.rs +311 -315
  16. package/sdk-core/bridge-ffi/src/wrappers.rs +108 -113
  17. package/sdk-core/client/Cargo.toml +13 -9
  18. package/sdk-core/client/LICENSE.txt +23 -0
  19. package/sdk-core/client/src/lib.rs +286 -174
  20. package/sdk-core/client/src/metrics.rs +86 -12
  21. package/sdk-core/client/src/raw.rs +566 -0
  22. package/sdk-core/client/src/retry.rs +137 -99
  23. package/sdk-core/core/Cargo.toml +15 -10
  24. package/sdk-core/core/LICENSE.txt +23 -0
  25. package/sdk-core/core/benches/workflow_replay.rs +79 -0
  26. package/sdk-core/core/src/abstractions.rs +38 -0
  27. package/sdk-core/core/src/core_tests/activity_tasks.rs +108 -182
  28. package/sdk-core/core/src/core_tests/child_workflows.rs +16 -11
  29. package/sdk-core/core/src/core_tests/determinism.rs +24 -12
  30. package/sdk-core/core/src/core_tests/local_activities.rs +53 -27
  31. package/sdk-core/core/src/core_tests/mod.rs +30 -43
  32. package/sdk-core/core/src/core_tests/queries.rs +82 -81
  33. package/sdk-core/core/src/core_tests/workers.rs +111 -296
  34. package/sdk-core/core/src/core_tests/workflow_cancels.rs +4 -4
  35. package/sdk-core/core/src/core_tests/workflow_tasks.rs +213 -241
  36. package/sdk-core/core/src/lib.rs +73 -318
  37. package/sdk-core/core/src/pollers/mod.rs +4 -6
  38. package/sdk-core/core/src/pollers/poll_buffer.rs +20 -14
  39. package/sdk-core/core/src/protosext/mod.rs +7 -10
  40. package/sdk-core/core/src/replay/mod.rs +11 -150
  41. package/sdk-core/core/src/telemetry/metrics.rs +35 -2
  42. package/sdk-core/core/src/telemetry/mod.rs +49 -16
  43. package/sdk-core/core/src/telemetry/prometheus_server.rs +14 -35
  44. package/sdk-core/core/src/test_help/mod.rs +104 -170
  45. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +57 -34
  46. package/sdk-core/core/src/worker/activities/local_activities.rs +37 -17
  47. package/sdk-core/core/src/worker/activities.rs +23 -16
  48. package/sdk-core/core/src/worker/client/mocks.rs +86 -0
  49. package/sdk-core/core/src/worker/client.rs +209 -0
  50. package/sdk-core/core/src/worker/mod.rs +193 -105
  51. package/sdk-core/core/src/workflow/driven_workflow.rs +21 -6
  52. package/sdk-core/core/src/workflow/history_update.rs +107 -24
  53. package/sdk-core/core/src/workflow/machines/activity_state_machine.rs +2 -3
  54. package/sdk-core/core/src/workflow/machines/child_workflow_state_machine.rs +2 -3
  55. package/sdk-core/core/src/workflow/machines/mod.rs +20 -17
  56. package/sdk-core/core/src/workflow/machines/signal_external_state_machine.rs +56 -19
  57. package/sdk-core/core/src/workflow/machines/transition_coverage.rs +5 -0
  58. package/sdk-core/core/src/workflow/machines/upsert_search_attributes_state_machine.rs +230 -22
  59. package/sdk-core/core/src/workflow/machines/workflow_machines.rs +81 -115
  60. package/sdk-core/core/src/workflow/machines/workflow_task_state_machine.rs +4 -4
  61. package/sdk-core/core/src/workflow/mod.rs +13 -1
  62. package/sdk-core/core/src/workflow/workflow_tasks/mod.rs +43 -33
  63. package/sdk-core/core-api/Cargo.toml +9 -1
  64. package/sdk-core/core-api/LICENSE.txt +23 -0
  65. package/sdk-core/core-api/src/errors.rs +7 -38
  66. package/sdk-core/core-api/src/lib.rs +44 -52
  67. package/sdk-core/core-api/src/worker.rs +10 -2
  68. package/sdk-core/etc/deps.svg +127 -96
  69. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +11 -7
  70. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +10 -0
  71. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +6 -1
  72. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +6 -0
  73. package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +6 -0
  74. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +2 -1
  75. package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +3 -0
  76. package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +12 -0
  77. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +25 -0
  78. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +4 -0
  79. package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +19 -35
  80. package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +2 -6
  81. package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +53 -11
  82. package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +14 -7
  83. package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +3 -5
  84. package/sdk-core/sdk/Cargo.toml +16 -2
  85. package/sdk-core/sdk/LICENSE.txt +23 -0
  86. package/sdk-core/sdk/src/interceptors.rs +11 -0
  87. package/sdk-core/sdk/src/lib.rs +138 -150
  88. package/sdk-core/sdk/src/workflow_context/options.rs +86 -1
  89. package/sdk-core/sdk/src/workflow_context.rs +36 -17
  90. package/sdk-core/sdk/src/workflow_future.rs +19 -25
  91. package/sdk-core/sdk-core-protos/Cargo.toml +1 -1
  92. package/sdk-core/sdk-core-protos/build.rs +1 -0
  93. package/sdk-core/sdk-core-protos/src/history_info.rs +17 -4
  94. package/sdk-core/sdk-core-protos/src/lib.rs +251 -47
  95. package/sdk-core/test-utils/Cargo.toml +3 -1
  96. package/sdk-core/test-utils/src/canned_histories.rs +27 -0
  97. package/sdk-core/test-utils/src/histfetch.rs +3 -3
  98. package/sdk-core/test-utils/src/lib.rs +223 -68
  99. package/sdk-core/tests/integ_tests/client_tests.rs +27 -4
  100. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +93 -14
  101. package/sdk-core/tests/integ_tests/polling_tests.rs +18 -12
  102. package/sdk-core/tests/integ_tests/queries_tests.rs +50 -53
  103. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +117 -103
  104. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +8 -1
  105. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +10 -5
  106. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +7 -1
  107. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +8 -3
  108. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +7 -1
  109. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +76 -15
  110. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +19 -3
  111. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +39 -42
  112. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +84 -0
  113. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +30 -8
  114. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +21 -6
  115. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +26 -16
  116. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +66 -0
  117. package/sdk-core/tests/integ_tests/workflow_tests.rs +78 -74
  118. package/sdk-core/tests/load_tests.rs +9 -6
  119. package/sdk-core/tests/main.rs +43 -10
  120. package/src/conversions.rs +7 -12
  121. package/src/lib.rs +322 -357
  122. package/sdk-core/client/src/mocks.rs +0 -167
  123. package/sdk-core/core/src/worker/dispatcher.rs +0 -171
  124. package/sdk-core/protos/local/temporal/sdk/core/bridge/service.proto +0 -61
@@ -3,6 +3,7 @@ use std::{
3
3
  sync::atomic::{AtomicBool, AtomicUsize, Ordering},
4
4
  time::Duration,
5
5
  };
6
+ use temporal_client::WorkflowOptions;
6
7
  use temporal_sdk::{WfContext, WorkflowResult};
7
8
  use temporal_sdk_core_test_utils::CoreWfStarter;
8
9
  use tokio::sync::Barrier;
@@ -16,7 +17,12 @@ async fn timer_workflow_not_sticky() {
16
17
  worker.register_wf(wf_name.to_owned(), timer_wf);
17
18
 
18
19
  worker
19
- .submit_wf(wf_name.to_owned(), wf_name.to_owned(), vec![])
20
+ .submit_wf(
21
+ wf_name.to_owned(),
22
+ wf_name.to_owned(),
23
+ vec![],
24
+ WorkflowOptions::default(),
25
+ )
20
26
  .await
21
27
  .unwrap();
22
28
  worker.run_until_done().await.unwrap();
@@ -46,7 +52,12 @@ async fn timer_workflow_timeout_on_sticky() {
46
52
  worker.register_wf(wf_name.to_owned(), timer_timeout_wf);
47
53
 
48
54
  worker
49
- .submit_wf(wf_name.to_owned(), wf_name.to_owned(), vec![])
55
+ .submit_wf(
56
+ wf_name.to_owned(),
57
+ wf_name.to_owned(),
58
+ vec![],
59
+ WorkflowOptions::default(),
60
+ )
50
61
  .await
51
62
  .unwrap();
52
63
  worker.run_until_done().await.unwrap();
@@ -69,14 +80,18 @@ async fn cache_miss_ok() {
69
80
  });
70
81
 
71
82
  let run_id = worker
72
- .submit_wf(wf_name.to_owned(), wf_name.to_owned(), vec![])
83
+ .submit_wf(
84
+ wf_name.to_owned(),
85
+ wf_name.to_owned(),
86
+ vec![],
87
+ WorkflowOptions::default(),
88
+ )
73
89
  .await
74
90
  .unwrap();
75
- let core = starter.get_core().await;
76
- let tq = starter.get_task_queue();
91
+ let core = starter.get_worker().await;
77
92
  let (r1, _) = tokio::join!(worker.run_until_done(), async move {
78
93
  barr.wait().await;
79
- core.request_workflow_eviction(tq, &run_id);
94
+ core.request_workflow_eviction(&run_id);
80
95
  // We need to signal the barrier again since the wf gets evicted and will hit it again
81
96
  barr.wait().await;
82
97
  });
@@ -1,11 +1,12 @@
1
1
  use std::time::Duration;
2
+ use temporal_client::WorkflowOptions;
2
3
  use temporal_sdk::{WfContext, WorkflowResult};
3
4
  use temporal_sdk_core_protos::coresdk::{
4
5
  workflow_commands::{CancelTimer, CompleteWorkflowExecution, StartTimer},
5
6
  workflow_completion::WorkflowActivationCompletion,
6
7
  };
7
8
  use temporal_sdk_core_test_utils::{
8
- init_core_and_create_wf, start_timer_cmd, CoreTestHelpers, CoreWfStarter,
9
+ init_core_and_create_wf, start_timer_cmd, CoreWfStarter, WorkerTestHelpers,
9
10
  };
10
11
 
11
12
  pub async fn timer_wf(command_sink: WfContext) -> WorkflowResult<()> {
@@ -21,7 +22,12 @@ async fn timer_workflow_workflow_driver() {
21
22
  worker.register_wf(wf_name.to_owned(), timer_wf);
22
23
 
23
24
  worker
24
- .submit_wf(wf_name.to_owned(), wf_name.to_owned(), vec![])
25
+ .submit_wf(
26
+ wf_name.to_owned(),
27
+ wf_name.to_owned(),
28
+ vec![],
29
+ WorkflowOptions::default(),
30
+ )
25
31
  .await
26
32
  .unwrap();
27
33
  worker.run_until_done().await.unwrap();
@@ -29,10 +35,10 @@ async fn timer_workflow_workflow_driver() {
29
35
 
30
36
  #[tokio::test]
31
37
  async fn timer_workflow_manual() {
32
- let (core, task_q) = init_core_and_create_wf("timer_workflow").await;
33
- let task = core.poll_workflow_activation(&task_q).await.unwrap();
38
+ let mut starter = init_core_and_create_wf("timer_workflow").await;
39
+ let core = starter.get_worker().await;
40
+ let task = core.poll_workflow_activation().await.unwrap();
34
41
  core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
35
- &task_q,
36
42
  task.run_id,
37
43
  vec![StartTimer {
38
44
  seq: 0,
@@ -42,17 +48,17 @@ async fn timer_workflow_manual() {
42
48
  ))
43
49
  .await
44
50
  .unwrap();
45
- let task = core.poll_workflow_activation(&task_q).await.unwrap();
46
- core.complete_execution(&task_q, &task.run_id).await;
51
+ let task = core.poll_workflow_activation().await.unwrap();
52
+ core.complete_execution(&task.run_id).await;
47
53
  core.shutdown().await;
48
54
  }
49
55
 
50
56
  #[tokio::test]
51
57
  async fn timer_cancel_workflow() {
52
- let (core, task_q) = init_core_and_create_wf("timer_cancel_workflow").await;
53
- let task = core.poll_workflow_activation(&task_q).await.unwrap();
58
+ let mut starter = init_core_and_create_wf("timer_cancel_workflow").await;
59
+ let core = starter.get_worker().await;
60
+ let task = core.poll_workflow_activation().await.unwrap();
54
61
  core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
55
- &task_q,
56
62
  task.run_id,
57
63
  vec![
58
64
  StartTimer {
@@ -69,9 +75,8 @@ async fn timer_cancel_workflow() {
69
75
  ))
70
76
  .await
71
77
  .unwrap();
72
- let task = core.poll_workflow_activation(&task_q).await.unwrap();
78
+ let task = core.poll_workflow_activation().await.unwrap();
73
79
  core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
74
- &task_q,
75
80
  task.run_id,
76
81
  vec![
77
82
  CancelTimer { seq: 1 }.into(),
@@ -84,10 +89,10 @@ async fn timer_cancel_workflow() {
84
89
 
85
90
  #[tokio::test]
86
91
  async fn timer_immediate_cancel_workflow() {
87
- let (core, task_q) = init_core_and_create_wf("timer_immediate_cancel_workflow").await;
88
- let task = core.poll_workflow_activation(&task_q).await.unwrap();
92
+ let mut starter = init_core_and_create_wf("timer_immediate_cancel_workflow").await;
93
+ let core = starter.get_worker().await;
94
+ let task = core.poll_workflow_activation().await.unwrap();
89
95
  core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
90
- &task_q,
91
96
  task.run_id,
92
97
  vec![
93
98
  start_timer_cmd(0, Duration::from_secs(1)),
@@ -114,7 +119,12 @@ async fn parallel_timers() {
114
119
  worker.register_wf(wf_name.to_owned(), parallel_timer_wf);
115
120
 
116
121
  worker
117
- .submit_wf(wf_name.to_owned(), wf_name.to_owned(), vec![])
122
+ .submit_wf(
123
+ wf_name.to_owned(),
124
+ wf_name.to_owned(),
125
+ vec![],
126
+ WorkflowOptions::default(),
127
+ )
118
128
  .await
119
129
  .unwrap();
120
130
  worker.run_until_done().await.unwrap();
@@ -0,0 +1,66 @@
1
+ use std::collections::HashMap;
2
+ use temporal_client::{WorkflowClientTrait, WorkflowOptions};
3
+ use temporal_sdk::{WfContext, WorkflowResult};
4
+ use temporal_sdk_core_protos::coresdk::AsJsonPayloadExt;
5
+ use temporal_sdk_core_test_utils::CoreWfStarter;
6
+ use uuid::Uuid;
7
+
8
+ // These are initialized on the server as part of the autosetup container which we
9
+ // use for integration tests.
10
+ static TXT_ATTR: &str = "CustomTextField";
11
+ static INT_ATTR: &str = "CustomIntField";
12
+
13
+ async fn search_attr_updater(ctx: WfContext) -> WorkflowResult<()> {
14
+ ctx.upsert_search_attributes([
15
+ (TXT_ATTR.to_string(), "goodbye".as_json_payload().unwrap()),
16
+ (INT_ATTR.to_string(), 98.as_json_payload().unwrap()),
17
+ ]);
18
+ Ok(().into())
19
+ }
20
+
21
+ #[tokio::test]
22
+ async fn sends_upsert() {
23
+ let wf_name = "sends_upsert_search_attrs";
24
+ let wf_id = Uuid::new_v4();
25
+ let mut starter = CoreWfStarter::new(wf_name);
26
+ let mut worker = starter.worker().await;
27
+ worker.register_wf(wf_name, search_attr_updater);
28
+ let run_id = worker
29
+ .submit_wf(
30
+ wf_id.to_string(),
31
+ wf_name,
32
+ vec![],
33
+ WorkflowOptions {
34
+ search_attributes: Some(HashMap::from([
35
+ (TXT_ATTR.to_string(), "hello".as_json_payload().unwrap()),
36
+ (INT_ATTR.to_string(), 1.as_json_payload().unwrap()),
37
+ ])),
38
+ ..Default::default()
39
+ },
40
+ )
41
+ .await
42
+ .unwrap();
43
+ worker.run_until_done().await.unwrap();
44
+
45
+ let search_attrs = starter
46
+ .get_client()
47
+ .await
48
+ .describe_workflow_execution(wf_id.to_string(), Some(run_id))
49
+ .await
50
+ .unwrap()
51
+ .workflow_execution_info
52
+ .unwrap()
53
+ .search_attributes
54
+ .unwrap()
55
+ .indexed_fields;
56
+ let txt_attr_payload = search_attrs.get(TXT_ATTR).unwrap();
57
+ let int_attr_payload = search_attrs.get(INT_ATTR).unwrap();
58
+ for payload in [txt_attr_payload, int_attr_payload] {
59
+ assert_eq!(
60
+ &b"json/plain".to_vec(),
61
+ payload.metadata.get("encoding").unwrap()
62
+ );
63
+ }
64
+ assert_eq!("\"goodbye\"", txt_attr_payload.to_string());
65
+ assert_eq!("98", int_attr_payload.to_string());
66
+ }
@@ -7,9 +7,11 @@ mod determinism;
7
7
  mod local_activities;
8
8
  mod patches;
9
9
  mod replay;
10
+ mod resets;
10
11
  mod signals;
11
12
  mod stickyness;
12
13
  mod timers;
14
+ mod upsert_search_attrs;
13
15
 
14
16
  use assert_matches::assert_matches;
15
17
  use futures::{channel::mpsc::UnboundedReceiver, future, SinkExt, StreamExt};
@@ -21,8 +23,9 @@ use std::{
21
23
  },
22
24
  time::Duration,
23
25
  };
26
+ use temporal_client::{WorkflowClientTrait, WorkflowOptions};
24
27
  use temporal_sdk::{WfContext, WorkflowResult};
25
- use temporal_sdk_core_api::{errors::PollWfError, Core};
28
+ use temporal_sdk_core_api::{errors::PollWfError, Worker};
26
29
  use temporal_sdk_core_protos::{
27
30
  coresdk::{
28
31
  activity_result::ActivityExecutionResult,
@@ -35,7 +38,7 @@ use temporal_sdk_core_protos::{
35
38
  };
36
39
  use temporal_sdk_core_test_utils::{
37
40
  history_from_proto_binary, init_core_and_create_wf, init_core_replay_preloaded,
38
- schedule_activity_cmd, CoreTestHelpers, CoreWfStarter,
41
+ schedule_activity_cmd, CoreWfStarter, WorkerTestHelpers,
39
42
  };
40
43
  use tokio::time::sleep;
41
44
  use uuid::Uuid;
@@ -46,19 +49,18 @@ use uuid::Uuid;
46
49
  #[tokio::test]
47
50
  async fn parallel_workflows_same_queue() {
48
51
  let mut starter = CoreWfStarter::new("parallel_workflows_same_queue");
49
- let core = starter.get_core().await;
50
- let task_q = starter.get_task_queue().to_string();
52
+ let core = starter.get_worker().await;
51
53
  let num_workflows = 25usize;
52
54
 
53
55
  let run_ids: Vec<_> = future::join_all(
54
- (0..num_workflows).map(|i| starter.start_wf_with_id(format!("wf-id-{}", i))),
56
+ (0..num_workflows)
57
+ .map(|i| starter.start_wf_with_id(format!("wf-id-{}", i), WorkflowOptions::default())),
55
58
  )
56
59
  .await;
57
60
 
58
61
  let mut send_chans = HashMap::new();
59
62
  async fn wf_task(
60
- core: Arc<dyn Core>,
61
- task_q: String,
63
+ worker: Arc<dyn Worker>,
62
64
  mut task_chan: UnboundedReceiver<WorkflowActivation>,
63
65
  ) {
64
66
  let task = task_chan.next().await.unwrap();
@@ -68,10 +70,11 @@ async fn parallel_workflows_same_queue() {
68
70
  variant: Some(workflow_activation_job::Variant::StartWorkflow(_)),
69
71
  }]
70
72
  );
71
- core.complete_timer(&task_q, &task.run_id, 1, Duration::from_secs(1))
73
+ worker
74
+ .complete_timer(&task.run_id, 1, Duration::from_secs(1))
72
75
  .await;
73
76
  let task = task_chan.next().await.unwrap();
74
- core.complete_execution(&task_q, &task.run_id).await;
77
+ worker.complete_execution(&task.run_id).await;
75
78
  }
76
79
 
77
80
  let handles: Vec<_> = run_ids
@@ -79,12 +82,12 @@ async fn parallel_workflows_same_queue() {
79
82
  .map(|run_id| {
80
83
  let (tx, rx) = futures::channel::mpsc::unbounded();
81
84
  send_chans.insert(run_id.clone(), tx);
82
- tokio::spawn(wf_task(core.clone(), task_q.clone(), rx))
85
+ tokio::spawn(wf_task(core.clone(), rx))
83
86
  })
84
87
  .collect();
85
88
 
86
89
  for _ in 0..num_workflows * 2 {
87
- let task = core.poll_workflow_activation(&task_q).await.unwrap();
90
+ let task = core.poll_workflow_activation().await.unwrap();
88
91
  send_chans
89
92
  .get(&task.run_id)
90
93
  .unwrap()
@@ -120,6 +123,7 @@ async fn workflow_lru_cache_evictions() {
120
123
  format!("wce-{}", Uuid::new_v4()),
121
124
  wf_type.to_string(),
122
125
  vec![],
126
+ WorkflowOptions::default(),
123
127
  )
124
128
  .await
125
129
  .unwrap();
@@ -136,8 +140,7 @@ async fn workflow_lru_cache_evictions() {
136
140
  #[tokio::test]
137
141
  async fn shutdown_aborts_actively_blocked_poll() {
138
142
  let mut starter = CoreWfStarter::new("shutdown_aborts_actively_blocked_poll");
139
- let core = starter.get_core().await;
140
- let task_q = starter.get_task_queue();
143
+ let core = starter.get_worker().await;
141
144
  // Begin the poll, and request shutdown from another thread after a small period of time.
142
145
  let tcore = core.clone();
143
146
  let handle = tokio::spawn(async move {
@@ -145,14 +148,14 @@ async fn shutdown_aborts_actively_blocked_poll() {
145
148
  tcore.shutdown().await;
146
149
  });
147
150
  assert_matches!(
148
- core.poll_workflow_activation(task_q).await.unwrap_err(),
151
+ core.poll_workflow_activation().await.unwrap_err(),
149
152
  PollWfError::ShutDown
150
153
  );
151
154
  handle.await.unwrap();
152
155
  // Ensure double-shutdown doesn't explode
153
156
  core.shutdown().await;
154
157
  assert_matches!(
155
- core.poll_workflow_activation(task_q).await.unwrap_err(),
158
+ core.poll_workflow_activation().await.unwrap_err(),
156
159
  PollWfError::ShutDown
157
160
  );
158
161
  }
@@ -160,25 +163,26 @@ async fn shutdown_aborts_actively_blocked_poll() {
160
163
  #[rstest::rstest]
161
164
  #[tokio::test]
162
165
  async fn fail_wf_task(#[values(true, false)] replay: bool) {
163
- let (core, task_q) = if replay {
164
- init_core_replay_preloaded(
166
+ let core = if replay {
167
+ let (core, _) = init_core_replay_preloaded(
165
168
  "fail_wf_task",
166
169
  &history_from_proto_binary("histories/fail_wf_task.bin")
167
170
  .await
168
171
  .unwrap(),
169
- )
172
+ );
173
+ core
170
174
  } else {
171
- init_core_and_create_wf("fail_wf_task").await
175
+ let mut starter = init_core_and_create_wf("fail_wf_task").await;
176
+ starter.get_worker().await
172
177
  };
173
178
  // Start with a timer
174
- let task = core.poll_workflow_activation(&task_q).await.unwrap();
175
- core.complete_timer(&task_q, &task.run_id, 0, Duration::from_millis(200))
179
+ let task = core.poll_workflow_activation().await.unwrap();
180
+ core.complete_timer(&task.run_id, 0, Duration::from_millis(200))
176
181
  .await;
177
182
 
178
183
  // Then break for whatever reason
179
- let task = core.poll_workflow_activation(&task_q).await.unwrap();
184
+ let task = core.poll_workflow_activation().await.unwrap();
180
185
  core.complete_workflow_activation(WorkflowActivationCompletion::fail(
181
- &task_q,
182
186
  task.run_id,
183
187
  Failure::application_failure("I did an oopsie".to_string(), false),
184
188
  ))
@@ -187,7 +191,7 @@ async fn fail_wf_task(#[values(true, false)] replay: bool) {
187
191
 
188
192
  // The server will want to retry the task. This time we finish the workflow -- but we need
189
193
  // to poll a couple of times as there will be more than one required workflow activation.
190
- let task = core.poll_workflow_activation(&task_q).await.unwrap();
194
+ let task = core.poll_workflow_activation().await.unwrap();
191
195
  // The first poll response will tell us to evict
192
196
  assert_matches!(
193
197
  task.jobs.as_slice(),
@@ -195,13 +199,12 @@ async fn fail_wf_task(#[values(true, false)] replay: bool) {
195
199
  variant: Some(workflow_activation_job::Variant::RemoveFromCache(_)),
196
200
  }]
197
201
  );
198
- core.complete_workflow_activation(WorkflowActivationCompletion::empty(&task_q, task.run_id))
202
+ core.complete_workflow_activation(WorkflowActivationCompletion::empty(task.run_id))
199
203
  .await
200
204
  .unwrap();
201
205
 
202
- let task = core.poll_workflow_activation(&task_q).await.unwrap();
206
+ let task = core.poll_workflow_activation().await.unwrap();
203
207
  core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
204
- &task_q,
205
208
  task.run_id,
206
209
  vec![StartTimer {
207
210
  seq: 0,
@@ -211,19 +214,21 @@ async fn fail_wf_task(#[values(true, false)] replay: bool) {
211
214
  ))
212
215
  .await
213
216
  .unwrap();
214
- let task = core.poll_workflow_activation(&task_q).await.unwrap();
215
- core.complete_execution(&task_q, &task.run_id).await;
217
+ let task = core.poll_workflow_activation().await.unwrap();
218
+ core.complete_execution(&task.run_id).await;
216
219
  }
217
220
 
218
221
  #[tokio::test]
219
222
  async fn fail_workflow_execution() {
220
- let (core, task_q) = init_core_and_create_wf("fail_workflow_execution").await;
221
- let task = core.poll_workflow_activation(&task_q).await.unwrap();
222
- core.complete_timer(&task_q, &task.run_id, 0, Duration::from_secs(1))
223
+ let core = init_core_and_create_wf("fail_workflow_execution")
224
+ .await
225
+ .get_worker()
226
+ .await;
227
+ let task = core.poll_workflow_activation().await.unwrap();
228
+ core.complete_timer(&task.run_id, 0, Duration::from_secs(1))
223
229
  .await;
224
- let task = core.poll_workflow_activation(&task_q).await.unwrap();
230
+ let task = core.poll_workflow_activation().await.unwrap();
225
231
  core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
226
- &task_q,
227
232
  task.run_id,
228
233
  vec![FailWorkflowExecution {
229
234
  failure: Some(Failure::application_failure("I'm ded".to_string(), false)),
@@ -236,15 +241,16 @@ async fn fail_workflow_execution() {
236
241
 
237
242
  #[tokio::test]
238
243
  async fn signal_workflow() {
239
- let (core, task_q) = init_core_and_create_wf("signal_workflow").await;
240
- let workflow_id = task_q.clone();
244
+ let mut starter = init_core_and_create_wf("signal_workflow").await;
245
+ let core = starter.get_worker().await;
246
+ let client = starter.get_client().await;
247
+ let workflow_id = starter.get_task_queue().to_string();
241
248
 
242
249
  let signal_id_1 = "signal1";
243
250
  let signal_id_2 = "signal2";
244
- let res = core.poll_workflow_activation(&task_q).await.unwrap();
251
+ let res = core.poll_workflow_activation().await.unwrap();
245
252
  // Task is completed with no commands
246
253
  core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
247
- &task_q,
248
254
  res.run_id.clone(),
249
255
  vec![],
250
256
  ))
@@ -252,7 +258,7 @@ async fn signal_workflow() {
252
258
  .unwrap();
253
259
 
254
260
  // Send the signals to the server
255
- core.server_gateway()
261
+ client
256
262
  .signal_workflow_execution(
257
263
  workflow_id.to_string(),
258
264
  res.run_id.to_string(),
@@ -261,7 +267,7 @@ async fn signal_workflow() {
261
267
  )
262
268
  .await
263
269
  .unwrap();
264
- core.server_gateway()
270
+ client
265
271
  .signal_workflow_execution(
266
272
  workflow_id.to_string(),
267
273
  res.run_id.to_string(),
@@ -271,7 +277,7 @@ async fn signal_workflow() {
271
277
  .await
272
278
  .unwrap();
273
279
 
274
- let mut res = core.poll_workflow_activation(&task_q).await.unwrap();
280
+ let mut res = core.poll_workflow_activation().await.unwrap();
275
281
  // Sometimes both signals are complete at once, sometimes only one, depending on server
276
282
  // Converting test to wf function type would make this shorter
277
283
  if res.jobs.len() == 2 {
@@ -294,13 +300,12 @@ async fn signal_workflow() {
294
300
  },]
295
301
  );
296
302
  core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
297
- &task_q,
298
303
  res.run_id,
299
304
  vec![],
300
305
  ))
301
306
  .await
302
307
  .unwrap();
303
- res = core.poll_workflow_activation(&task_q).await.unwrap();
308
+ res = core.poll_workflow_activation().await.unwrap();
304
309
  assert_matches!(
305
310
  res.jobs.as_slice(),
306
311
  [WorkflowActivationJob {
@@ -308,20 +313,20 @@ async fn signal_workflow() {
308
313
  },]
309
314
  );
310
315
  }
311
- core.complete_execution(&task_q, &res.run_id).await;
316
+ core.complete_execution(&res.run_id).await;
312
317
  }
313
318
 
314
319
  #[tokio::test]
315
320
  async fn signal_workflow_signal_not_handled_on_workflow_completion() {
316
- let (core, task_q) =
321
+ let mut starter =
317
322
  init_core_and_create_wf("signal_workflow_signal_not_handled_on_workflow_completion").await;
318
- let workflow_id = task_q.as_str();
323
+ let core = starter.get_worker().await;
324
+ let workflow_id = starter.get_task_queue().to_string();
319
325
  let signal_id_1 = "signal1";
320
326
  for i in 1..=2 {
321
- let res = core.poll_workflow_activation(&task_q).await.unwrap();
327
+ let res = core.poll_workflow_activation().await.unwrap();
322
328
  // Task is completed with a timer
323
329
  core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
324
- &task_q,
325
330
  res.run_id,
326
331
  vec![StartTimer {
327
332
  seq: 0,
@@ -332,7 +337,7 @@ async fn signal_workflow_signal_not_handled_on_workflow_completion() {
332
337
  .await
333
338
  .unwrap();
334
339
 
335
- let res = core.poll_workflow_activation(&task_q).await.unwrap();
340
+ let res = core.poll_workflow_activation().await.unwrap();
336
341
 
337
342
  if i == 1 {
338
343
  // First attempt we should only see the timer being fired
@@ -346,9 +351,11 @@ async fn signal_workflow_signal_not_handled_on_workflow_completion() {
346
351
  let run_id = res.run_id.clone();
347
352
 
348
353
  // Send the signal to the server
349
- core.server_gateway()
354
+ starter
355
+ .get_client()
356
+ .await
350
357
  .signal_workflow_execution(
351
- workflow_id.to_string(),
358
+ workflow_id.clone(),
352
359
  res.run_id.to_string(),
353
360
  signal_id_1.to_string(),
354
361
  None,
@@ -358,22 +365,19 @@ async fn signal_workflow_signal_not_handled_on_workflow_completion() {
358
365
 
359
366
  // Send completion - not having seen a poll response with a signal in it yet (unhandled
360
367
  // command error will be logged as a warning and an eviction will be issued)
361
- core.complete_execution(&task_q, &run_id).await;
368
+ core.complete_execution(&run_id).await;
362
369
 
363
370
  // We should be told to evict
364
- let res = core.poll_workflow_activation(&task_q).await.unwrap();
371
+ let res = core.poll_workflow_activation().await.unwrap();
365
372
  assert_matches!(
366
373
  res.jobs.as_slice(),
367
374
  [WorkflowActivationJob {
368
375
  variant: Some(workflow_activation_job::Variant::RemoveFromCache(_)),
369
376
  }]
370
377
  );
371
- core.complete_workflow_activation(WorkflowActivationCompletion::empty(
372
- task_q.clone(),
373
- res.run_id,
374
- ))
375
- .await
376
- .unwrap();
378
+ core.complete_workflow_activation(WorkflowActivationCompletion::empty(res.run_id))
379
+ .await
380
+ .unwrap();
377
381
  // Loop to the top to handle wf from the beginning
378
382
  continue;
379
383
  }
@@ -390,7 +394,7 @@ async fn signal_workflow_signal_not_handled_on_workflow_completion() {
390
394
  }
391
395
  ]
392
396
  );
393
- core.complete_execution(&task_q, &res.run_id).await;
397
+ core.complete_execution(&res.run_id).await;
394
398
  }
395
399
  }
396
400
 
@@ -404,13 +408,14 @@ async fn wft_timeout_doesnt_create_unsolvable_autocomplete() {
404
408
  // Test needs eviction on and a short timeout
405
409
  .max_cached_workflows(0usize)
406
410
  .wft_timeout(Duration::from_secs(1));
407
- let core = wf_starter.get_core().await;
411
+ let core = wf_starter.get_worker().await;
412
+ let client = wf_starter.get_client().await;
408
413
  let task_q = wf_starter.get_task_queue();
409
414
  let wf_id = &wf_starter.get_wf_id().to_owned();
410
415
 
411
416
  // Set up some helpers for polling and completing
412
417
  let poll_sched_act = || async {
413
- let wf_task = core.poll_workflow_activation(task_q).await.unwrap();
418
+ let wf_task = core.poll_workflow_activation().await.unwrap();
414
419
  core.complete_workflow_activation(
415
420
  schedule_activity_cmd(
416
421
  0,
@@ -420,7 +425,7 @@ async fn wft_timeout_doesnt_create_unsolvable_autocomplete() {
420
425
  Duration::from_secs(60),
421
426
  Duration::from_secs(60),
422
427
  )
423
- .into_completion(task_q.to_string(), wf_task.run_id.clone()),
428
+ .into_completion(wf_task.run_id.clone()),
424
429
  )
425
430
  .await
426
431
  .unwrap();
@@ -428,7 +433,7 @@ async fn wft_timeout_doesnt_create_unsolvable_autocomplete() {
428
433
  };
429
434
  let poll_sched_act_poll = || async {
430
435
  poll_sched_act().await;
431
- let wf_task = core.poll_workflow_activation(task_q).await.unwrap();
436
+ let wf_task = core.poll_workflow_activation().await.unwrap();
432
437
  assert_matches!(
433
438
  wf_task.jobs.as_slice(),
434
439
  [
@@ -452,36 +457,35 @@ async fn wft_timeout_doesnt_create_unsolvable_autocomplete() {
452
457
  let wf_task = poll_sched_act().await;
453
458
  // Before polling for a task again, we start and complete the activity and send the
454
459
  // corresponding signals.
455
- let ac_task = core.poll_activity_task(task_q).await.unwrap();
460
+ let ac_task = core.poll_activity_task().await.unwrap();
456
461
  let rid = wf_task.run_id.clone();
457
462
  // Send the signals to the server & resolve activity -- sometimes this happens too fast
458
463
  sleep(Duration::from_millis(200)).await;
459
- core.server_gateway()
464
+ client
460
465
  .signal_workflow_execution(wf_id.to_string(), rid, signal_at_start.to_string(), None)
461
466
  .await
462
467
  .unwrap();
463
468
  // Complete activity successfully.
464
469
  core.complete_activity_task(ActivityTaskCompletion {
465
470
  task_token: ac_task.task_token,
466
- task_queue: task_q.to_string(),
467
471
  result: Some(ActivityExecutionResult::ok(Default::default())),
468
472
  })
469
473
  .await
470
474
  .unwrap();
471
475
  let rid = wf_task.run_id.clone();
472
- core.server_gateway()
476
+ client
473
477
  .signal_workflow_execution(wf_id.to_string(), rid, signal_at_complete.to_string(), None)
474
478
  .await
475
479
  .unwrap();
476
480
  // Now poll again, it will be an eviction b/c non-sticky mode.
477
- let wf_task = core.poll_workflow_activation(task_q).await.unwrap();
481
+ let wf_task = core.poll_workflow_activation().await.unwrap();
478
482
  assert_matches!(
479
483
  wf_task.jobs.as_slice(),
480
484
  [WorkflowActivationJob {
481
485
  variant: Some(workflow_activation_job::Variant::RemoveFromCache(_)),
482
486
  }]
483
487
  );
484
- core.complete_workflow_activation(WorkflowActivationCompletion::empty(task_q, wf_task.run_id))
488
+ core.complete_workflow_activation(WorkflowActivationCompletion::empty(wf_task.run_id))
485
489
  .await
486
490
  .unwrap();
487
491
  // Start from the beginning
@@ -491,11 +495,11 @@ async fn wft_timeout_doesnt_create_unsolvable_autocomplete() {
491
495
  // Poll again, which should not have any work to do and spin, until the complete goes through.
492
496
  // Which will be rejected with not found, producing an eviction.
493
497
  let (wf_task, _) = tokio::join!(
494
- async { core.poll_workflow_activation(task_q).await.unwrap() },
498
+ async { core.poll_workflow_activation().await.unwrap() },
495
499
  async {
496
500
  sleep(Duration::from_millis(500)).await;
497
501
  // Reply to the first one, finally
498
- core.complete_execution(task_q, &wf_task.run_id).await;
502
+ core.complete_execution(&wf_task.run_id).await;
499
503
  }
500
504
  );
501
505
  assert_matches!(
@@ -504,10 +508,10 @@ async fn wft_timeout_doesnt_create_unsolvable_autocomplete() {
504
508
  variant: Some(workflow_activation_job::Variant::RemoveFromCache(_)),
505
509
  }]
506
510
  );
507
- core.complete_workflow_activation(WorkflowActivationCompletion::empty(task_q, wf_task.run_id))
511
+ core.complete_workflow_activation(WorkflowActivationCompletion::empty(wf_task.run_id))
508
512
  .await
509
513
  .unwrap();
510
514
  // Do it all over again, without timing out this time
511
515
  let wf_task = poll_sched_act_poll().await;
512
- core.complete_execution(task_q, &wf_task.run_id).await;
516
+ core.complete_execution(&wf_task.run_id).await;
513
517
  }