@temporalio/core-bridge 1.15.0 → 1.16.1

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 (209) hide show
  1. package/Cargo.lock +172 -70
  2. package/lib/native.d.ts +1 -1
  3. package/package.json +2 -2
  4. package/releases/aarch64-apple-darwin/index.node +0 -0
  5. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  6. package/releases/x86_64-apple-darwin/index.node +0 -0
  7. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  8. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  9. package/sdk-core/.github/workflows/per-pr.yml +6 -6
  10. package/sdk-core/AGENTS.md +41 -30
  11. package/sdk-core/Cargo.toml +3 -0
  12. package/sdk-core/README.md +15 -9
  13. package/sdk-core/crates/client/Cargo.toml +4 -0
  14. package/sdk-core/crates/client/README.md +139 -0
  15. package/sdk-core/crates/client/src/async_activity_handle.rs +297 -0
  16. package/sdk-core/crates/client/src/callback_based.rs +7 -0
  17. package/sdk-core/crates/client/src/errors.rs +294 -0
  18. package/sdk-core/crates/client/src/{raw.rs → grpc.rs} +280 -159
  19. package/sdk-core/crates/client/src/lib.rs +920 -1326
  20. package/sdk-core/crates/client/src/metrics.rs +24 -33
  21. package/sdk-core/crates/client/src/options_structs.rs +457 -0
  22. package/sdk-core/crates/client/src/replaceable.rs +5 -4
  23. package/sdk-core/crates/client/src/request_extensions.rs +8 -9
  24. package/sdk-core/crates/client/src/retry.rs +99 -54
  25. package/sdk-core/crates/client/src/{worker/mod.rs → worker.rs} +1 -1
  26. package/sdk-core/crates/client/src/workflow_handle.rs +826 -0
  27. package/sdk-core/crates/common/Cargo.toml +61 -2
  28. package/sdk-core/crates/common/build.rs +742 -12
  29. package/sdk-core/crates/common/protos/api_upstream/.github/workflows/ci.yml +2 -0
  30. package/sdk-core/crates/common/protos/api_upstream/Makefile +2 -1
  31. package/sdk-core/crates/common/protos/api_upstream/buf.yaml +0 -3
  32. package/sdk-core/crates/common/protos/api_upstream/cmd/check-path-conflicts/main.go +137 -0
  33. package/sdk-core/crates/common/protos/api_upstream/openapi/openapiv2.json +1166 -770
  34. package/sdk-core/crates/common/protos/api_upstream/openapi/openapiv3.yaml +1243 -750
  35. package/sdk-core/crates/common/protos/api_upstream/temporal/api/deployment/v1/message.proto +2 -2
  36. package/sdk-core/crates/common/protos/api_upstream/temporal/api/enums/v1/workflow.proto +4 -3
  37. package/sdk-core/crates/common/protos/api_upstream/temporal/api/failure/v1/message.proto +1 -0
  38. package/sdk-core/crates/common/protos/api_upstream/temporal/api/history/v1/message.proto +4 -0
  39. package/sdk-core/crates/common/protos/api_upstream/temporal/api/namespace/v1/message.proto +6 -0
  40. package/sdk-core/crates/common/protos/api_upstream/temporal/api/nexus/v1/message.proto +16 -1
  41. package/sdk-core/crates/common/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +64 -6
  42. package/sdk-core/crates/common/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +88 -33
  43. package/sdk-core/crates/common/protos/local/temporal/sdk/core/nexus/nexus.proto +4 -2
  44. package/sdk-core/crates/common/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +4 -0
  45. package/sdk-core/crates/common/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +5 -5
  46. package/sdk-core/crates/common/src/activity_definition.rs +20 -0
  47. package/sdk-core/crates/common/src/data_converters.rs +770 -0
  48. package/sdk-core/crates/common/src/envconfig.rs +5 -0
  49. package/sdk-core/crates/common/src/lib.rs +15 -211
  50. package/sdk-core/crates/common/src/payload_visitor.rs +648 -0
  51. package/sdk-core/crates/common/src/priority.rs +110 -0
  52. package/sdk-core/crates/common/src/protos/canned_histories.rs +3 -0
  53. package/sdk-core/crates/common/src/protos/history_builder.rs +45 -0
  54. package/sdk-core/crates/common/src/protos/history_info.rs +2 -0
  55. package/sdk-core/crates/common/src/protos/mod.rs +122 -27
  56. package/sdk-core/crates/common/src/protos/task_token.rs +3 -3
  57. package/sdk-core/crates/common/src/protos/utilities.rs +11 -0
  58. package/sdk-core/crates/{sdk-core → common}/src/telemetry/log_export.rs +5 -7
  59. package/sdk-core/crates/common/src/telemetry/metrics/core.rs +125 -0
  60. package/sdk-core/crates/common/src/telemetry/metrics.rs +268 -223
  61. package/sdk-core/crates/{sdk-core → common}/src/telemetry/otel.rs +8 -13
  62. package/sdk-core/crates/{sdk-core → common}/src/telemetry/prometheus_meter.rs +49 -50
  63. package/sdk-core/crates/{sdk-core → common}/src/telemetry/prometheus_server.rs +2 -3
  64. package/sdk-core/crates/common/src/telemetry.rs +264 -4
  65. package/sdk-core/crates/common/src/worker.rs +68 -603
  66. package/sdk-core/crates/common/src/workflow_definition.rs +60 -0
  67. package/sdk-core/crates/macros/Cargo.toml +5 -1
  68. package/sdk-core/crates/macros/src/activities_definitions.rs +585 -0
  69. package/sdk-core/crates/macros/src/fsm_impl.rs +507 -0
  70. package/sdk-core/crates/macros/src/lib.rs +138 -512
  71. package/sdk-core/crates/macros/src/macro_utils.rs +106 -0
  72. package/sdk-core/crates/macros/src/workflow_definitions.rs +1224 -0
  73. package/sdk-core/crates/sdk/Cargo.toml +19 -6
  74. package/sdk-core/crates/sdk/README.md +415 -0
  75. package/sdk-core/crates/sdk/src/activities.rs +417 -0
  76. package/sdk-core/crates/sdk/src/interceptors.rs +1 -1
  77. package/sdk-core/crates/sdk/src/lib.rs +757 -442
  78. package/sdk-core/crates/sdk/src/workflow_context/options.rs +45 -35
  79. package/sdk-core/crates/sdk/src/workflow_context.rs +1033 -289
  80. package/sdk-core/crates/sdk/src/workflow_future.rs +277 -213
  81. package/sdk-core/crates/sdk/src/workflows.rs +711 -0
  82. package/sdk-core/crates/sdk-core/Cargo.toml +57 -64
  83. package/sdk-core/crates/sdk-core/benches/workflow_replay_bench.rs +41 -35
  84. package/sdk-core/crates/sdk-core/machine_coverage/ActivityMachine_Coverage.puml +1 -1
  85. package/sdk-core/crates/sdk-core/src/abstractions.rs +6 -10
  86. package/sdk-core/crates/sdk-core/src/core_tests/activity_tasks.rs +6 -5
  87. package/sdk-core/crates/sdk-core/src/core_tests/mod.rs +13 -15
  88. package/sdk-core/crates/sdk-core/src/core_tests/queries.rs +21 -25
  89. package/sdk-core/crates/sdk-core/src/core_tests/replay_flag.rs +7 -10
  90. package/sdk-core/crates/sdk-core/src/core_tests/updates.rs +14 -17
  91. package/sdk-core/crates/sdk-core/src/core_tests/workers.rs +493 -26
  92. package/sdk-core/crates/sdk-core/src/core_tests/workflow_tasks.rs +4 -8
  93. package/sdk-core/crates/sdk-core/src/ephemeral_server/mod.rs +7 -7
  94. package/sdk-core/crates/sdk-core/src/histfetch.rs +20 -10
  95. package/sdk-core/crates/sdk-core/src/lib.rs +41 -111
  96. package/sdk-core/crates/sdk-core/src/pollers/mod.rs +4 -9
  97. package/sdk-core/crates/sdk-core/src/pollers/poll_buffer.rs +118 -19
  98. package/sdk-core/crates/sdk-core/src/protosext/mod.rs +2 -2
  99. package/sdk-core/crates/sdk-core/src/replay/mod.rs +14 -5
  100. package/sdk-core/crates/sdk-core/src/telemetry/metrics.rs +179 -196
  101. package/sdk-core/crates/sdk-core/src/telemetry/mod.rs +3 -280
  102. package/sdk-core/crates/sdk-core/src/test_help/integ_helpers.rs +6 -9
  103. package/sdk-core/crates/sdk-core/src/test_help/unit_helpers.rs +3 -6
  104. package/sdk-core/crates/sdk-core/src/worker/activities/local_activities.rs +11 -14
  105. package/sdk-core/crates/sdk-core/src/worker/activities.rs +16 -19
  106. package/sdk-core/crates/sdk-core/src/worker/client/mocks.rs +9 -5
  107. package/sdk-core/crates/sdk-core/src/worker/client.rs +103 -81
  108. package/sdk-core/crates/sdk-core/src/worker/heartbeat.rs +7 -11
  109. package/sdk-core/crates/sdk-core/src/worker/mod.rs +1124 -229
  110. package/sdk-core/crates/sdk-core/src/worker/nexus.rs +145 -23
  111. package/sdk-core/crates/sdk-core/src/worker/slot_provider.rs +2 -2
  112. package/sdk-core/crates/sdk-core/src/worker/tuner/fixed_size.rs +2 -2
  113. package/sdk-core/crates/sdk-core/src/worker/tuner/resource_based.rs +13 -13
  114. package/sdk-core/crates/sdk-core/src/worker/tuner.rs +28 -8
  115. package/sdk-core/crates/sdk-core/src/worker/workflow/driven_workflow.rs +9 -3
  116. package/sdk-core/crates/sdk-core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +21 -22
  117. package/sdk-core/crates/sdk-core/src/worker/workflow/machines/workflow_machines.rs +19 -4
  118. package/sdk-core/crates/sdk-core/src/worker/workflow/managed_run.rs +14 -18
  119. package/sdk-core/crates/sdk-core/src/worker/workflow/mod.rs +4 -6
  120. package/sdk-core/crates/sdk-core/src/worker/workflow/run_cache.rs +4 -7
  121. package/sdk-core/crates/sdk-core/src/worker/workflow/wft_extraction.rs +2 -4
  122. package/sdk-core/crates/sdk-core/src/worker/workflow/wft_poller.rs +8 -9
  123. package/sdk-core/crates/sdk-core/src/worker/workflow/workflow_stream.rs +1 -3
  124. package/sdk-core/crates/sdk-core/tests/activities_procmacro.rs +6 -0
  125. package/sdk-core/crates/sdk-core/tests/activities_trybuild/basic_pass.rs +54 -0
  126. package/sdk-core/crates/sdk-core/tests/activities_trybuild/invalid_self_type_fail.rs +18 -0
  127. package/sdk-core/crates/sdk-core/tests/activities_trybuild/invalid_self_type_fail.stderr +5 -0
  128. package/sdk-core/crates/sdk-core/tests/activities_trybuild/missing_context_fail.rs +14 -0
  129. package/sdk-core/crates/sdk-core/tests/activities_trybuild/missing_context_fail.stderr +5 -0
  130. package/sdk-core/crates/sdk-core/tests/activities_trybuild/multi_arg_pass.rs +48 -0
  131. package/sdk-core/crates/sdk-core/tests/activities_trybuild/no_input_pass.rs +14 -0
  132. package/sdk-core/crates/sdk-core/tests/activities_trybuild/no_return_type_pass.rs +19 -0
  133. package/sdk-core/crates/sdk-core/tests/cloud_tests.rs +14 -5
  134. package/sdk-core/crates/sdk-core/tests/common/activity_functions.rs +55 -0
  135. package/sdk-core/crates/sdk-core/tests/common/mod.rs +241 -196
  136. package/sdk-core/crates/sdk-core/tests/common/workflows.rs +41 -28
  137. package/sdk-core/crates/sdk-core/tests/global_metric_tests.rs +3 -5
  138. package/sdk-core/crates/sdk-core/tests/heavy_tests/fuzzy_workflow.rs +73 -64
  139. package/sdk-core/crates/sdk-core/tests/heavy_tests.rs +298 -252
  140. package/sdk-core/crates/sdk-core/tests/integ_tests/async_activity_client_tests.rs +230 -0
  141. package/sdk-core/crates/sdk-core/tests/integ_tests/client_tests.rs +94 -57
  142. package/sdk-core/crates/sdk-core/tests/integ_tests/data_converter_tests.rs +381 -0
  143. package/sdk-core/crates/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +16 -12
  144. package/sdk-core/crates/sdk-core/tests/integ_tests/heartbeat_tests.rs +48 -40
  145. package/sdk-core/crates/sdk-core/tests/integ_tests/metrics_tests.rs +327 -255
  146. package/sdk-core/crates/sdk-core/tests/integ_tests/pagination_tests.rs +50 -45
  147. package/sdk-core/crates/sdk-core/tests/integ_tests/polling_tests.rs +147 -126
  148. package/sdk-core/crates/sdk-core/tests/integ_tests/queries_tests.rs +103 -89
  149. package/sdk-core/crates/sdk-core/tests/integ_tests/update_tests.rs +609 -453
  150. package/sdk-core/crates/sdk-core/tests/integ_tests/visibility_tests.rs +80 -62
  151. package/sdk-core/crates/sdk-core/tests/integ_tests/worker_heartbeat_tests.rs +360 -231
  152. package/sdk-core/crates/sdk-core/tests/integ_tests/worker_tests.rs +248 -185
  153. package/sdk-core/crates/sdk-core/tests/integ_tests/worker_versioning_tests.rs +52 -43
  154. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_client_tests.rs +180 -0
  155. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/activities.rs +428 -315
  156. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +82 -56
  157. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +56 -28
  158. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +364 -243
  159. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/client_interactions.rs +552 -0
  160. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +101 -42
  161. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +243 -147
  162. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/eager.rs +98 -28
  163. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +1475 -1036
  164. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +73 -41
  165. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/nexus.rs +397 -238
  166. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/patches.rs +414 -189
  167. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/queries.rs +415 -0
  168. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/replay.rs +96 -36
  169. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/resets.rs +154 -137
  170. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/signals.rs +183 -105
  171. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +85 -38
  172. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/timers.rs +142 -40
  173. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +73 -54
  174. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests.rs +363 -226
  175. package/sdk-core/crates/sdk-core/tests/main.rs +17 -15
  176. package/sdk-core/crates/sdk-core/tests/manual_tests.rs +207 -152
  177. package/sdk-core/crates/sdk-core/tests/shared_tests/mod.rs +65 -34
  178. package/sdk-core/crates/sdk-core/tests/shared_tests/priority.rs +107 -84
  179. package/sdk-core/crates/sdk-core/tests/workflows_procmacro.rs +6 -0
  180. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/async_query_fail.rs +26 -0
  181. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/async_query_fail.stderr +5 -0
  182. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/basic_pass.rs +49 -0
  183. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/minimal_pass.rs +21 -0
  184. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/mut_query_fail.rs +26 -0
  185. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/mut_query_fail.stderr +5 -0
  186. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/sync_run_fail.rs +21 -0
  187. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/sync_run_fail.stderr +5 -0
  188. package/sdk-core/crates/sdk-core-c-bridge/Cargo.toml +7 -1
  189. package/sdk-core/crates/sdk-core-c-bridge/include/temporal-sdk-core-c-bridge.h +14 -14
  190. package/sdk-core/crates/sdk-core-c-bridge/src/client.rs +83 -74
  191. package/sdk-core/crates/sdk-core-c-bridge/src/metric.rs +9 -14
  192. package/sdk-core/crates/sdk-core-c-bridge/src/runtime.rs +1 -2
  193. package/sdk-core/crates/sdk-core-c-bridge/src/tests/context.rs +13 -13
  194. package/sdk-core/crates/sdk-core-c-bridge/src/tests/mod.rs +6 -6
  195. package/sdk-core/crates/sdk-core-c-bridge/src/tests/utils.rs +3 -4
  196. package/sdk-core/crates/sdk-core-c-bridge/src/worker.rs +62 -75
  197. package/sdk-core/rustfmt.toml +2 -1
  198. package/src/client.rs +205 -318
  199. package/src/metrics.rs +22 -30
  200. package/src/runtime.rs +4 -5
  201. package/src/worker.rs +16 -19
  202. package/ts/native.ts +1 -1
  203. package/sdk-core/crates/client/src/workflow_handle/mod.rs +0 -212
  204. package/sdk-core/crates/common/src/errors.rs +0 -85
  205. package/sdk-core/crates/common/tests/worker_task_types_test.rs +0 -129
  206. package/sdk-core/crates/sdk/src/activity_context.rs +0 -238
  207. package/sdk-core/crates/sdk/src/app_data.rs +0 -37
  208. package/sdk-core/crates/sdk-core/tests/integ_tests/activity_functions.rs +0 -5
  209. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +0 -61
@@ -0,0 +1,381 @@
1
+ use crate::common::{CoreWfStarter, get_integ_connection, integ_namespace};
2
+ use futures::{FutureExt, future::BoxFuture};
3
+ use std::{
4
+ sync::{
5
+ Arc,
6
+ atomic::{AtomicUsize, Ordering},
7
+ },
8
+ time::Duration,
9
+ };
10
+ use temporalio_client::{Client, ClientOptions, UntypedWorkflow, WorkflowStartOptions};
11
+ use temporalio_common::{
12
+ data_converters::{
13
+ DataConverter, DefaultFailureConverter, MultiArgs2, PayloadCodec, PayloadConversionError,
14
+ PayloadConverter, SerializationContext, SerializationContextData, TemporalDeserializable,
15
+ TemporalSerializable,
16
+ },
17
+ protos::temporal::api::{common::v1::Payload, history::v1::history_event::Attributes},
18
+ worker::WorkerTaskTypes,
19
+ };
20
+ use temporalio_macros::{activities, workflow, workflow_methods};
21
+ use temporalio_sdk::{
22
+ ActivityOptions, WorkflowContext, WorkflowResult,
23
+ activities::{ActivityContext, ActivityError},
24
+ };
25
+
26
+ #[derive(Clone, Debug)]
27
+ struct TrackedWrapper(TrackedValue);
28
+ #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
29
+ struct TrackedValue {
30
+ data: String,
31
+ serialize_count: u32,
32
+ deserialize_count: u32,
33
+ }
34
+
35
+ impl TrackedValue {
36
+ fn new(data: String) -> Self {
37
+ Self {
38
+ data,
39
+ serialize_count: 0,
40
+ deserialize_count: 0,
41
+ }
42
+ }
43
+ }
44
+
45
+ impl TemporalSerializable for TrackedWrapper {
46
+ fn to_payload(&self, _: &SerializationContext<'_>) -> Result<Payload, PayloadConversionError> {
47
+ let mut wire = self.0.clone();
48
+ wire.serialize_count += 1;
49
+ let json = serde_json::to_vec(&wire)
50
+ .map_err(|e| PayloadConversionError::EncodingError(Box::new(e)))?;
51
+ Ok(Payload {
52
+ metadata: {
53
+ let mut hm = std::collections::HashMap::new();
54
+ hm.insert("encoding".to_string(), b"json/plain".to_vec());
55
+ hm
56
+ },
57
+ data: json,
58
+ external_payloads: vec![],
59
+ })
60
+ }
61
+ }
62
+
63
+ impl TemporalDeserializable for TrackedWrapper {
64
+ fn from_payload(
65
+ _: &SerializationContext<'_>,
66
+ payload: Payload,
67
+ ) -> Result<Self, PayloadConversionError> {
68
+ let wire: TrackedValue = serde_json::from_slice(&payload.data)
69
+ .map_err(|e| PayloadConversionError::EncodingError(Box::new(e)))?;
70
+ let mut val = wire.clone();
71
+ val.deserialize_count += 1;
72
+ Ok(TrackedWrapper(val))
73
+ }
74
+ }
75
+
76
+ struct TestActivities;
77
+ #[activities]
78
+ impl TestActivities {
79
+ #[activity]
80
+ async fn process_tracked(
81
+ _ctx: ActivityContext,
82
+ mut input: TrackedWrapper,
83
+ ) -> Result<TrackedWrapper, ActivityError> {
84
+ input.0.data = format!("activity-processed:{}", input.0.data);
85
+ Ok(input)
86
+ }
87
+ }
88
+
89
+ #[workflow]
90
+ #[derive(Default)]
91
+ struct DataConverterTestWorkflow;
92
+ #[workflow_methods]
93
+ impl DataConverterTestWorkflow {
94
+ #[run]
95
+ async fn run(
96
+ ctx: &mut WorkflowContext<Self>,
97
+ input: TrackedWrapper,
98
+ ) -> WorkflowResult<TrackedWrapper> {
99
+ let output = ctx
100
+ .start_activity(
101
+ TestActivities::process_tracked,
102
+ input,
103
+ ActivityOptions {
104
+ start_to_close_timeout: Some(Duration::from_secs(5)),
105
+ ..Default::default()
106
+ },
107
+ )
108
+ .await
109
+ .map_err(|e| anyhow::anyhow!("{e}"))?;
110
+
111
+ Ok(output)
112
+ }
113
+ }
114
+
115
+ #[tokio::test]
116
+ async fn data_converter_tracks_serialization_points() {
117
+ let wf_name = DataConverterTestWorkflow::name();
118
+ let mut starter = CoreWfStarter::new(wf_name);
119
+ starter.sdk_config.register_activities(TestActivities);
120
+ starter
121
+ .sdk_config
122
+ .register_workflow::<DataConverterTestWorkflow>();
123
+ let mut worker = starter.worker().await;
124
+
125
+ let input = TrackedValue::new("test-input".to_string());
126
+ assert_eq!(input.serialize_count, 0);
127
+ assert_eq!(input.deserialize_count, 0);
128
+
129
+ let task_queue = starter.get_task_queue().to_owned();
130
+ let handle = worker
131
+ .submit_workflow(
132
+ DataConverterTestWorkflow::run,
133
+ TrackedWrapper(input),
134
+ WorkflowStartOptions::new(task_queue, wf_name.to_owned()).build(),
135
+ )
136
+ .await
137
+ .unwrap();
138
+ worker.run_until_done().await.unwrap();
139
+
140
+ let output = handle.get_result(Default::default()).await.unwrap().0;
141
+
142
+ assert!(
143
+ output.data.contains("activity-processed:test-input"),
144
+ "Activity should have processed the input, got: {}",
145
+ output.data
146
+ );
147
+
148
+ // Expected path:
149
+ // 1. Client serializes input (serialize_count: 0 -> 1)
150
+ // 2. Workflow deserializes input (deserialize_count: 0 -> 1)
151
+ // 3. Workflow serializes for activity call (serialize_count: 1 -> 2)
152
+ // 4. Activity deserializes input (deserialize_count: 1 -> 2)
153
+ // 5. Activity serializes result (serialize_count: 2 -> 3)
154
+ // 6. Workflow deserializes activity result (deserialize_count: 2 -> 3)
155
+ // 7. Workflow serializes final result (serialize_count: 3 -> 4)
156
+ // 8. Client deserializes result (deserialize_count: 3 -> 4)
157
+
158
+ assert!(
159
+ output.serialize_count == 4,
160
+ "Value should have been serialized 4 times, was serialized {} times",
161
+ output.serialize_count
162
+ );
163
+ assert!(
164
+ output.deserialize_count == 4,
165
+ "Value should have been deserialized 4 times, was deserialized {} times",
166
+ output.deserialize_count
167
+ );
168
+ }
169
+
170
+ #[workflow]
171
+ #[derive(Default)]
172
+ struct MultiArgs2Workflow;
173
+ #[workflow_methods]
174
+ impl MultiArgs2Workflow {
175
+ #[run]
176
+ async fn run(
177
+ _ctx: &mut WorkflowContext<Self>,
178
+ input: MultiArgs2<String, i32>,
179
+ ) -> WorkflowResult<String> {
180
+ Ok(format!("received: {} and {}", input.0, input.1))
181
+ }
182
+ }
183
+
184
+ #[tokio::test]
185
+ async fn multi_args_serializes_as_multiple_payloads() {
186
+ let wf_name = MultiArgs2Workflow::name();
187
+ let mut starter = CoreWfStarter::new(wf_name);
188
+ starter.sdk_config.register_workflow::<MultiArgs2Workflow>();
189
+ starter.sdk_config.task_types = WorkerTaskTypes::workflow_only();
190
+ let mut worker = starter.worker().await;
191
+
192
+ let input = MultiArgs2("hello".to_string(), 42);
193
+
194
+ let task_queue = starter.get_task_queue().to_owned();
195
+ let handle = worker
196
+ .submit_workflow(
197
+ MultiArgs2Workflow::run,
198
+ input,
199
+ WorkflowStartOptions::new(task_queue, wf_name.to_owned()).build(),
200
+ )
201
+ .await
202
+ .unwrap();
203
+ worker.run_until_done().await.unwrap();
204
+
205
+ let output = handle.get_result(Default::default()).await.unwrap();
206
+ assert_eq!(output, "received: hello and 42");
207
+
208
+ // Verify the workflow history contains multiple payloads in the input
209
+ let client = starter.get_client().await;
210
+ let events = client
211
+ .get_workflow_handle::<UntypedWorkflow>(wf_name)
212
+ .fetch_history(Default::default())
213
+ .await
214
+ .unwrap()
215
+ .into_events();
216
+
217
+ let workflow_started_event = events
218
+ .iter()
219
+ .find_map(|e| {
220
+ if let Attributes::WorkflowExecutionStartedEventAttributes(attrs) =
221
+ e.attributes.as_ref().unwrap()
222
+ {
223
+ Some(attrs)
224
+ } else {
225
+ None
226
+ }
227
+ })
228
+ .expect("Should find WorkflowExecutionStarted event");
229
+
230
+ let input_payloads = workflow_started_event
231
+ .input
232
+ .as_ref()
233
+ .expect("Should have input payloads");
234
+
235
+ assert_eq!(
236
+ input_payloads.payloads.len(),
237
+ 2,
238
+ "MultiArgs2<A, B> should produce 2 payloads, got {}",
239
+ input_payloads.payloads.len()
240
+ );
241
+
242
+ // Verify the content of each payload
243
+ let first_payload_data: String =
244
+ serde_json::from_slice(&input_payloads.payloads[0].data).unwrap();
245
+ assert_eq!(first_payload_data, "hello");
246
+
247
+ let second_payload_data: i32 =
248
+ serde_json::from_slice(&input_payloads.payloads[1].data).unwrap();
249
+ assert_eq!(second_payload_data, 42);
250
+ }
251
+
252
+ /// A codec that XORs payload data with a key and tracks encode/decode operations.
253
+ struct XorCodec {
254
+ key: u8,
255
+ encode_count: AtomicUsize,
256
+ decode_count: AtomicUsize,
257
+ }
258
+
259
+ impl XorCodec {
260
+ fn new(key: u8) -> Self {
261
+ Self {
262
+ key,
263
+ encode_count: AtomicUsize::new(0),
264
+ decode_count: AtomicUsize::new(0),
265
+ }
266
+ }
267
+
268
+ fn encode_count(&self) -> usize {
269
+ self.encode_count.load(Ordering::SeqCst)
270
+ }
271
+
272
+ fn decode_count(&self) -> usize {
273
+ self.decode_count.load(Ordering::SeqCst)
274
+ }
275
+ }
276
+
277
+ impl PayloadCodec for XorCodec {
278
+ fn encode(
279
+ &self,
280
+ _context: &SerializationContextData,
281
+ payloads: Vec<Payload>,
282
+ ) -> BoxFuture<'static, Vec<Payload>> {
283
+ let count = payloads.len();
284
+ eprintln!("XorCodec::encode called with {} payloads", count);
285
+ self.encode_count.fetch_add(count, Ordering::SeqCst);
286
+ let key = self.key;
287
+ async move {
288
+ payloads
289
+ .into_iter()
290
+ .map(|mut p| {
291
+ p.data = p.data.iter().map(|b| b ^ key).collect();
292
+ p.metadata.insert("xor_encoded".to_string(), vec![key]);
293
+ p
294
+ })
295
+ .collect()
296
+ }
297
+ .boxed()
298
+ }
299
+
300
+ fn decode(
301
+ &self,
302
+ _context: &SerializationContextData,
303
+ payloads: Vec<Payload>,
304
+ ) -> BoxFuture<'static, Vec<Payload>> {
305
+ let count = payloads.len();
306
+ eprintln!("XorCodec::decode called with {} payloads", count);
307
+ self.decode_count.fetch_add(count, Ordering::SeqCst);
308
+ let key = self.key;
309
+ async move {
310
+ payloads
311
+ .into_iter()
312
+ .map(|mut p| {
313
+ if p.metadata.remove("xor_encoded").is_some() {
314
+ p.data = p.data.iter().map(|b| b ^ key).collect();
315
+ }
316
+ p
317
+ })
318
+ .collect()
319
+ }
320
+ .boxed()
321
+ }
322
+ }
323
+
324
+ #[tokio::test]
325
+ async fn codec_encodes_and_decodes_payloads() {
326
+ let wf_name = DataConverterTestWorkflow::name();
327
+ let codec = Arc::new(XorCodec::new(0x42));
328
+
329
+ // Create a client with our custom codec
330
+ let connection = get_integ_connection(None).await;
331
+ let data_converter = DataConverter::new(
332
+ PayloadConverter::default(),
333
+ DefaultFailureConverter,
334
+ codec.clone(),
335
+ );
336
+ let client_opts = ClientOptions::new(integ_namespace())
337
+ .data_converter(data_converter)
338
+ .build();
339
+ let client = Client::new(connection, client_opts).unwrap();
340
+
341
+ let mut starter = CoreWfStarter::new_with_overrides(wf_name, None, Some(client));
342
+ starter.sdk_config.register_activities(TestActivities);
343
+ starter.sdk_config.task_types = WorkerTaskTypes::all();
344
+ starter
345
+ .sdk_config
346
+ .register_workflow::<DataConverterTestWorkflow>();
347
+ // Use task queue name as workflow ID to avoid collisions with parallel tests
348
+ let wf_id = starter.get_task_queue().to_owned();
349
+ let mut worker = starter.worker().await;
350
+
351
+ let input = TrackedValue::new("codec-test".to_string());
352
+ let task_queue = starter.get_task_queue().to_owned();
353
+ let handle = worker
354
+ .submit_workflow(
355
+ DataConverterTestWorkflow::run,
356
+ TrackedWrapper(input),
357
+ WorkflowStartOptions::new(task_queue, wf_id).build(),
358
+ )
359
+ .await
360
+ .unwrap();
361
+ worker.run_until_done().await.unwrap();
362
+
363
+ let output = handle.get_result(Default::default()).await.unwrap().0;
364
+
365
+ // Verify the workflow processed correctly (activity echoed the data)
366
+ assert!(
367
+ output.data.contains("activity-processed:codec-test"),
368
+ "Activity should have processed the input, got: {}",
369
+ output.data
370
+ );
371
+
372
+ // Verify the codec was used for both encoding and decoding
373
+ assert!(
374
+ codec.encode_count() > 0,
375
+ "Codec should have encoded payloads, but encode_count was 0"
376
+ );
377
+ assert!(
378
+ codec.decode_count() > 0,
379
+ "Codec should have decoded payloads, but decode_count was 0"
380
+ );
381
+ }
@@ -1,7 +1,10 @@
1
1
  use crate::common::{INTEG_CLIENT_IDENTITY, INTEG_CLIENT_NAME, INTEG_CLIENT_VERSION, NAMESPACE};
2
2
  use futures_util::{TryStreamExt, stream};
3
3
  use std::time::{SystemTime, UNIX_EPOCH};
4
- use temporalio_client::{ClientOptions, TestService, WorkflowService};
4
+ use temporalio_client::{
5
+ Connection, ConnectionOptions,
6
+ grpc::{TestService, WorkflowService},
7
+ };
5
8
  use temporalio_common::protos::temporal::api::workflowservice::v1::DescribeNamespaceRequest;
6
9
  use temporalio_sdk_core::ephemeral_server::{
7
10
  EphemeralExe, EphemeralExeVersion, EphemeralServer, TemporalDevServerConfig,
@@ -132,16 +135,14 @@ fn fixed_cached_download(version: &str) -> EphemeralExe {
132
135
 
133
136
  async fn assert_ephemeral_server(server: &EphemeralServer) {
134
137
  // Connect and describe namespace
135
- let mut client = ClientOptions::builder()
136
- .identity(INTEG_CLIENT_IDENTITY.to_string())
137
- .target_url(Url::try_from(&*format!("http://{}", server.target)).unwrap())
138
- .client_name(INTEG_CLIENT_NAME.to_string())
139
- .client_version(INTEG_CLIENT_VERSION.to_string())
140
- .build()
141
- .connect_no_namespace(None)
142
- .await
143
- .unwrap();
144
- let resp = client
138
+ let connection_opts =
139
+ ConnectionOptions::new(Url::try_from(&*format!("http://{}", server.target)).unwrap())
140
+ .identity(INTEG_CLIENT_IDENTITY.to_string())
141
+ .client_name(INTEG_CLIENT_NAME.to_string())
142
+ .client_version(INTEG_CLIENT_VERSION.to_string())
143
+ .build();
144
+ let mut connection = Connection::connect(connection_opts).await.unwrap();
145
+ let resp = connection
145
146
  .describe_namespace(
146
147
  DescribeNamespaceRequest {
147
148
  namespace: NAMESPACE.to_string(),
@@ -155,7 +156,10 @@ async fn assert_ephemeral_server(server: &EphemeralServer) {
155
156
 
156
157
  // If it has test service, make sure we can use it too
157
158
  if server.has_test_service {
158
- let resp = client.get_current_time(().into_request()).await.unwrap();
159
+ let resp = connection
160
+ .get_current_time(().into_request())
161
+ .await
162
+ .unwrap();
159
163
  // Make sure it's within 5 mins of now
160
164
  let resp_seconds = resp.get_ref().time.as_ref().unwrap().seconds as u64;
161
165
  let curr_seconds = SystemTime::now()
@@ -1,13 +1,13 @@
1
- use crate::common::{CoreWfStarter, init_core_and_create_wf};
1
+ use crate::common::{CoreWfStarter, activity_functions::StdActivities, init_core_and_create_wf};
2
2
  use assert_matches::assert_matches;
3
3
  use std::time::Duration;
4
- use temporalio_client::{WfClientExt, WorkflowOptions};
4
+ use temporalio_client::WorkflowStartOptions;
5
5
  use temporalio_common::{
6
6
  prost_dur,
7
7
  protos::{
8
8
  DEFAULT_ACTIVITY_TYPE,
9
9
  coresdk::{
10
- ActivityHeartbeat, ActivityTaskCompletion, AsJsonPayloadExt, IntoCompletion,
10
+ ActivityHeartbeat, ActivityTaskCompletion, IntoCompletion,
11
11
  activity_result::{
12
12
  self, ActivityExecutionResult, ActivityResolution, activity_resolution as act_res,
13
13
  },
@@ -25,10 +25,44 @@ use temporalio_common::{
25
25
  test_utils::schedule_activity_cmd,
26
26
  },
27
27
  };
28
- use temporalio_sdk::{ActContext, ActivityOptions, WfContext};
28
+ use temporalio_macros::{workflow, workflow_methods};
29
+ use temporalio_sdk::{ActivityExecutionError, ActivityOptions, WorkflowContext, WorkflowResult};
29
30
  use temporalio_sdk_core::test_help::{WorkerTestHelpers, drain_pollers_and_shutdown};
30
31
  use tokio::time::sleep;
31
32
 
33
+ #[workflow]
34
+ #[derive(Default)]
35
+ struct ActivityDoesntHeartbeatHitsTimeoutThenCompletesWf;
36
+
37
+ #[workflow_methods]
38
+ impl ActivityDoesntHeartbeatHitsTimeoutThenCompletesWf {
39
+ #[run]
40
+ async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
41
+ let res: Result<(), ActivityExecutionError> = ctx
42
+ .start_activity(
43
+ StdActivities::delay,
44
+ Duration::from_secs(4),
45
+ ActivityOptions {
46
+ start_to_close_timeout: Some(Duration::from_secs(10)),
47
+ heartbeat_timeout: Some(Duration::from_secs(2)),
48
+ retry_policy: Some(RetryPolicy {
49
+ maximum_attempts: 1,
50
+ ..Default::default()
51
+ }),
52
+ ..Default::default()
53
+ },
54
+ )
55
+ .await;
56
+ let err = res.unwrap_err();
57
+ if let ActivityExecutionError::Failed(f) = &err {
58
+ assert_eq!(f.is_timeout(), Some(TimeoutType::Heartbeat));
59
+ } else {
60
+ panic!("expected Failed, got {err:?}");
61
+ }
62
+ Ok(())
63
+ }
64
+ }
65
+
32
66
  #[tokio::test]
33
67
  async fn activity_heartbeat() {
34
68
  let mut starter = init_core_and_create_wf("activity_heartbeat").await;
@@ -184,46 +218,20 @@ async fn many_act_fails_with_heartbeats() {
184
218
  async fn activity_doesnt_heartbeat_hits_timeout_then_completes() {
185
219
  let wf_name = "activity_doesnt_heartbeat_hits_timeout_then_completes";
186
220
  let mut starter = CoreWfStarter::new(wf_name);
221
+ starter.sdk_config.register_activities(StdActivities);
187
222
  let mut worker = starter.worker().await;
188
- let client = starter.get_client().await;
189
- worker.register_activity(
190
- "echo_activity",
191
- |_ctx: ActContext, echo_me: String| async move {
192
- sleep(Duration::from_secs(4)).await;
193
- Ok(echo_me)
194
- },
195
- );
196
- worker.register_wf(wf_name.to_owned(), |ctx: WfContext| async move {
197
- let res = ctx
198
- .activity(ActivityOptions {
199
- activity_type: "echo_activity".to_string(),
200
- input: "hi!".as_json_payload().expect("serializes fine"),
201
- start_to_close_timeout: Some(Duration::from_secs(10)),
202
- heartbeat_timeout: Some(Duration::from_secs(2)),
203
- retry_policy: Some(RetryPolicy {
204
- maximum_attempts: 1,
205
- ..Default::default()
206
- }),
207
- ..Default::default()
208
- })
209
- .await;
210
- assert_eq!(res.timed_out(), Some(TimeoutType::Heartbeat));
211
- Ok(().into())
212
- });
213
223
 
214
- let run_id = worker
215
- .submit_wf(
216
- wf_name.to_owned(),
217
- wf_name.to_owned(),
218
- vec![],
219
- WorkflowOptions::default(),
224
+ worker.register_workflow::<ActivityDoesntHeartbeatHitsTimeoutThenCompletesWf>();
225
+
226
+ let task_queue = starter.get_task_queue().to_owned();
227
+ let handle = worker
228
+ .submit_workflow(
229
+ ActivityDoesntHeartbeatHitsTimeoutThenCompletesWf::run,
230
+ (),
231
+ WorkflowStartOptions::new(task_queue, wf_name.to_owned()).build(),
220
232
  )
221
233
  .await
222
234
  .unwrap();
223
235
  worker.run_until_done().await.unwrap();
224
- let handle = client.get_untyped_workflow_handle(wf_name, run_id);
225
- handle
226
- .get_workflow_result(Default::default())
227
- .await
228
- .unwrap();
236
+ handle.get_result(Default::default()).await.unwrap();
229
237
  }