@temporalio/core-bridge 0.16.4 → 0.18.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 (170) hide show
  1. package/Cargo.lock +339 -226
  2. package/Cargo.toml +7 -3
  3. package/common.js +50 -0
  4. package/index.d.ts +7 -0
  5. package/index.js +12 -0
  6. package/package.json +7 -4
  7. package/releases/aarch64-apple-darwin/index.node +0 -0
  8. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  9. package/{index.node → releases/index.node} +0 -0
  10. package/releases/x86_64-apple-darwin/index.node +0 -0
  11. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  12. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  13. package/scripts/build.js +10 -50
  14. package/sdk-core/.buildkite/docker/Dockerfile +1 -1
  15. package/sdk-core/.buildkite/docker/docker-compose.yaml +2 -2
  16. package/sdk-core/.buildkite/pipeline.yml +2 -0
  17. package/sdk-core/Cargo.toml +1 -88
  18. package/sdk-core/README.md +30 -6
  19. package/sdk-core/bridge-ffi/Cargo.toml +24 -0
  20. package/sdk-core/bridge-ffi/LICENSE.txt +23 -0
  21. package/sdk-core/bridge-ffi/build.rs +25 -0
  22. package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +216 -0
  23. package/sdk-core/bridge-ffi/src/lib.rs +829 -0
  24. package/sdk-core/bridge-ffi/src/wrappers.rs +193 -0
  25. package/sdk-core/client/Cargo.toml +32 -0
  26. package/sdk-core/{src/pollers/gateway.rs → client/src/lib.rs} +101 -195
  27. package/sdk-core/client/src/metrics.rs +89 -0
  28. package/sdk-core/client/src/mocks.rs +167 -0
  29. package/sdk-core/{src/pollers → client/src}/retry.rs +172 -14
  30. package/sdk-core/core/Cargo.toml +96 -0
  31. package/sdk-core/{src → core/src}/core_tests/activity_tasks.rs +193 -37
  32. package/sdk-core/{src → core/src}/core_tests/child_workflows.rs +14 -14
  33. package/sdk-core/{src → core/src}/core_tests/determinism.rs +8 -8
  34. package/sdk-core/core/src/core_tests/local_activities.rs +328 -0
  35. package/sdk-core/{src → core/src}/core_tests/mod.rs +6 -9
  36. package/sdk-core/{src → core/src}/core_tests/queries.rs +54 -54
  37. package/sdk-core/{src → core/src}/core_tests/replay_flag.rs +8 -12
  38. package/sdk-core/{src → core/src}/core_tests/workers.rs +120 -33
  39. package/sdk-core/{src → core/src}/core_tests/workflow_cancels.rs +16 -26
  40. package/sdk-core/{src → core/src}/core_tests/workflow_tasks.rs +280 -292
  41. package/sdk-core/core/src/lib.rs +374 -0
  42. package/sdk-core/{src → core/src}/log_export.rs +3 -27
  43. package/sdk-core/core/src/pending_activations.rs +162 -0
  44. package/sdk-core/{src → core/src}/pollers/mod.rs +4 -22
  45. package/sdk-core/{src → core/src}/pollers/poll_buffer.rs +1 -1
  46. package/sdk-core/core/src/protosext/mod.rs +396 -0
  47. package/sdk-core/core/src/replay/mod.rs +210 -0
  48. package/sdk-core/core/src/retry_logic.rs +144 -0
  49. package/sdk-core/{src → core/src}/telemetry/metrics.rs +3 -58
  50. package/sdk-core/{src → core/src}/telemetry/mod.rs +8 -8
  51. package/sdk-core/{src → core/src}/telemetry/prometheus_server.rs +0 -0
  52. package/sdk-core/{src → core/src}/test_help/mod.rs +35 -83
  53. package/sdk-core/{src → core/src}/worker/activities/activity_heartbeat_manager.rs +95 -42
  54. package/sdk-core/core/src/worker/activities/local_activities.rs +973 -0
  55. package/sdk-core/{src → core/src}/worker/activities.rs +52 -33
  56. package/sdk-core/{src → core/src}/worker/dispatcher.rs +8 -6
  57. package/sdk-core/{src → core/src}/worker/mod.rs +347 -221
  58. package/sdk-core/core/src/worker/wft_delivery.rs +81 -0
  59. package/sdk-core/{src → core/src}/workflow/bridge.rs +5 -2
  60. package/sdk-core/{src → core/src}/workflow/driven_workflow.rs +17 -7
  61. package/sdk-core/{src → core/src}/workflow/history_update.rs +33 -7
  62. package/sdk-core/{src → core/src/workflow}/machines/activity_state_machine.rs +26 -26
  63. package/sdk-core/{src → core/src/workflow}/machines/cancel_external_state_machine.rs +8 -11
  64. package/sdk-core/{src → core/src/workflow}/machines/cancel_workflow_state_machine.rs +19 -21
  65. package/sdk-core/{src → core/src/workflow}/machines/child_workflow_state_machine.rs +20 -31
  66. package/sdk-core/{src → core/src/workflow}/machines/complete_workflow_state_machine.rs +3 -5
  67. package/sdk-core/{src → core/src/workflow}/machines/continue_as_new_workflow_state_machine.rs +18 -18
  68. package/sdk-core/{src → core/src/workflow}/machines/fail_workflow_state_machine.rs +5 -6
  69. package/sdk-core/core/src/workflow/machines/local_activity_state_machine.rs +1451 -0
  70. package/sdk-core/{src → core/src/workflow}/machines/mod.rs +54 -107
  71. package/sdk-core/{src → core/src/workflow}/machines/mutable_side_effect_state_machine.rs +0 -0
  72. package/sdk-core/{src → core/src/workflow}/machines/patch_state_machine.rs +29 -30
  73. package/sdk-core/{src → core/src/workflow}/machines/side_effect_state_machine.rs +0 -0
  74. package/sdk-core/{src → core/src/workflow}/machines/signal_external_state_machine.rs +17 -19
  75. package/sdk-core/{src → core/src/workflow}/machines/timer_state_machine.rs +20 -21
  76. package/sdk-core/{src → core/src/workflow}/machines/transition_coverage.rs +5 -2
  77. package/sdk-core/{src → core/src/workflow}/machines/upsert_search_attributes_state_machine.rs +0 -0
  78. package/sdk-core/core/src/workflow/machines/workflow_machines/local_acts.rs +96 -0
  79. package/sdk-core/{src → core/src/workflow}/machines/workflow_machines.rs +357 -171
  80. package/sdk-core/{src → core/src/workflow}/machines/workflow_task_state_machine.rs +1 -1
  81. package/sdk-core/{src → core/src}/workflow/mod.rs +200 -39
  82. package/sdk-core/{src → core/src}/workflow/workflow_tasks/cache_manager.rs +0 -0
  83. package/sdk-core/{src → core/src}/workflow/workflow_tasks/concurrency_manager.rs +38 -5
  84. package/sdk-core/{src → core/src}/workflow/workflow_tasks/mod.rs +317 -103
  85. package/sdk-core/{test_utils → core-api}/Cargo.toml +10 -7
  86. package/sdk-core/{src → core-api/src}/errors.rs +42 -92
  87. package/sdk-core/core-api/src/lib.rs +158 -0
  88. package/sdk-core/{src/worker/config.rs → core-api/src/worker.rs} +18 -23
  89. package/sdk-core/etc/deps.svg +156 -0
  90. package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +5 -5
  91. package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +3 -5
  92. package/sdk-core/fsm/rustfsm_trait/src/lib.rs +7 -1
  93. package/sdk-core/histories/fail_wf_task.bin +0 -0
  94. package/sdk-core/histories/timer_workflow_history.bin +0 -0
  95. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +44 -13
  96. package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +19 -1
  97. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +1 -1
  98. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +9 -0
  99. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +1 -0
  100. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +1 -0
  101. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +13 -0
  102. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +14 -7
  103. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +176 -18
  104. package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +6 -0
  105. package/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +11 -0
  106. package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +3 -0
  107. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +156 -7
  108. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +135 -104
  109. package/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +78 -0
  110. package/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +78 -0
  111. package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +205 -0
  112. package/sdk-core/protos/local/temporal/sdk/core/bridge/service.proto +61 -0
  113. package/sdk-core/protos/local/{child_workflow.proto → temporal/sdk/core/child_workflow/child_workflow.proto} +1 -1
  114. package/sdk-core/protos/local/{common.proto → temporal/sdk/core/common/common.proto} +5 -3
  115. package/sdk-core/protos/local/{core_interface.proto → temporal/sdk/core/core_interface.proto} +10 -10
  116. package/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +30 -0
  117. package/sdk-core/protos/local/{workflow_activation.proto → temporal/sdk/core/workflow_activation/workflow_activation.proto} +35 -11
  118. package/sdk-core/protos/local/{workflow_commands.proto → temporal/sdk/core/workflow_commands/workflow_commands.proto} +55 -4
  119. package/sdk-core/protos/local/{workflow_completion.proto → temporal/sdk/core/workflow_completion/workflow_completion.proto} +3 -3
  120. package/sdk-core/sdk/Cargo.toml +32 -0
  121. package/sdk-core/{src/prototype_rust_sdk → sdk/src}/conversions.rs +0 -0
  122. package/sdk-core/sdk/src/lib.rs +699 -0
  123. package/sdk-core/sdk/src/payload_converter.rs +11 -0
  124. package/sdk-core/sdk/src/workflow_context/options.rs +180 -0
  125. package/sdk-core/{src/prototype_rust_sdk → sdk/src}/workflow_context.rs +201 -124
  126. package/sdk-core/{src/prototype_rust_sdk → sdk/src}/workflow_future.rs +63 -30
  127. package/sdk-core/sdk-core-protos/Cargo.toml +10 -0
  128. package/sdk-core/sdk-core-protos/build.rs +28 -6
  129. package/sdk-core/sdk-core-protos/src/constants.rs +7 -0
  130. package/sdk-core/{src/test_help → sdk-core-protos/src}/history_builder.rs +134 -49
  131. package/sdk-core/sdk-core-protos/src/history_info.rs +216 -0
  132. package/sdk-core/sdk-core-protos/src/lib.rs +601 -168
  133. package/sdk-core/sdk-core-protos/src/task_token.rs +38 -0
  134. package/sdk-core/sdk-core-protos/src/utilities.rs +14 -0
  135. package/sdk-core/test-utils/Cargo.toml +32 -0
  136. package/sdk-core/{src/test_help → test-utils/src}/canned_histories.rs +59 -78
  137. package/sdk-core/test-utils/src/histfetch.rs +28 -0
  138. package/sdk-core/{test_utils → test-utils}/src/lib.rs +131 -68
  139. package/sdk-core/tests/integ_tests/client_tests.rs +1 -1
  140. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +11 -7
  141. package/sdk-core/tests/integ_tests/polling_tests.rs +12 -11
  142. package/sdk-core/tests/integ_tests/queries_tests.rs +82 -78
  143. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +91 -71
  144. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +3 -4
  145. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +2 -4
  146. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +4 -6
  147. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +4 -6
  148. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -4
  149. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +496 -0
  150. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +5 -8
  151. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +125 -0
  152. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +7 -13
  153. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +33 -5
  154. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +12 -16
  155. package/sdk-core/tests/integ_tests/workflow_tests.rs +85 -82
  156. package/sdk-core/tests/load_tests.rs +6 -6
  157. package/sdk-core/tests/main.rs +2 -2
  158. package/src/conversions.rs +24 -21
  159. package/src/errors.rs +8 -0
  160. package/src/lib.rs +323 -211
  161. package/sdk-core/protos/local/activity_result.proto +0 -46
  162. package/sdk-core/protos/local/activity_task.proto +0 -66
  163. package/sdk-core/src/core_tests/retry.rs +0 -147
  164. package/sdk-core/src/lib.rs +0 -403
  165. package/sdk-core/src/machines/local_activity_state_machine.rs +0 -117
  166. package/sdk-core/src/pending_activations.rs +0 -249
  167. package/sdk-core/src/protosext/mod.rs +0 -160
  168. package/sdk-core/src/prototype_rust_sdk.rs +0 -412
  169. package/sdk-core/src/task_token.rs +0 -20
  170. package/sdk-core/src/test_help/history_info.rs +0 -157
@@ -0,0 +1,38 @@
1
+ use std::fmt::{Debug, Display, Formatter};
2
+
3
+ static LOCAL_ACT_TASK_TOKEN_PREFIX: &[u8] = b"local_act_";
4
+
5
+ #[derive(Hash, Eq, PartialEq, Clone, derive_more::From, derive_more::Into)]
6
+ /// Type-safe wrapper for task token bytes
7
+ pub struct TaskToken(pub Vec<u8>);
8
+
9
+ impl TaskToken {
10
+ /// Task tokens for local activities are always prefixed with a special sigil so they can
11
+ /// be identified easily
12
+ pub fn new_local_activity_token(unique_data: impl IntoIterator<Item = u8>) -> Self {
13
+ let mut bytes = LOCAL_ACT_TASK_TOKEN_PREFIX.to_vec();
14
+ bytes.extend(unique_data);
15
+ TaskToken(bytes)
16
+ }
17
+
18
+ /// Returns true if the task token is for a local activity
19
+ pub fn is_local_activity_task(&self) -> bool {
20
+ self.0.starts_with(LOCAL_ACT_TASK_TOKEN_PREFIX)
21
+ }
22
+ }
23
+
24
+ impl Display for TaskToken {
25
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
26
+ f.write_str(&fmt_tt(&self.0))
27
+ }
28
+ }
29
+
30
+ impl Debug for TaskToken {
31
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
32
+ f.write_str(&format!("TaskToken({})", fmt_tt(&self.0)))
33
+ }
34
+ }
35
+
36
+ pub fn fmt_tt(tt: &[u8]) -> String {
37
+ base64::encode(tt)
38
+ }
@@ -0,0 +1,14 @@
1
+ pub trait TryIntoOrNone<F, T> {
2
+ /// Turn an option of something into an option of another thing, trying to convert along the way
3
+ /// and returning `None` if that conversion fails
4
+ fn try_into_or_none(self) -> Option<T>;
5
+ }
6
+
7
+ impl<F, T> TryIntoOrNone<F, T> for Option<F>
8
+ where
9
+ F: TryInto<T>,
10
+ {
11
+ fn try_into_or_none(self) -> Option<T> {
12
+ self.map(TryInto::try_into).transpose().ok().flatten()
13
+ }
14
+ }
@@ -0,0 +1,32 @@
1
+ [package]
2
+ name = "temporal-sdk-core-test-utils"
3
+ version = "0.1.0"
4
+ authors = ["Spencer Judge <spencer@temporal.io>"]
5
+ edition = "2021"
6
+
7
+ [[bin]]
8
+ name = "histfetch"
9
+ path = "src/histfetch.rs"
10
+
11
+ [dependencies]
12
+ anyhow = "1.0"
13
+ async-trait = "0.1"
14
+ base64 = "0.13"
15
+ futures = "0.3"
16
+ log = "0.4"
17
+ prost = "0.9"
18
+ prost-types = "0.9"
19
+ rand = "0.8"
20
+ serde_json = "1.0"
21
+ temporal-client = { path = "../client", features = ["mocks"] }
22
+ temporal-sdk = { path = "../sdk" }
23
+ temporal-sdk-core = { path = "../core" }
24
+ temporal-sdk-core-api = { path = "../core-api" }
25
+ thiserror = "1.0"
26
+ tokio = "1.1"
27
+ url = "2.2"
28
+ uuid = "0.8"
29
+
30
+ [dependencies.temporal-sdk-core-protos]
31
+ path = "../sdk-core-protos"
32
+ version = "0.1"
@@ -1,4 +1,4 @@
1
- use crate::test_help::TestHistoryBuilder;
1
+ use temporal_sdk_core::replay::TestHistoryBuilder;
2
2
  use temporal_sdk_core_protos::{
3
3
  coresdk::common::NamespacedWorkflowExecution,
4
4
  temporal::api::{
@@ -22,13 +22,7 @@ pub fn single_timer(timer_id: &str) -> TestHistoryBuilder {
22
22
  t.add_by_type(EventType::WorkflowExecutionStarted);
23
23
  t.add_full_wf_task();
24
24
  let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
25
- t.add(
26
- EventType::TimerFired,
27
- history_event::Attributes::TimerFiredEventAttributes(TimerFiredEventAttributes {
28
- started_event_id: timer_started_event_id,
29
- timer_id: timer_id.to_string(),
30
- }),
31
- );
25
+ t.add_timer_fired(timer_started_event_id, timer_id.to_string());
32
26
  t.add_workflow_task_scheduled_and_started();
33
27
  t
34
28
  }
@@ -58,13 +52,7 @@ pub fn cancel_timer(wait_timer_id: &str, cancel_timer_id: &str) -> TestHistoryBu
58
52
  t.add_full_wf_task();
59
53
  let cancel_timer_started_id = t.add_get_event_id(EventType::TimerStarted, None);
60
54
  let wait_timer_started_id = t.add_get_event_id(EventType::TimerStarted, None);
61
- t.add(
62
- EventType::TimerFired,
63
- history_event::Attributes::TimerFiredEventAttributes(TimerFiredEventAttributes {
64
- started_event_id: wait_timer_started_id,
65
- timer_id: wait_timer_id.to_string(),
66
- }),
67
- );
55
+ t.add_timer_fired(wait_timer_started_id, wait_timer_id.to_string());
68
56
  // 8
69
57
  t.add_full_wf_task();
70
58
  // 11
@@ -97,20 +85,8 @@ pub fn parallel_timer(timer1: &str, timer2: &str) -> TestHistoryBuilder {
97
85
  t.add_full_wf_task();
98
86
  let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
99
87
  let timer_2_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
100
- t.add(
101
- EventType::TimerFired,
102
- history_event::Attributes::TimerFiredEventAttributes(TimerFiredEventAttributes {
103
- started_event_id: timer_started_event_id,
104
- timer_id: timer1.to_string(),
105
- }),
106
- );
107
- t.add(
108
- EventType::TimerFired,
109
- history_event::Attributes::TimerFiredEventAttributes(TimerFiredEventAttributes {
110
- started_event_id: timer_2_started_event_id,
111
- timer_id: timer2.to_string(),
112
- }),
113
- );
88
+ t.add_timer_fired(timer_started_event_id, timer1.to_string());
89
+ t.add_timer_fired(timer_2_started_event_id, timer2.to_string());
114
90
  t.add_workflow_task_scheduled_and_started();
115
91
  t
116
92
  }
@@ -195,13 +171,7 @@ pub fn workflow_fails_with_failure_two_different_points(
195
171
  );
196
172
  t.add_full_wf_task();
197
173
  let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
198
- t.add(
199
- EventType::TimerFired,
200
- history_event::Attributes::TimerFiredEventAttributes(TimerFiredEventAttributes {
201
- started_event_id: timer_started_event_id,
202
- timer_id: timer_2.to_string(),
203
- }),
204
- );
174
+ t.add_timer_fired(timer_started_event_id, timer_2.to_string());
205
175
  t.add_workflow_task_scheduled_and_started();
206
176
  t.add_workflow_task_failed_with_failure(
207
177
  WorkflowTaskFailedCause::WorkflowWorkerUnhandledFailure,
@@ -877,13 +847,7 @@ pub fn long_sequential_timers(num_tasks: usize) -> TestHistoryBuilder {
877
847
 
878
848
  for i in 1..=num_tasks {
879
849
  let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
880
- t.add(
881
- EventType::TimerFired,
882
- history_event::Attributes::TimerFiredEventAttributes(TimerFiredEventAttributes {
883
- started_event_id: timer_started_event_id,
884
- timer_id: i.to_string(),
885
- }),
886
- );
850
+ t.add_timer_fired(timer_started_event_id, i.to_string());
887
851
  t.add_full_wf_task();
888
852
  }
889
853
 
@@ -922,13 +886,7 @@ pub fn unsent_at_cancel_repro() -> TestHistoryBuilder {
922
886
  ),
923
887
  );
924
888
  let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
925
- t.add(
926
- EventType::TimerFired,
927
- history_event::Attributes::TimerFiredEventAttributes(TimerFiredEventAttributes {
928
- started_event_id: timer_started_event_id,
929
- timer_id: 1.to_string(),
930
- }),
931
- );
889
+ t.add_timer_fired(timer_started_event_id, 1.to_string());
932
890
 
933
891
  t.add_full_wf_task();
934
892
  t.add_activity_task_cancel_requested(scheduled_event_id);
@@ -1098,13 +1056,7 @@ pub fn timer_then_continue_as_new(timer_id: &str) -> TestHistoryBuilder {
1098
1056
  t.add_by_type(EventType::WorkflowExecutionStarted);
1099
1057
  t.add_full_wf_task();
1100
1058
  let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
1101
- t.add(
1102
- EventType::TimerFired,
1103
- history_event::Attributes::TimerFiredEventAttributes(TimerFiredEventAttributes {
1104
- started_event_id: timer_started_event_id,
1105
- timer_id: timer_id.to_string(),
1106
- }),
1107
- );
1059
+ t.add_timer_fired(timer_started_event_id, timer_id.to_string());
1108
1060
  t.add_full_wf_task();
1109
1061
  t.add_continued_as_new();
1110
1062
  t
@@ -1153,13 +1105,7 @@ pub fn timer_wf_cancel_req_failed(timer_id: &str) -> TestHistoryBuilder {
1153
1105
  pub fn timer_wf_cancel_req_do_another_timer_then_cancelled() -> TestHistoryBuilder {
1154
1106
  timer_cancel_req_then("1", |t| {
1155
1107
  let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
1156
- t.add(
1157
- EventType::TimerFired,
1158
- history_event::Attributes::TimerFiredEventAttributes(TimerFiredEventAttributes {
1159
- started_event_id: timer_started_event_id,
1160
- timer_id: "2".to_string(),
1161
- }),
1162
- );
1108
+ t.add_timer_fired(timer_started_event_id, "2".to_string());
1163
1109
  t.add_full_wf_task();
1164
1110
  t.add_cancelled();
1165
1111
  })
@@ -1184,13 +1130,7 @@ fn timer_cancel_req_then(
1184
1130
  t.add_by_type(EventType::WorkflowExecutionStarted);
1185
1131
  t.add_full_wf_task();
1186
1132
  let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
1187
- t.add(
1188
- EventType::TimerFired,
1189
- history_event::Attributes::TimerFiredEventAttributes(TimerFiredEventAttributes {
1190
- started_event_id: timer_started_event_id,
1191
- timer_id: timer_id.to_string(),
1192
- }),
1193
- );
1133
+ t.add_timer_fired(timer_started_event_id, timer_id.to_string());
1194
1134
  t.add_cancel_requested();
1195
1135
  t.add_full_wf_task();
1196
1136
  end_action(&mut t);
@@ -1277,13 +1217,7 @@ pub fn activity_double_resolve_repro() -> TestHistoryBuilder {
1277
1217
  t.add_we_signaled("sig2", vec![]);
1278
1218
  t.add_workflow_task_started();
1279
1219
  t.add_workflow_task_timed_out();
1280
- t.add(
1281
- EventType::TimerFired,
1282
- history_event::Attributes::TimerFiredEventAttributes(TimerFiredEventAttributes {
1283
- started_event_id: timer_started_event_id,
1284
- timer_id: "2".to_string(),
1285
- }),
1286
- );
1220
+ t.add_timer_fired(timer_started_event_id, "2".to_string());
1287
1221
  t.add_full_wf_task();
1288
1222
  t.add_workflow_execution_completed();
1289
1223
 
@@ -1511,3 +1445,50 @@ pub fn single_child_workflow_start_fail(child_wf_id: &str) -> TestHistoryBuilder
1511
1445
  t.add_workflow_execution_completed();
1512
1446
  t
1513
1447
  }
1448
+
1449
+ /// 1: EVENT_TYPE_WORKFLOW_EXECUTION_STARTED
1450
+ /// 2: EVENT_TYPE_WORKFLOW_TASK_SCHEDULED
1451
+ /// 3: EVENT_TYPE_WORKFLOW_TASK_STARTED
1452
+ /// 4: EVENT_TYPE_WORKFLOW_TASK_COMPLETED
1453
+ /// 5: EVENT_TYPE_MARKER_RECORDED (la result)
1454
+ /// 7: EVENT_TYPE_MARKER_RECORDED (la result)
1455
+ /// 8: EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED
1456
+ pub fn two_local_activities_one_wft(parallel: bool) -> TestHistoryBuilder {
1457
+ let mut t = TestHistoryBuilder::default();
1458
+ t.add_by_type(EventType::WorkflowExecutionStarted);
1459
+ t.add_full_wf_task();
1460
+ let mut start_time = t.wft_start_time();
1461
+ start_time.seconds += 1;
1462
+ t.add_local_activity_result_marker_with_time(1, "1", b"hi".into(), start_time.clone());
1463
+ if !parallel {
1464
+ start_time.seconds += 1;
1465
+ }
1466
+ t.add_local_activity_result_marker_with_time(2, "2", b"hi2".into(), start_time);
1467
+ t.add_workflow_execution_completed();
1468
+ t
1469
+ }
1470
+
1471
+ /// 1: EVENT_TYPE_WORKFLOW_EXECUTION_STARTED
1472
+ /// 2: EVENT_TYPE_WORKFLOW_TASK_SCHEDULED
1473
+ /// 3: EVENT_TYPE_WORKFLOW_TASK_STARTED
1474
+ /// 4: EVENT_TYPE_WORKFLOW_TASK_COMPLETED
1475
+ /// 5: EVENT_TYPE_MARKER_RECORDED (la result)
1476
+ /// 6: EVENT_TYPE_TIMER_STARTED
1477
+ /// 7: EVENT_TYPE_TIMER_FIRED
1478
+ /// 8: EVENT_TYPE_WORKFLOW_TASK_SCHEDULED
1479
+ /// 9: EVENT_TYPE_WORKFLOW_TASK_STARTED
1480
+ /// 10: EVENT_TYPE_WORKFLOW_TASK_COMPLETED
1481
+ /// 11: EVENT_TYPE_MARKER_RECORDED (la result)
1482
+ /// 12: EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED
1483
+ pub fn two_local_activities_separated_by_timer() -> TestHistoryBuilder {
1484
+ let mut t = TestHistoryBuilder::default();
1485
+ t.add_by_type(EventType::WorkflowExecutionStarted);
1486
+ t.add_full_wf_task();
1487
+ t.add_local_activity_result_marker(1, "1", b"hi".into());
1488
+ let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
1489
+ t.add_timer_fired(timer_started_event_id, "1".to_string());
1490
+ t.add_full_wf_task();
1491
+ t.add_local_activity_result_marker(2, "2", b"hi2".into());
1492
+ t.add_workflow_execution_completed();
1493
+ t
1494
+ }
@@ -0,0 +1,28 @@
1
+ //! Use this binary to fetch histories as proto-encoded binary. The first argument must be a
2
+ //! workflow ID. A run id may optionally be provided as the second arg. The history is written to
3
+ //! `{workflow_id}_history.bin`.
4
+ //!
5
+ //! We can use `clap` if this needs more arguments / other stuff later on.
6
+
7
+ use prost::Message;
8
+ use temporal_client::ServerGatewayApis;
9
+ use temporal_sdk_core_test_utils::get_integ_server_options;
10
+
11
+ #[tokio::main]
12
+ async fn main() -> Result<(), anyhow::Error> {
13
+ let gw_opts = get_integ_server_options();
14
+ let gateway = gw_opts.connect(None).await?;
15
+ let wf_id = std::env::args()
16
+ .nth(1)
17
+ .expect("must provide workflow id as only argument");
18
+ let run_id = std::env::args().nth(2);
19
+ let hist = gateway
20
+ .get_workflow_execution_history(wf_id.clone(), run_id, vec![])
21
+ .await?
22
+ .history
23
+ .expect("history field must be populated");
24
+ // Serialize history to file
25
+ let byteified = hist.encode_to_vec();
26
+ tokio::fs::write(format!("{}_history.bin", wf_id), &byteified).await?;
27
+ Ok(())
28
+ }
@@ -1,31 +1,78 @@
1
+ //! This crate contains testing functionality that can be useful when building SDKs against Core,
2
+ //! or even when testing workflows written in SDKs that use Core.
3
+
4
+ pub mod canned_histories;
5
+
1
6
  use futures::{stream::FuturesUnordered, StreamExt};
2
7
  use log::LevelFilter;
8
+ use prost::Message;
3
9
  use rand::{distributions::Standard, Rng};
4
- use std::{convert::TryFrom, env, future::Future, net::SocketAddr, sync::Arc, time::Duration};
10
+ use std::{
11
+ convert::TryFrom, env, future::Future, net::SocketAddr, path::PathBuf, sync::Arc,
12
+ time::Duration,
13
+ };
14
+ use temporal_sdk::TestRustWorker;
5
15
  use temporal_sdk_core::{
6
- prototype_rust_sdk::TestRustWorker, Core, CoreInitOptions, CoreInitOptionsBuilder,
7
- ServerGatewayApis, ServerGatewayOptions, ServerGatewayOptionsBuilder, TelemetryOptions,
8
- TelemetryOptionsBuilder, WorkerConfig, WorkerConfigBuilder,
16
+ replay::{init_core_replay, ReplayCore},
17
+ CoreInitOptions, CoreInitOptionsBuilder, ServerGatewayOptions, ServerGatewayOptionsBuilder,
18
+ TelemetryOptions, TelemetryOptionsBuilder, WorkerConfig, WorkerConfigBuilder,
9
19
  };
10
- use temporal_sdk_core_protos::coresdk::{
11
- workflow_commands::{
12
- workflow_command, ActivityCancellationType, CompleteWorkflowExecution, ScheduleActivity,
13
- StartTimer,
20
+ use temporal_sdk_core_api::Core;
21
+ use temporal_sdk_core_protos::{
22
+ coresdk::{
23
+ workflow_commands::{
24
+ workflow_command, ActivityCancellationType, CompleteWorkflowExecution,
25
+ ScheduleActivity, StartTimer,
26
+ },
27
+ workflow_completion::WorkflowActivationCompletion,
14
28
  },
15
- workflow_completion::WfActivationCompletion,
29
+ temporal::api::history::v1::History,
16
30
  };
17
31
  use url::Url;
18
32
 
19
33
  pub const NAMESPACE: &str = "default";
20
- pub type GwApi = Arc<dyn ServerGatewayApis>;
34
+ pub const TEST_Q: &str = "q";
21
35
  /// If set, turn export traces and metrics to the OTel collector at the given URL
22
36
  const OTEL_URL_ENV_VAR: &str = "TEMPORAL_INTEG_OTEL_URL";
23
37
  /// If set, enable direct scraping of prom metrics on the specified port
24
38
  const PROM_ENABLE_ENV_VAR: &str = "TEMPORAL_INTEG_PROM_PORT";
25
39
 
40
+ /// Create a core instance which will use the provided test name to base the task queue and wf id
41
+ /// upon. Returns the instance and the task queue name (which is also the workflow id).
42
+ pub async fn init_core_and_create_wf(test_name: &str) -> (Arc<dyn Core>, String) {
43
+ let mut starter = CoreWfStarter::new(test_name);
44
+ let core = starter.get_core().await;
45
+ starter.start_wf().await;
46
+ (core, starter.get_task_queue().to_string())
47
+ }
48
+
49
+ /// Create a core replay instance preloaded with just one provided history. Returns the core impl
50
+ /// and the task queue name as in [init_core_and_create_wf].
51
+ pub fn init_core_replay_preloaded(test_name: &str, history: &History) -> (Arc<dyn Core>, String) {
52
+ let replay_core = init_core_replay(get_integ_telem_options());
53
+ let worker_cfg = WorkerConfigBuilder::default()
54
+ .task_queue(test_name)
55
+ .build()
56
+ .expect("Configuration options construct properly");
57
+ replay_core
58
+ .make_replay_worker(worker_cfg, history)
59
+ .expect("Worker registration works");
60
+ (Arc::new(replay_core), test_name.to_string())
61
+ }
62
+
63
+ /// Load history from a file containing the protobuf serialization of it
64
+ pub async fn history_from_proto_binary(path_from_root: &str) -> Result<History, anyhow::Error> {
65
+ let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
66
+ path.push("..");
67
+ path.push(path_from_root);
68
+ let bytes = tokio::fs::read(path).await?;
69
+ Ok(History::decode(&*bytes)?)
70
+ }
71
+
26
72
  /// Implements a builder pattern to help integ tests initialize core and create workflows
27
73
  pub struct CoreWfStarter {
28
- test_name: String,
74
+ /// Used for both the task queue and workflow id
75
+ task_queue_name: String,
29
76
  core_options: CoreInitOptions,
30
77
  worker_config: WorkerConfig,
31
78
  wft_timeout: Option<Duration>,
@@ -37,8 +84,12 @@ impl CoreWfStarter {
37
84
  let rand_bytes: Vec<u8> = rand::thread_rng().sample_iter(&Standard).take(6).collect();
38
85
  let task_q_salt = base64::encode(rand_bytes);
39
86
  let task_queue = format!("{}_{}", test_name, task_q_salt);
87
+ Self::new_tq_name(&task_queue)
88
+ }
89
+
90
+ pub fn new_tq_name(task_queue: &str) -> Self {
40
91
  Self {
41
- test_name: test_name.to_owned(),
92
+ task_queue_name: task_queue.to_owned(),
42
93
  core_options: CoreInitOptionsBuilder::default()
43
94
  .gateway_opts(get_integ_server_options())
44
95
  .telemetry_opts(get_integ_telem_options())
@@ -67,37 +118,65 @@ impl CoreWfStarter {
67
118
  }
68
119
 
69
120
  pub async fn get_core(&mut self) -> Arc<dyn Core> {
70
- self.get_or_init_core().await
121
+ if self.initted_core.is_none() {
122
+ let core = temporal_sdk_core::init(self.core_options.clone())
123
+ .await
124
+ .unwrap();
125
+ // Register a worker for the task queue
126
+ core.register_worker(self.worker_config.clone()).unwrap();
127
+ self.initted_core = Some(Arc::new(core));
128
+ }
129
+ self.initted_core.as_ref().unwrap().clone()
71
130
  }
72
131
 
73
132
  /// Start the workflow defined by the builder and return run id
74
133
  pub async fn start_wf(&self) -> String {
75
- self.start_wf_with_id(self.test_name.clone()).await
134
+ self.start_wf_with_id(self.task_queue_name.clone()).await
76
135
  }
77
136
 
78
137
  pub async fn start_wf_with_id(&self, workflow_id: String) -> String {
79
- with_gw(
80
- self.initted_core
81
- .as_ref()
82
- .expect(
83
- "Core must be initted before starting a workflow.\
138
+ self.initted_core
139
+ .as_ref()
140
+ .expect(
141
+ "Core must be initted before starting a workflow.\
84
142
  Tests must call `get_core` first.",
85
- )
86
- .as_ref(),
87
- |gw: GwApi| async move {
88
- gw.start_workflow(
89
- vec![],
90
- self.worker_config.task_queue.clone(),
91
- workflow_id,
92
- self.test_name.clone(),
93
- self.wft_timeout,
94
- )
95
- .await
96
- .unwrap()
97
- .run_id
98
- },
99
- )
100
- .await
143
+ )
144
+ .as_ref()
145
+ .server_gateway()
146
+ .start_workflow(
147
+ vec![],
148
+ self.worker_config.task_queue.clone(),
149
+ workflow_id,
150
+ self.task_queue_name.clone(),
151
+ self.wft_timeout,
152
+ )
153
+ .await
154
+ .unwrap()
155
+ .run_id
156
+ }
157
+
158
+ /// Fetch the history for the indicated workflow and replay it using the provided worker.
159
+ /// Can be used after completing workflows normally to ensure replay works as well.
160
+ pub async fn fetch_history_and_replay(
161
+ &mut self,
162
+ wf_id: impl Into<String>,
163
+ run_id: impl Into<String>,
164
+ worker: &mut TestRustWorker,
165
+ ) -> Result<(), anyhow::Error> {
166
+ // Fetch history and replay it
167
+ let history = self
168
+ .get_core()
169
+ .await
170
+ .server_gateway()
171
+ .get_workflow_execution_history(wf_id.into(), Some(run_id.into()), vec![])
172
+ .await?
173
+ .history
174
+ .expect("history field must be populated");
175
+ let (replay_core, _) = init_core_replay_preloaded(worker.task_queue(), &history);
176
+ let mut replay_worker = worker.swap_core(replay_core);
177
+ replay_worker.incr_expected_run_count(1);
178
+ replay_worker.run_until_done().await.unwrap();
179
+ Ok(())
101
180
  }
102
181
 
103
182
  pub fn get_task_queue(&self) -> &str {
@@ -105,7 +184,7 @@ impl CoreWfStarter {
105
184
  }
106
185
 
107
186
  pub fn get_wf_id(&self) -> &str {
108
- &self.test_name
187
+ &self.task_queue_name
109
188
  }
110
189
 
111
190
  pub fn max_cached_workflows(&mut self, num: usize) -> &mut Self {
@@ -123,6 +202,11 @@ impl CoreWfStarter {
123
202
  self
124
203
  }
125
204
 
205
+ pub fn max_local_at(&mut self, max: usize) -> &mut Self {
206
+ self.worker_config.max_outstanding_local_activities = max;
207
+ self
208
+ }
209
+
126
210
  pub fn max_at_polls(&mut self, max: usize) -> &mut Self {
127
211
  self.worker_config.max_concurrent_at_polls = max;
128
212
  self
@@ -132,35 +216,6 @@ impl CoreWfStarter {
132
216
  self.wft_timeout = Some(timeout);
133
217
  self
134
218
  }
135
-
136
- async fn get_or_init_core(&mut self) -> Arc<dyn Core> {
137
- let opts = self.core_options.clone();
138
- if self.initted_core.is_none() {
139
- let core = temporal_sdk_core::init(opts).await.unwrap();
140
- // Register a worker for the task queue
141
- core.register_worker(self.worker_config.clone())
142
- .await
143
- .unwrap();
144
- self.initted_core = Some(Arc::new(core));
145
- }
146
- self.initted_core.as_ref().unwrap().clone()
147
- }
148
- }
149
-
150
- pub async fn init_core_and_create_wf(test_name: &str) -> (Arc<dyn Core>, String) {
151
- let mut starter = CoreWfStarter::new(test_name);
152
- let core = starter.get_core().await;
153
- starter.start_wf().await;
154
- (core, starter.get_task_queue().to_string())
155
- }
156
-
157
- // TODO: This should get removed. Pretty pointless now that gateway is exported
158
- pub async fn with_gw<F: FnOnce(GwApi) -> Fout, Fout: Future>(
159
- core: &dyn Core,
160
- fun: F,
161
- ) -> Fout::Output {
162
- let gw = core.server_gateway();
163
- fun(gw).await
164
219
  }
165
220
 
166
221
  pub fn get_integ_server_options() -> ServerGatewayOptions {
@@ -194,7 +249,7 @@ pub fn get_integ_telem_options() -> TelemetryOptions {
194
249
  {
195
250
  ob.prometheus_export_bind_address(addr);
196
251
  }
197
- ob.tracing_filter("temporal_sdk_core=INFO".to_string())
252
+ ob.tracing_filter(env::var("RUST_LOG").unwrap_or_else(|_| "temporal_sdk_core=INFO".to_string()))
198
253
  .log_forwarding_level(LevelFilter::Off)
199
254
  .build()
200
255
  .unwrap()
@@ -224,6 +279,14 @@ pub fn schedule_activity_cmd(
224
279
  .into()
225
280
  }
226
281
 
282
+ pub fn start_timer_cmd(seq: u32, duration: Duration) -> workflow_command::Variant {
283
+ StartTimer {
284
+ seq,
285
+ start_to_fire_timeout: Some(duration.into()),
286
+ }
287
+ .into()
288
+ }
289
+
227
290
  /// Given a desired number of concurrent executions and a provided function that produces a future,
228
291
  /// run that many instances of the future concurrently.
229
292
  ///
@@ -256,7 +319,7 @@ where
256
319
  T: Core + ?Sized,
257
320
  {
258
321
  async fn complete_execution(&self, task_q: &str, run_id: &str) {
259
- self.complete_workflow_activation(WfActivationCompletion::from_cmds(
322
+ self.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
260
323
  task_q.to_string(),
261
324
  run_id.to_string(),
262
325
  vec![CompleteWorkflowExecution { result: None }.into()],
@@ -266,7 +329,7 @@ where
266
329
  }
267
330
 
268
331
  async fn complete_timer(&self, task_q: &str, run_id: &str, seq: u32, duration: Duration) {
269
- self.complete_workflow_activation(WfActivationCompletion::from_cmds(
332
+ self.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
270
333
  task_q.to_string(),
271
334
  run_id.to_string(),
272
335
  vec![StartTimer {
@@ -1,5 +1,5 @@
1
1
  use std::time::Duration;
2
- use test_utils::CoreWfStarter;
2
+ use temporal_sdk_core_test_utils::CoreWfStarter;
3
3
 
4
4
  #[tokio::test]
5
5
  async fn can_use_retry_gateway() {
@@ -1,14 +1,18 @@
1
1
  use assert_matches::assert_matches;
2
2
  use std::time::Duration;
3
3
  use temporal_sdk_core_protos::coresdk::{
4
- activity_result::{self, activity_result as act_res, ActivityResult},
4
+ activity_result::{
5
+ self, activity_resolution as act_res, ActivityExecutionResult, ActivityResolution,
6
+ },
5
7
  activity_task::activity_task as act_task,
6
8
  common::Payload,
7
- workflow_activation::{wf_activation_job, ResolveActivity, WfActivationJob},
9
+ workflow_activation::{workflow_activation_job, ResolveActivity, WorkflowActivationJob},
8
10
  workflow_commands::ActivityCancellationType,
9
11
  ActivityHeartbeat, ActivityTaskCompletion, IntoCompletion,
10
12
  };
11
- use test_utils::{init_core_and_create_wf, schedule_activity_cmd, CoreTestHelpers};
13
+ use temporal_sdk_core_test_utils::{
14
+ init_core_and_create_wf, schedule_activity_cmd, CoreTestHelpers,
15
+ };
12
16
  use tokio::time::sleep;
13
17
 
14
18
  #[tokio::test]
@@ -58,7 +62,7 @@ async fn activity_heartbeat() {
58
62
  core.complete_activity_task(ActivityTaskCompletion {
59
63
  task_token: task.task_token,
60
64
  task_queue: task_q.to_string(),
61
- result: Some(ActivityResult::ok(response_payload.clone())),
65
+ result: Some(ActivityExecutionResult::ok(response_payload.clone())),
62
66
  })
63
67
  .await
64
68
  .unwrap();
@@ -67,9 +71,9 @@ async fn activity_heartbeat() {
67
71
  assert_matches!(
68
72
  task.jobs.as_slice(),
69
73
  [
70
- WfActivationJob {
71
- variant: Some(wf_activation_job::Variant::ResolveActivity(
72
- ResolveActivity {seq, result: Some(ActivityResult{
74
+ WorkflowActivationJob {
75
+ variant: Some(workflow_activation_job::Variant::ResolveActivity(
76
+ ResolveActivity {seq, result: Some(ActivityResolution {
73
77
  status: Some(act_res::Status::Completed(activity_result::Success{result: Some(r)})),
74
78
  ..})}
75
79
  )),