@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,826 @@
1
+ use crate::{
2
+ NamespacedClient, WorkflowCancelOptions, WorkflowDescribeOptions, WorkflowExecuteUpdateOptions,
3
+ WorkflowFetchHistoryOptions, WorkflowGetResultOptions, WorkflowQueryOptions,
4
+ WorkflowSignalOptions, WorkflowStartUpdateOptions, WorkflowTerminateOptions,
5
+ WorkflowUpdateWaitStage,
6
+ errors::{
7
+ WorkflowGetResultError, WorkflowInteractionError, WorkflowQueryError, WorkflowUpdateError,
8
+ },
9
+ grpc::WorkflowService,
10
+ };
11
+ use std::{fmt::Debug, marker::PhantomData};
12
+ use temporalio_common::{
13
+ QueryDefinition, SignalDefinition, UpdateDefinition, WorkflowDefinition,
14
+ data_converters::{RawValue, SerializationContextData},
15
+ protos::{
16
+ coresdk::FromPayloadsExt,
17
+ temporal::api::{
18
+ common::v1::{Payload, Payloads, WorkflowExecution as ProtoWorkflowExecution},
19
+ enums::v1::{HistoryEventFilterType, UpdateWorkflowExecutionLifecycleStage},
20
+ failure::v1::Failure,
21
+ history::{
22
+ self,
23
+ v1::{HistoryEvent, history_event::Attributes},
24
+ },
25
+ query::v1::WorkflowQuery,
26
+ update::{self, v1::WaitPolicy},
27
+ workflowservice::v1::{
28
+ DescribeWorkflowExecutionRequest, DescribeWorkflowExecutionResponse,
29
+ GetWorkflowExecutionHistoryRequest, PollWorkflowExecutionUpdateRequest,
30
+ QueryWorkflowRequest, RequestCancelWorkflowExecutionRequest,
31
+ SignalWorkflowExecutionRequest, TerminateWorkflowExecutionRequest,
32
+ UpdateWorkflowExecutionRequest,
33
+ },
34
+ },
35
+ },
36
+ };
37
+ use tonic::IntoRequest;
38
+ use uuid::Uuid;
39
+
40
+ /// Enumerates terminal states for a particular workflow execution
41
+ #[derive(Debug)]
42
+ #[allow(clippy::large_enum_variant)]
43
+ pub enum WorkflowExecutionResult<T> {
44
+ /// The workflow finished successfully
45
+ Succeeded(T),
46
+ /// The workflow finished in failure
47
+ Failed(Failure),
48
+ /// The workflow was cancelled
49
+ Cancelled {
50
+ /// Details provided at cancellation time
51
+ details: Vec<Payload>,
52
+ },
53
+ /// The workflow was terminated
54
+ Terminated {
55
+ /// Details provided at termination time
56
+ details: Vec<Payload>,
57
+ },
58
+ /// The workflow timed out
59
+ TimedOut,
60
+ /// The workflow continued as new
61
+ ContinuedAsNew,
62
+ }
63
+
64
+ /// Description of a workflow execution returned by `WorkflowHandle::describe`.
65
+ #[derive(Debug, Clone)]
66
+ pub struct WorkflowExecutionDescription {
67
+ /// The raw proto response from the server.
68
+ pub raw_description: DescribeWorkflowExecutionResponse,
69
+ }
70
+
71
+ impl WorkflowExecutionDescription {
72
+ fn new(raw_description: DescribeWorkflowExecutionResponse) -> Self {
73
+ Self { raw_description }
74
+ }
75
+ }
76
+
77
+ // TODO [rust-sdk-branch]: Could implment stream a-la ListWorkflowsStream
78
+ /// Workflow execution history returned by `WorkflowHandle::fetch_history`.
79
+ #[derive(Debug, Clone)]
80
+ pub struct WorkflowHistory {
81
+ events: Vec<HistoryEvent>,
82
+ }
83
+ impl From<WorkflowHistory> for history::v1::History {
84
+ fn from(h: WorkflowHistory) -> Self {
85
+ Self { events: h.events }
86
+ }
87
+ }
88
+
89
+ impl WorkflowHistory {
90
+ fn new(events: Vec<HistoryEvent>) -> Self {
91
+ Self { events }
92
+ }
93
+
94
+ /// The history events.
95
+ pub fn events(&self) -> &[HistoryEvent] {
96
+ &self.events
97
+ }
98
+
99
+ /// Consume the history and return the events.
100
+ pub fn into_events(self) -> Vec<HistoryEvent> {
101
+ self.events
102
+ }
103
+ }
104
+
105
+ /// A workflow handle which can refer to a specific workflow run, or a chain of workflow runs with
106
+ /// the same workflow id.
107
+ #[derive(Clone)]
108
+ pub struct WorkflowHandle<ClientT, W> {
109
+ client: ClientT,
110
+ info: WorkflowExecutionInfo,
111
+
112
+ _wf_type: PhantomData<W>,
113
+ }
114
+
115
+ impl<CT, W> WorkflowHandle<CT, W> {
116
+ /// Return the run id of the Workflow Execution pointed at by this handle, if there is one.
117
+ pub fn run_id(&self) -> Option<&str> {
118
+ self.info.run_id.as_deref()
119
+ }
120
+ }
121
+
122
+ /// Holds needed information to refer to a specific workflow run, or workflow execution chain
123
+ #[derive(Debug, Clone)]
124
+ pub struct WorkflowExecutionInfo {
125
+ /// Namespace the workflow lives in.
126
+ pub namespace: String,
127
+ /// The workflow's id.
128
+ pub workflow_id: String,
129
+ /// If set, target this specific run of the workflow.
130
+ pub run_id: Option<String>,
131
+ /// Run ID used for cancellation and termination to ensure they happen on a workflow starting
132
+ /// with this run ID. This can be set when getting a workflow handle. When starting a workflow,
133
+ /// this is set as the resulting run ID if no start signal was provided.
134
+ pub first_execution_run_id: Option<String>,
135
+ }
136
+
137
+ impl WorkflowExecutionInfo {
138
+ /// Bind the workflow info to a specific client, turning it into a workflow handle
139
+ pub fn bind_untyped<CT>(self, client: CT) -> UntypedWorkflowHandle<CT>
140
+ where
141
+ CT: WorkflowService + Clone,
142
+ {
143
+ UntypedWorkflowHandle::new(client, self)
144
+ }
145
+ }
146
+
147
+ /// A workflow handle to a workflow with unknown types. Uses single argument raw payloads for input
148
+ /// and output.
149
+ pub type UntypedWorkflowHandle<CT> = WorkflowHandle<CT, UntypedWorkflow>;
150
+
151
+ /// Marker type for untyped workflow handles. Stores the workflow type name.
152
+ pub struct UntypedWorkflow {
153
+ name: String,
154
+ }
155
+ impl UntypedWorkflow {
156
+ /// Create a new `UntypedWorkflow` with the given workflow type name.
157
+ pub fn new(name: impl Into<String>) -> Self {
158
+ Self { name: name.into() }
159
+ }
160
+ }
161
+ impl WorkflowDefinition for UntypedWorkflow {
162
+ type Input = RawValue;
163
+ type Output = RawValue;
164
+ fn name(&self) -> &str {
165
+ &self.name
166
+ }
167
+ }
168
+
169
+ /// Marker type for sending untyped signals. Stores the signal name for runtime lookup.
170
+ ///
171
+ /// Use with `handle.signal(UntypedSignal::new("signal_name"), raw_payload)`.
172
+ pub struct UntypedSignal<W> {
173
+ name: String,
174
+ _wf: PhantomData<W>,
175
+ }
176
+
177
+ impl<W> UntypedSignal<W> {
178
+ /// Create a new `UntypedSignal` with the given signal name.
179
+ pub fn new(name: impl Into<String>) -> Self {
180
+ Self {
181
+ name: name.into(),
182
+ _wf: PhantomData,
183
+ }
184
+ }
185
+ }
186
+
187
+ impl<W: WorkflowDefinition> SignalDefinition for UntypedSignal<W> {
188
+ type Workflow = W;
189
+ type Input = RawValue;
190
+
191
+ fn name(&self) -> &str {
192
+ &self.name
193
+ }
194
+ }
195
+
196
+ /// Marker type for sending untyped queries. Stores the query name for runtime lookup.
197
+ ///
198
+ /// Use with `handle.query(UntypedQuery::new("query_name"), raw_payload)`.
199
+ pub struct UntypedQuery<W> {
200
+ name: String,
201
+ _wf: PhantomData<W>,
202
+ }
203
+
204
+ impl<W> UntypedQuery<W> {
205
+ /// Create a new `UntypedQuery` with the given query name.
206
+ pub fn new(name: impl Into<String>) -> Self {
207
+ Self {
208
+ name: name.into(),
209
+ _wf: PhantomData,
210
+ }
211
+ }
212
+ }
213
+
214
+ impl<W: WorkflowDefinition> QueryDefinition for UntypedQuery<W> {
215
+ type Workflow = W;
216
+ type Input = RawValue;
217
+ type Output = RawValue;
218
+
219
+ fn name(&self) -> &str {
220
+ &self.name
221
+ }
222
+ }
223
+
224
+ /// Marker type for sending untyped updates. Stores the update name for runtime lookup.
225
+ ///
226
+ /// Use with `handle.update(UntypedUpdate::new("update_name"), raw_payload)`.
227
+ pub struct UntypedUpdate<W> {
228
+ name: String,
229
+ _wf: PhantomData<W>,
230
+ }
231
+
232
+ impl<W> UntypedUpdate<W> {
233
+ /// Create a new `UntypedUpdate` with the given update name.
234
+ pub fn new(name: impl Into<String>) -> Self {
235
+ Self {
236
+ name: name.into(),
237
+ _wf: PhantomData,
238
+ }
239
+ }
240
+ }
241
+
242
+ impl<W: WorkflowDefinition> UpdateDefinition for UntypedUpdate<W> {
243
+ type Workflow = W;
244
+ type Input = RawValue;
245
+ type Output = RawValue;
246
+
247
+ fn name(&self) -> &str {
248
+ &self.name
249
+ }
250
+ }
251
+
252
+ impl<CT, W> WorkflowHandle<CT, W>
253
+ where
254
+ CT: WorkflowService + Clone,
255
+ W: WorkflowDefinition,
256
+ {
257
+ /// Create a workflow handle from a client and identifying information.
258
+ pub fn new(client: CT, info: WorkflowExecutionInfo) -> Self {
259
+ Self {
260
+ client,
261
+ info,
262
+ _wf_type: PhantomData::<W>,
263
+ }
264
+ }
265
+
266
+ /// Get the workflow execution info
267
+ pub fn info(&self) -> &WorkflowExecutionInfo {
268
+ &self.info
269
+ }
270
+
271
+ /// Get the client attached to this handle
272
+ pub fn client(&self) -> &CT {
273
+ &self.client
274
+ }
275
+
276
+ /// Await the result of the workflow execution
277
+ pub async fn get_result(
278
+ &self,
279
+ opts: WorkflowGetResultOptions,
280
+ ) -> Result<W::Output, WorkflowGetResultError>
281
+ where
282
+ CT: WorkflowService + NamespacedClient + Clone,
283
+ {
284
+ let raw = self.get_result_raw(opts).await?;
285
+ match raw {
286
+ WorkflowExecutionResult::Succeeded(v) => Ok(v),
287
+ WorkflowExecutionResult::Failed(f) => Err(WorkflowGetResultError::Failed(Box::new(f))),
288
+ WorkflowExecutionResult::Cancelled { details } => {
289
+ Err(WorkflowGetResultError::Cancelled { details })
290
+ }
291
+ WorkflowExecutionResult::Terminated { details } => {
292
+ Err(WorkflowGetResultError::Terminated { details })
293
+ }
294
+ WorkflowExecutionResult::TimedOut => Err(WorkflowGetResultError::TimedOut),
295
+ WorkflowExecutionResult::ContinuedAsNew => Err(WorkflowGetResultError::ContinuedAsNew),
296
+ }
297
+ }
298
+
299
+ /// Await the result of the workflow execution, returning the full
300
+ /// [`WorkflowExecutionResult`] enum for callers that need to inspect non-success outcomes
301
+ /// directly.
302
+ async fn get_result_raw(
303
+ &self,
304
+ opts: WorkflowGetResultOptions,
305
+ ) -> Result<WorkflowExecutionResult<W::Output>, WorkflowInteractionError>
306
+ where
307
+ CT: WorkflowService + NamespacedClient + Clone,
308
+ {
309
+ let mut run_id = self.info.run_id.clone().unwrap_or_default();
310
+ let fetch_opts = WorkflowFetchHistoryOptions::builder()
311
+ .skip_archival(true)
312
+ .wait_new_event(true)
313
+ .event_filter_type(HistoryEventFilterType::CloseEvent)
314
+ .build();
315
+
316
+ loop {
317
+ let history = self.fetch_history_for_run(&run_id, &fetch_opts).await?;
318
+ let mut events = history.into_events();
319
+
320
+ if events.is_empty() {
321
+ continue;
322
+ }
323
+
324
+ let event_attrs = events.pop().and_then(|ev| ev.attributes);
325
+
326
+ macro_rules! follow {
327
+ ($attrs:ident) => {
328
+ if opts.follow_runs && $attrs.new_execution_run_id != "" {
329
+ run_id = $attrs.new_execution_run_id;
330
+ continue;
331
+ }
332
+ };
333
+ }
334
+
335
+ let dc = self.client.data_converter();
336
+
337
+ break match event_attrs {
338
+ Some(Attributes::WorkflowExecutionCompletedEventAttributes(attrs)) => {
339
+ follow!(attrs);
340
+ let payload = attrs
341
+ .result
342
+ .and_then(|p| p.payloads.into_iter().next())
343
+ .unwrap_or_default();
344
+ let result: W::Output = dc
345
+ .from_payload(&SerializationContextData::Workflow, payload)
346
+ .await?;
347
+ Ok(WorkflowExecutionResult::Succeeded(result))
348
+ }
349
+ Some(Attributes::WorkflowExecutionFailedEventAttributes(attrs)) => {
350
+ follow!(attrs);
351
+ Ok(WorkflowExecutionResult::Failed(
352
+ attrs.failure.unwrap_or_default(),
353
+ ))
354
+ }
355
+ Some(Attributes::WorkflowExecutionCanceledEventAttributes(attrs)) => {
356
+ Ok(WorkflowExecutionResult::Cancelled {
357
+ details: Vec::from_payloads(attrs.details),
358
+ })
359
+ }
360
+ Some(Attributes::WorkflowExecutionTimedOutEventAttributes(attrs)) => {
361
+ follow!(attrs);
362
+ Ok(WorkflowExecutionResult::TimedOut)
363
+ }
364
+ Some(Attributes::WorkflowExecutionTerminatedEventAttributes(attrs)) => {
365
+ Ok(WorkflowExecutionResult::Terminated {
366
+ details: Vec::from_payloads(attrs.details),
367
+ })
368
+ }
369
+ Some(Attributes::WorkflowExecutionContinuedAsNewEventAttributes(attrs)) => {
370
+ if opts.follow_runs {
371
+ if !attrs.new_execution_run_id.is_empty() {
372
+ run_id = attrs.new_execution_run_id;
373
+ continue;
374
+ } else {
375
+ return Err(WorkflowInteractionError::Other(
376
+ "New execution run id was empty in continue as new event!".into(),
377
+ ));
378
+ }
379
+ } else {
380
+ Ok(WorkflowExecutionResult::ContinuedAsNew)
381
+ }
382
+ }
383
+ o => Err(WorkflowInteractionError::Other(
384
+ format!(
385
+ "Server returned an event that didn't match the CloseEvent filter. \
386
+ This is either a server bug or a new event the SDK does not understand. \
387
+ Event details: {o:?}"
388
+ )
389
+ .into(),
390
+ )),
391
+ };
392
+ }
393
+ }
394
+
395
+ /// Send a signal to the workflow
396
+ pub async fn signal<S>(
397
+ &self,
398
+ signal: S,
399
+ input: S::Input,
400
+ opts: WorkflowSignalOptions,
401
+ ) -> Result<(), WorkflowInteractionError>
402
+ where
403
+ CT: WorkflowService + NamespacedClient + Clone,
404
+ S: SignalDefinition<Workflow = W>,
405
+ S::Input: Send,
406
+ {
407
+ let payloads = self
408
+ .client
409
+ .data_converter()
410
+ .to_payloads(&SerializationContextData::Workflow, &input)
411
+ .await?;
412
+ WorkflowService::signal_workflow_execution(
413
+ &mut self.client.clone(),
414
+ SignalWorkflowExecutionRequest {
415
+ namespace: self.client.namespace(),
416
+ workflow_execution: Some(ProtoWorkflowExecution {
417
+ workflow_id: self.info.workflow_id.clone(),
418
+ run_id: self.info.run_id.clone().unwrap_or_default(),
419
+ }),
420
+ signal_name: signal.name().to_string(),
421
+ input: Some(Payloads { payloads }),
422
+ identity: self.client.identity(),
423
+ request_id: opts
424
+ .request_id
425
+ .unwrap_or_else(|| Uuid::new_v4().to_string()),
426
+ header: opts.header,
427
+ ..Default::default()
428
+ }
429
+ .into_request(),
430
+ )
431
+ .await
432
+ .map_err(WorkflowInteractionError::from_status)?;
433
+ Ok(())
434
+ }
435
+
436
+ /// Query the workflow
437
+ pub async fn query<Q>(
438
+ &self,
439
+ query: Q,
440
+ input: Q::Input,
441
+ opts: WorkflowQueryOptions,
442
+ ) -> Result<Q::Output, WorkflowQueryError>
443
+ where
444
+ CT: WorkflowService + NamespacedClient + Clone,
445
+ Q: QueryDefinition<Workflow = W>,
446
+ Q::Input: Send,
447
+ {
448
+ let dc = self.client.data_converter();
449
+ let payloads = dc
450
+ .to_payloads(&SerializationContextData::Workflow, &input)
451
+ .await?;
452
+ let response = self
453
+ .client
454
+ .clone()
455
+ .query_workflow(
456
+ QueryWorkflowRequest {
457
+ namespace: self.client.namespace(),
458
+ execution: Some(ProtoWorkflowExecution {
459
+ workflow_id: self.info.workflow_id.clone(),
460
+ run_id: self.info.run_id.clone().unwrap_or_default(),
461
+ }),
462
+ query: Some(WorkflowQuery {
463
+ query_type: query.name().to_string(),
464
+ query_args: Some(Payloads { payloads }),
465
+ header: opts.header,
466
+ }),
467
+ // Default to None (1) which means don't reject
468
+ query_reject_condition: opts.reject_condition.map(|c| c as i32).unwrap_or(1),
469
+ }
470
+ .into_request(),
471
+ )
472
+ .await
473
+ .map_err(WorkflowQueryError::from_status)?
474
+ .into_inner();
475
+
476
+ if let Some(rejected) = response.query_rejected {
477
+ return Err(WorkflowQueryError::Rejected(rejected));
478
+ }
479
+
480
+ let result_payloads = response
481
+ .query_result
482
+ .map(|p| p.payloads)
483
+ .unwrap_or_default();
484
+
485
+ dc.from_payloads(&SerializationContextData::Workflow, result_payloads)
486
+ .await
487
+ .map_err(WorkflowQueryError::from)
488
+ }
489
+
490
+ /// Send an update to the workflow and wait for it to complete, returning the result.
491
+ pub async fn execute_update<U>(
492
+ &self,
493
+ update: U,
494
+ input: U::Input,
495
+ options: WorkflowExecuteUpdateOptions,
496
+ ) -> Result<U::Output, WorkflowUpdateError>
497
+ where
498
+ CT: WorkflowService + NamespacedClient + Clone,
499
+ U: UpdateDefinition<Workflow = W>,
500
+ U::Input: Send,
501
+ U::Output: 'static,
502
+ {
503
+ let handle = self
504
+ .start_update(
505
+ update,
506
+ input,
507
+ WorkflowStartUpdateOptions::builder()
508
+ .maybe_update_id(options.update_id)
509
+ .maybe_header(options.header)
510
+ .wait_for_stage(WorkflowUpdateWaitStage::Completed)
511
+ .build(),
512
+ )
513
+ .await?;
514
+ handle.get_result().await
515
+ }
516
+
517
+ /// Start an update and return a handle without waiting for completion.
518
+ /// Use `execute_update()` if you want to wait for the result immediately.
519
+ pub async fn start_update<U>(
520
+ &self,
521
+ update: U,
522
+ input: U::Input,
523
+ options: WorkflowStartUpdateOptions,
524
+ ) -> Result<WorkflowUpdateHandle<CT, U::Output>, WorkflowUpdateError>
525
+ where
526
+ CT: WorkflowService + NamespacedClient + Clone,
527
+ U: UpdateDefinition<Workflow = W>,
528
+ U::Input: Send,
529
+ {
530
+ let dc = self.client.data_converter();
531
+ let payloads = dc
532
+ .to_payloads(&SerializationContextData::Workflow, &input)
533
+ .await?;
534
+
535
+ let lifecycle_stage = match options.wait_for_stage {
536
+ WorkflowUpdateWaitStage::Admitted => UpdateWorkflowExecutionLifecycleStage::Admitted,
537
+ WorkflowUpdateWaitStage::Accepted => UpdateWorkflowExecutionLifecycleStage::Accepted,
538
+ WorkflowUpdateWaitStage::Completed => UpdateWorkflowExecutionLifecycleStage::Completed,
539
+ };
540
+
541
+ let update_id = options
542
+ .update_id
543
+ .unwrap_or_else(|| Uuid::new_v4().to_string());
544
+
545
+ let response = WorkflowService::update_workflow_execution(
546
+ &mut self.client.clone(),
547
+ UpdateWorkflowExecutionRequest {
548
+ namespace: self.client.namespace(),
549
+ workflow_execution: Some(ProtoWorkflowExecution {
550
+ workflow_id: self.info().workflow_id.clone(),
551
+ run_id: self.info().run_id.clone().unwrap_or_default(),
552
+ }),
553
+ wait_policy: Some(WaitPolicy {
554
+ lifecycle_stage: lifecycle_stage.into(),
555
+ }),
556
+ request: Some(update::v1::Request {
557
+ meta: Some(update::v1::Meta {
558
+ update_id: update_id.clone(),
559
+ identity: self.client.identity(),
560
+ }),
561
+ input: Some(update::v1::Input {
562
+ header: options.header,
563
+ name: update.name().to_string(),
564
+ args: Some(Payloads { payloads }),
565
+ }),
566
+ }),
567
+ ..Default::default()
568
+ }
569
+ .into_request(),
570
+ )
571
+ .await
572
+ .map_err(WorkflowUpdateError::from_status)?
573
+ .into_inner();
574
+
575
+ // Extract run_id from response if available
576
+ let run_id = response
577
+ .update_ref
578
+ .as_ref()
579
+ .and_then(|r| r.workflow_execution.as_ref())
580
+ .map(|e| e.run_id.clone())
581
+ .filter(|s| !s.is_empty())
582
+ .or_else(|| self.info().run_id.clone());
583
+
584
+ Ok(WorkflowUpdateHandle {
585
+ client: self.client.clone(),
586
+ update_id,
587
+ workflow_id: self.info().workflow_id.clone(),
588
+ run_id,
589
+ known_outcome: response.outcome,
590
+ _output: PhantomData,
591
+ })
592
+ }
593
+
594
+ /// Request cancellation of this workflow.
595
+ pub async fn cancel(&self, opts: WorkflowCancelOptions) -> Result<(), WorkflowInteractionError>
596
+ where
597
+ CT: NamespacedClient,
598
+ {
599
+ WorkflowService::request_cancel_workflow_execution(
600
+ &mut self.client.clone(),
601
+ RequestCancelWorkflowExecutionRequest {
602
+ namespace: self.client.namespace(),
603
+ workflow_execution: Some(ProtoWorkflowExecution {
604
+ workflow_id: self.info.workflow_id.clone(),
605
+ run_id: self.info.run_id.clone().unwrap_or_default(),
606
+ }),
607
+ identity: self.client.identity(),
608
+ request_id: opts
609
+ .request_id
610
+ .unwrap_or_else(|| Uuid::new_v4().to_string()),
611
+ first_execution_run_id: self
612
+ .info
613
+ .first_execution_run_id
614
+ .clone()
615
+ .unwrap_or_default(),
616
+ reason: opts.reason,
617
+ links: vec![],
618
+ }
619
+ .into_request(),
620
+ )
621
+ .await
622
+ .map_err(WorkflowInteractionError::from_status)?;
623
+ Ok(())
624
+ }
625
+
626
+ /// Terminate this workflow.
627
+ pub async fn terminate(
628
+ &self,
629
+ opts: WorkflowTerminateOptions,
630
+ ) -> Result<(), WorkflowInteractionError>
631
+ where
632
+ CT: NamespacedClient,
633
+ {
634
+ WorkflowService::terminate_workflow_execution(
635
+ &mut self.client.clone(),
636
+ TerminateWorkflowExecutionRequest {
637
+ namespace: self.client.namespace(),
638
+ workflow_execution: Some(ProtoWorkflowExecution {
639
+ workflow_id: self.info.workflow_id.clone(),
640
+ run_id: self.info.run_id.clone().unwrap_or_default(),
641
+ }),
642
+ reason: opts.reason,
643
+ details: opts.details,
644
+ identity: self.client.identity(),
645
+ first_execution_run_id: self
646
+ .info
647
+ .first_execution_run_id
648
+ .clone()
649
+ .unwrap_or_default(),
650
+ links: vec![],
651
+ }
652
+ .into_request(),
653
+ )
654
+ .await
655
+ .map_err(WorkflowInteractionError::from_status)?;
656
+ Ok(())
657
+ }
658
+
659
+ /// Get workflow execution description/metadata.
660
+ pub async fn describe(
661
+ &self,
662
+ _opts: WorkflowDescribeOptions,
663
+ ) -> Result<WorkflowExecutionDescription, WorkflowInteractionError>
664
+ where
665
+ CT: NamespacedClient,
666
+ {
667
+ let response = WorkflowService::describe_workflow_execution(
668
+ &mut self.client.clone(),
669
+ DescribeWorkflowExecutionRequest {
670
+ namespace: self.client.namespace(),
671
+ execution: Some(ProtoWorkflowExecution {
672
+ workflow_id: self.info.workflow_id.clone(),
673
+ run_id: self.info.run_id.clone().unwrap_or_default(),
674
+ }),
675
+ }
676
+ .into_request(),
677
+ )
678
+ .await
679
+ .map_err(WorkflowInteractionError::from_status)?
680
+ .into_inner();
681
+ Ok(WorkflowExecutionDescription::new(response))
682
+ }
683
+ /// Fetch workflow execution history.
684
+ pub async fn fetch_history(
685
+ &self,
686
+ opts: WorkflowFetchHistoryOptions,
687
+ ) -> Result<WorkflowHistory, WorkflowInteractionError>
688
+ where
689
+ CT: NamespacedClient,
690
+ {
691
+ let run_id = self.info.run_id.clone().unwrap_or_default();
692
+ self.fetch_history_for_run(&run_id, &opts).await
693
+ }
694
+
695
+ /// Fetch history for a specific run_id, handling pagination.
696
+ async fn fetch_history_for_run(
697
+ &self,
698
+ run_id: &str,
699
+ opts: &WorkflowFetchHistoryOptions,
700
+ ) -> Result<WorkflowHistory, WorkflowInteractionError>
701
+ where
702
+ CT: NamespacedClient,
703
+ {
704
+ let mut all_events = Vec::new();
705
+ let mut next_page_token = vec![];
706
+
707
+ loop {
708
+ let response = WorkflowService::get_workflow_execution_history(
709
+ &mut self.client.clone(),
710
+ GetWorkflowExecutionHistoryRequest {
711
+ namespace: self.client.namespace(),
712
+ execution: Some(ProtoWorkflowExecution {
713
+ workflow_id: self.info.workflow_id.clone(),
714
+ run_id: run_id.to_string(),
715
+ }),
716
+ next_page_token: next_page_token.clone(),
717
+ skip_archival: opts.skip_archival,
718
+ wait_new_event: opts.wait_new_event,
719
+ history_event_filter_type: opts.event_filter_type as i32,
720
+ ..Default::default()
721
+ }
722
+ .into_request(),
723
+ )
724
+ .await
725
+ .map_err(WorkflowInteractionError::from_status)?
726
+ .into_inner();
727
+
728
+ if let Some(history) = response.history {
729
+ all_events.extend(history.events);
730
+ }
731
+
732
+ if response.next_page_token.is_empty() {
733
+ break;
734
+ }
735
+ next_page_token = response.next_page_token;
736
+ }
737
+
738
+ Ok(WorkflowHistory::new(all_events))
739
+ }
740
+ }
741
+
742
+ /// Handle to a workflow update that has been started but may not be complete.
743
+ ///
744
+ /// Use `get_result()` to wait for the update to complete and retrieve its result.
745
+ pub struct WorkflowUpdateHandle<CT, T> {
746
+ client: CT,
747
+ update_id: String,
748
+ workflow_id: String,
749
+ run_id: Option<String>,
750
+ /// If the update was started with `Completed` wait stage, the outcome is already available.
751
+ known_outcome: Option<update::v1::Outcome>,
752
+ _output: PhantomData<T>,
753
+ }
754
+
755
+ impl<CT, T> WorkflowUpdateHandle<CT, T> {
756
+ /// Get the update ID.
757
+ pub fn id(&self) -> &str {
758
+ &self.update_id
759
+ }
760
+
761
+ /// Get the workflow ID.
762
+ pub fn workflow_id(&self) -> &str {
763
+ &self.workflow_id
764
+ }
765
+
766
+ /// Get the workflow run ID, if available.
767
+ pub fn workflow_run_id(&self) -> Option<&str> {
768
+ self.run_id.as_deref()
769
+ }
770
+ }
771
+
772
+ impl<CT, T: 'static> WorkflowUpdateHandle<CT, T>
773
+ where
774
+ CT: WorkflowService + NamespacedClient + Clone,
775
+ {
776
+ /// Wait for the update to complete and return the result.
777
+ pub async fn get_result(&self) -> Result<T, WorkflowUpdateError>
778
+ where
779
+ T: temporalio_common::data_converters::TemporalDeserializable,
780
+ {
781
+ let outcome = if let Some(known) = &self.known_outcome {
782
+ known.clone()
783
+ } else {
784
+ let response = WorkflowService::poll_workflow_execution_update(
785
+ &mut self.client.clone(),
786
+ PollWorkflowExecutionUpdateRequest {
787
+ namespace: self.client.namespace(),
788
+ update_ref: Some(update::v1::UpdateRef {
789
+ workflow_execution: Some(ProtoWorkflowExecution {
790
+ workflow_id: self.workflow_id.clone(),
791
+ run_id: self.run_id.clone().unwrap_or_default(),
792
+ }),
793
+ update_id: self.update_id.clone(),
794
+ }),
795
+ identity: self.client.identity(),
796
+ wait_policy: Some(WaitPolicy {
797
+ lifecycle_stage: UpdateWorkflowExecutionLifecycleStage::Completed.into(),
798
+ }),
799
+ }
800
+ .into_request(),
801
+ )
802
+ .await
803
+ .map_err(WorkflowUpdateError::from_status)?
804
+ .into_inner();
805
+
806
+ response.outcome.ok_or_else(|| {
807
+ WorkflowUpdateError::Other("Update poll returned no outcome".into())
808
+ })?
809
+ };
810
+
811
+ match outcome.value {
812
+ Some(update::v1::outcome::Value::Success(success)) => self
813
+ .client
814
+ .data_converter()
815
+ .from_payloads(&SerializationContextData::Workflow, success.payloads)
816
+ .await
817
+ .map_err(WorkflowUpdateError::from),
818
+ Some(update::v1::outcome::Value::Failure(failure)) => {
819
+ Err(WorkflowUpdateError::Failed(Box::new(failure)))
820
+ }
821
+ None => Err(WorkflowUpdateError::Other(
822
+ "Update returned no outcome value".into(),
823
+ )),
824
+ }
825
+ }
826
+ }