@temporalio/core-bridge 1.14.2-canary-release-testing.0 → 1.16.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 (233) hide show
  1. package/Cargo.lock +794 -650
  2. package/bridge-macros/src/derive_tryintojs.rs +40 -0
  3. package/lib/native.d.ts +24 -3
  4. package/package.json +4 -4
  5. package/releases/aarch64-apple-darwin/index.node +0 -0
  6. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  7. package/releases/x86_64-apple-darwin/index.node +0 -0
  8. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  9. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  10. package/sdk-core/.github/workflows/per-pr.yml +6 -6
  11. package/sdk-core/AGENTS.md +42 -31
  12. package/sdk-core/Cargo.toml +4 -1
  13. package/sdk-core/README.md +19 -13
  14. package/sdk-core/crates/client/Cargo.toml +4 -0
  15. package/sdk-core/crates/client/README.md +139 -0
  16. package/sdk-core/crates/client/src/async_activity_handle.rs +297 -0
  17. package/sdk-core/crates/client/src/callback_based.rs +7 -0
  18. package/sdk-core/crates/client/src/errors.rs +294 -0
  19. package/sdk-core/crates/client/src/{raw.rs → grpc.rs} +370 -159
  20. package/sdk-core/crates/client/src/lib.rs +920 -1326
  21. package/sdk-core/crates/client/src/metrics.rs +24 -33
  22. package/sdk-core/crates/client/src/options_structs.rs +457 -0
  23. package/sdk-core/crates/client/src/replaceable.rs +5 -4
  24. package/sdk-core/crates/client/src/request_extensions.rs +8 -9
  25. package/sdk-core/crates/client/src/retry.rs +99 -54
  26. package/sdk-core/crates/client/src/{worker/mod.rs → worker.rs} +104 -29
  27. package/sdk-core/crates/client/src/workflow_handle.rs +826 -0
  28. package/sdk-core/crates/common/Cargo.toml +62 -3
  29. package/sdk-core/crates/common/build.rs +742 -12
  30. package/sdk-core/crates/common/protos/api_upstream/.github/workflows/ci.yml +2 -0
  31. package/sdk-core/crates/common/protos/api_upstream/.github/workflows/create-release.yml +0 -5
  32. package/sdk-core/crates/common/protos/api_upstream/Makefile +2 -1
  33. package/sdk-core/crates/common/protos/api_upstream/README.md +8 -0
  34. package/sdk-core/crates/common/protos/api_upstream/cmd/check-path-conflicts/main.go +137 -0
  35. package/sdk-core/crates/common/protos/api_upstream/openapi/openapiv2.json +3329 -2647
  36. package/sdk-core/crates/common/protos/api_upstream/openapi/openapiv3.yaml +2734 -708
  37. package/sdk-core/crates/common/protos/api_upstream/temporal/api/activity/v1/message.proto +155 -3
  38. package/sdk-core/crates/common/protos/api_upstream/temporal/api/command/v1/message.proto +26 -0
  39. package/sdk-core/crates/common/protos/api_upstream/temporal/api/common/v1/message.proto +8 -1
  40. package/sdk-core/crates/common/protos/api_upstream/temporal/api/deployment/v1/message.proto +27 -1
  41. package/sdk-core/crates/common/protos/api_upstream/temporal/api/enums/v1/activity.proto +81 -0
  42. package/sdk-core/crates/common/protos/api_upstream/temporal/api/enums/v1/event_type.proto +4 -0
  43. package/sdk-core/crates/common/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +4 -0
  44. package/sdk-core/crates/common/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +15 -0
  45. package/sdk-core/crates/common/protos/api_upstream/temporal/api/enums/v1/workflow.proto +63 -15
  46. package/sdk-core/crates/common/protos/api_upstream/temporal/api/errordetails/v1/message.proto +8 -0
  47. package/sdk-core/crates/common/protos/api_upstream/temporal/api/failure/v1/message.proto +1 -0
  48. package/sdk-core/crates/common/protos/api_upstream/temporal/api/history/v1/message.proto +111 -17
  49. package/sdk-core/crates/common/protos/api_upstream/temporal/api/namespace/v1/message.proto +21 -0
  50. package/sdk-core/crates/common/protos/api_upstream/temporal/api/nexus/v1/message.proto +20 -1
  51. package/sdk-core/crates/common/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +4 -0
  52. package/sdk-core/crates/common/protos/api_upstream/temporal/api/schedule/v1/message.proto +2 -2
  53. package/sdk-core/crates/common/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -0
  54. package/sdk-core/crates/common/protos/api_upstream/temporal/api/worker/v1/message.proto +4 -7
  55. package/sdk-core/crates/common/protos/api_upstream/temporal/api/workflow/v1/message.proto +80 -22
  56. package/sdk-core/crates/common/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +347 -23
  57. package/sdk-core/crates/common/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +242 -43
  58. package/sdk-core/crates/common/protos/local/temporal/sdk/core/core_interface.proto +15 -0
  59. package/sdk-core/crates/common/protos/local/temporal/sdk/core/nexus/nexus.proto +9 -2
  60. package/sdk-core/crates/common/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +8 -0
  61. package/sdk-core/crates/common/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +22 -5
  62. package/sdk-core/crates/common/src/activity_definition.rs +20 -0
  63. package/sdk-core/crates/common/src/data_converters.rs +770 -0
  64. package/sdk-core/crates/common/src/envconfig.rs +5 -0
  65. package/sdk-core/crates/common/src/lib.rs +15 -211
  66. package/sdk-core/crates/common/src/payload_visitor.rs +648 -0
  67. package/sdk-core/crates/common/src/priority.rs +110 -0
  68. package/sdk-core/crates/common/src/protos/canned_histories.rs +19 -0
  69. package/sdk-core/crates/common/src/protos/history_builder.rs +45 -0
  70. package/sdk-core/crates/common/src/protos/history_info.rs +2 -0
  71. package/sdk-core/crates/common/src/protos/mod.rs +134 -27
  72. package/sdk-core/crates/common/src/protos/task_token.rs +3 -3
  73. package/sdk-core/crates/common/src/protos/utilities.rs +11 -0
  74. package/sdk-core/crates/{sdk-core → common}/src/telemetry/log_export.rs +11 -16
  75. package/sdk-core/crates/common/src/telemetry/metrics/core.rs +125 -0
  76. package/sdk-core/crates/common/src/telemetry/metrics.rs +272 -225
  77. package/sdk-core/crates/{sdk-core → common}/src/telemetry/otel.rs +8 -13
  78. package/sdk-core/crates/{sdk-core → common}/src/telemetry/prometheus_meter.rs +49 -50
  79. package/sdk-core/crates/{sdk-core → common}/src/telemetry/prometheus_server.rs +2 -3
  80. package/sdk-core/crates/common/src/telemetry.rs +278 -19
  81. package/sdk-core/crates/common/src/worker.rs +68 -636
  82. package/sdk-core/crates/common/src/workflow_definition.rs +60 -0
  83. package/sdk-core/crates/macros/Cargo.toml +5 -1
  84. package/sdk-core/crates/macros/src/activities_definitions.rs +585 -0
  85. package/sdk-core/crates/macros/src/fsm_impl.rs +507 -0
  86. package/sdk-core/crates/macros/src/lib.rs +138 -512
  87. package/sdk-core/crates/macros/src/macro_utils.rs +106 -0
  88. package/sdk-core/crates/macros/src/workflow_definitions.rs +1224 -0
  89. package/sdk-core/crates/sdk/Cargo.toml +19 -6
  90. package/sdk-core/crates/sdk/README.md +415 -0
  91. package/sdk-core/crates/sdk/src/activities.rs +417 -0
  92. package/sdk-core/crates/sdk/src/interceptors.rs +1 -1
  93. package/sdk-core/crates/sdk/src/lib.rs +759 -442
  94. package/sdk-core/crates/sdk/src/workflow_context/options.rs +64 -35
  95. package/sdk-core/crates/sdk/src/workflow_context.rs +1033 -289
  96. package/sdk-core/crates/sdk/src/workflow_future.rs +277 -213
  97. package/sdk-core/crates/sdk/src/workflows.rs +711 -0
  98. package/sdk-core/crates/sdk-core/Cargo.toml +59 -65
  99. package/sdk-core/crates/sdk-core/benches/workflow_replay_bench.rs +45 -54
  100. package/sdk-core/crates/sdk-core/machine_coverage/ActivityMachine_Coverage.puml +1 -1
  101. package/sdk-core/crates/sdk-core/src/abstractions.rs +6 -10
  102. package/sdk-core/crates/sdk-core/src/core_tests/activity_tasks.rs +6 -5
  103. package/sdk-core/crates/sdk-core/src/core_tests/mod.rs +22 -21
  104. package/sdk-core/crates/sdk-core/src/core_tests/queries.rs +21 -25
  105. package/sdk-core/crates/sdk-core/src/core_tests/replay_flag.rs +7 -10
  106. package/sdk-core/crates/sdk-core/src/core_tests/updates.rs +14 -17
  107. package/sdk-core/crates/sdk-core/src/core_tests/workers.rs +647 -27
  108. package/sdk-core/crates/sdk-core/src/core_tests/workflow_tasks.rs +46 -41
  109. package/sdk-core/crates/sdk-core/src/ephemeral_server/mod.rs +13 -16
  110. package/sdk-core/crates/sdk-core/src/histfetch.rs +20 -10
  111. package/sdk-core/crates/sdk-core/src/lib.rs +60 -123
  112. package/sdk-core/crates/sdk-core/src/pollers/mod.rs +4 -9
  113. package/sdk-core/crates/sdk-core/src/pollers/poll_buffer.rs +411 -32
  114. package/sdk-core/crates/sdk-core/src/protosext/mod.rs +2 -2
  115. package/sdk-core/crates/sdk-core/src/replay/mod.rs +14 -5
  116. package/sdk-core/crates/sdk-core/src/telemetry/metrics.rs +183 -198
  117. package/sdk-core/crates/sdk-core/src/telemetry/mod.rs +3 -281
  118. package/sdk-core/crates/sdk-core/src/test_help/integ_helpers.rs +35 -16
  119. package/sdk-core/crates/sdk-core/src/test_help/unit_helpers.rs +3 -6
  120. package/sdk-core/crates/sdk-core/src/worker/activities/activity_heartbeat_manager.rs +1 -0
  121. package/sdk-core/crates/sdk-core/src/worker/activities/local_activities.rs +11 -14
  122. package/sdk-core/crates/sdk-core/src/worker/activities.rs +16 -19
  123. package/sdk-core/crates/sdk-core/src/worker/client/mocks.rs +11 -5
  124. package/sdk-core/crates/sdk-core/src/worker/client.rs +104 -86
  125. package/sdk-core/crates/sdk-core/src/worker/heartbeat.rs +10 -14
  126. package/sdk-core/crates/sdk-core/src/worker/mod.rs +1175 -241
  127. package/sdk-core/crates/sdk-core/src/worker/nexus.rs +150 -23
  128. package/sdk-core/crates/sdk-core/src/worker/slot_provider.rs +2 -2
  129. package/sdk-core/crates/sdk-core/src/worker/tuner/fixed_size.rs +2 -2
  130. package/sdk-core/crates/sdk-core/src/worker/tuner/resource_based.rs +25 -27
  131. package/sdk-core/crates/sdk-core/src/worker/tuner.rs +64 -44
  132. package/sdk-core/crates/sdk-core/src/worker/workflow/driven_workflow.rs +9 -3
  133. package/sdk-core/crates/sdk-core/src/worker/workflow/machines/patch_state_machine.rs +5 -8
  134. package/sdk-core/crates/sdk-core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +21 -22
  135. package/sdk-core/crates/sdk-core/src/worker/workflow/machines/workflow_machines.rs +28 -4
  136. package/sdk-core/crates/sdk-core/src/worker/workflow/managed_run.rs +20 -41
  137. package/sdk-core/crates/sdk-core/src/worker/workflow/mod.rs +50 -9
  138. package/sdk-core/crates/sdk-core/src/worker/workflow/run_cache.rs +4 -7
  139. package/sdk-core/crates/sdk-core/src/worker/workflow/wft_extraction.rs +2 -4
  140. package/sdk-core/crates/sdk-core/src/worker/workflow/wft_poller.rs +8 -9
  141. package/sdk-core/crates/sdk-core/src/worker/workflow/workflow_stream.rs +1 -3
  142. package/sdk-core/crates/sdk-core/tests/activities_procmacro.rs +6 -0
  143. package/sdk-core/crates/sdk-core/tests/activities_trybuild/basic_pass.rs +54 -0
  144. package/sdk-core/crates/sdk-core/tests/activities_trybuild/invalid_self_type_fail.rs +18 -0
  145. package/sdk-core/crates/sdk-core/tests/activities_trybuild/invalid_self_type_fail.stderr +5 -0
  146. package/sdk-core/crates/sdk-core/tests/activities_trybuild/missing_context_fail.rs +14 -0
  147. package/sdk-core/crates/sdk-core/tests/activities_trybuild/missing_context_fail.stderr +5 -0
  148. package/sdk-core/crates/sdk-core/tests/activities_trybuild/multi_arg_pass.rs +48 -0
  149. package/sdk-core/crates/sdk-core/tests/activities_trybuild/no_input_pass.rs +14 -0
  150. package/sdk-core/crates/sdk-core/tests/activities_trybuild/no_return_type_pass.rs +19 -0
  151. package/sdk-core/crates/sdk-core/tests/cloud_tests.rs +14 -5
  152. package/sdk-core/crates/sdk-core/tests/common/activity_functions.rs +55 -0
  153. package/sdk-core/crates/sdk-core/tests/common/mod.rs +281 -236
  154. package/sdk-core/crates/sdk-core/tests/common/workflows.rs +41 -28
  155. package/sdk-core/crates/sdk-core/tests/global_metric_tests.rs +9 -14
  156. package/sdk-core/crates/sdk-core/tests/heavy_tests/fuzzy_workflow.rs +73 -66
  157. package/sdk-core/crates/sdk-core/tests/heavy_tests.rs +306 -268
  158. package/sdk-core/crates/sdk-core/tests/integ_tests/async_activity_client_tests.rs +230 -0
  159. package/sdk-core/crates/sdk-core/tests/integ_tests/client_tests.rs +94 -57
  160. package/sdk-core/crates/sdk-core/tests/integ_tests/data_converter_tests.rs +381 -0
  161. package/sdk-core/crates/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +37 -38
  162. package/sdk-core/crates/sdk-core/tests/integ_tests/heartbeat_tests.rs +49 -40
  163. package/sdk-core/crates/sdk-core/tests/integ_tests/metrics_tests.rs +447 -300
  164. package/sdk-core/crates/sdk-core/tests/integ_tests/pagination_tests.rs +50 -45
  165. package/sdk-core/crates/sdk-core/tests/integ_tests/polling_tests.rs +157 -157
  166. package/sdk-core/crates/sdk-core/tests/integ_tests/queries_tests.rs +103 -89
  167. package/sdk-core/crates/sdk-core/tests/integ_tests/update_tests.rs +609 -463
  168. package/sdk-core/crates/sdk-core/tests/integ_tests/visibility_tests.rs +80 -62
  169. package/sdk-core/crates/sdk-core/tests/integ_tests/worker_heartbeat_tests.rs +389 -265
  170. package/sdk-core/crates/sdk-core/tests/integ_tests/worker_tests.rs +250 -185
  171. package/sdk-core/crates/sdk-core/tests/integ_tests/worker_versioning_tests.rs +52 -49
  172. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_client_tests.rs +180 -0
  173. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/activities.rs +437 -327
  174. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +82 -58
  175. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +56 -30
  176. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +364 -251
  177. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/client_interactions.rs +552 -0
  178. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +110 -46
  179. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +243 -149
  180. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/eager.rs +98 -32
  181. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +1475 -1040
  182. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +73 -43
  183. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/nexus.rs +402 -245
  184. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/patches.rs +343 -207
  185. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/queries.rs +415 -0
  186. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/replay.rs +96 -36
  187. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/resets.rs +155 -140
  188. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/signals.rs +183 -113
  189. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +85 -44
  190. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/timers.rs +142 -48
  191. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +73 -56
  192. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests.rs +365 -242
  193. package/sdk-core/crates/sdk-core/tests/main.rs +22 -16
  194. package/sdk-core/crates/sdk-core/tests/manual_tests.rs +233 -187
  195. package/sdk-core/crates/sdk-core/tests/runner.rs +4 -6
  196. package/sdk-core/crates/sdk-core/tests/shared_tests/mod.rs +73 -27
  197. package/sdk-core/crates/sdk-core/tests/shared_tests/priority.rs +107 -84
  198. package/sdk-core/crates/sdk-core/tests/workflows_procmacro.rs +6 -0
  199. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/async_query_fail.rs +26 -0
  200. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/async_query_fail.stderr +5 -0
  201. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/basic_pass.rs +49 -0
  202. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/minimal_pass.rs +21 -0
  203. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/mut_query_fail.rs +26 -0
  204. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/mut_query_fail.stderr +5 -0
  205. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/sync_run_fail.rs +21 -0
  206. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/sync_run_fail.stderr +5 -0
  207. package/sdk-core/crates/sdk-core-c-bridge/Cargo.toml +8 -1
  208. package/sdk-core/crates/sdk-core-c-bridge/include/temporal-sdk-core-c-bridge.h +37 -26
  209. package/sdk-core/crates/sdk-core-c-bridge/src/client.rs +180 -87
  210. package/sdk-core/crates/sdk-core-c-bridge/src/lib.rs +89 -5
  211. package/sdk-core/crates/sdk-core-c-bridge/src/metric.rs +10 -16
  212. package/sdk-core/crates/sdk-core-c-bridge/src/runtime.rs +59 -67
  213. package/sdk-core/crates/sdk-core-c-bridge/src/testing.rs +10 -10
  214. package/sdk-core/crates/sdk-core-c-bridge/src/tests/context.rs +57 -22
  215. package/sdk-core/crates/sdk-core-c-bridge/src/tests/mod.rs +108 -12
  216. package/sdk-core/crates/sdk-core-c-bridge/src/tests/utils.rs +9 -52
  217. package/sdk-core/crates/sdk-core-c-bridge/src/worker.rs +74 -91
  218. package/sdk-core/rustfmt.toml +2 -1
  219. package/src/client.rs +206 -289
  220. package/src/helpers/try_into_js.rs +88 -2
  221. package/src/metrics.rs +277 -35
  222. package/src/runtime.rs +94 -45
  223. package/src/testing.rs +9 -16
  224. package/src/worker.rs +86 -68
  225. package/ts/native.ts +39 -3
  226. package/sdk-core/crates/client/src/workflow_handle/mod.rs +0 -212
  227. package/sdk-core/crates/common/src/errors.rs +0 -85
  228. package/sdk-core/crates/common/tests/worker_task_types_test.rs +0 -129
  229. package/sdk-core/crates/macros/LICENSE.txt +0 -21
  230. package/sdk-core/crates/sdk/src/activity_context.rs +0 -238
  231. package/sdk-core/crates/sdk/src/app_data.rs +0 -37
  232. package/sdk-core/crates/sdk-core/tests/integ_tests/activity_functions.rs +0 -5
  233. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +0 -61
@@ -1,11 +1,11 @@
1
1
  use crate::{
2
- PollError, prost_dur,
2
+ CompleteNexusError, PollError, prost_dur,
3
3
  test_help::{
4
4
  MockPollCfg, MockWorkerInputs, MocksHolder, QueueResponse, ResponseType, WorkerExt,
5
5
  WorkerTestHelpers, build_fake_worker, build_mock_pollers, mock_worker, test_worker_cfg,
6
6
  },
7
7
  worker::{
8
- self,
8
+ self, PollerBehavior,
9
9
  client::{
10
10
  MockWorkerClient,
11
11
  mocks::{DEFAULT_TEST_CAPABILITIES, DEFAULT_WORKERS_REGISTRY, mock_worker_client},
@@ -13,37 +13,46 @@ use crate::{
13
13
  },
14
14
  };
15
15
  use futures_util::{stream, stream::StreamExt};
16
- use std::{cell::RefCell, time::Duration};
16
+ use std::{cell::RefCell, collections::HashMap, time::Duration};
17
17
  use temporalio_common::{
18
- Worker,
19
18
  protos::{
20
19
  canned_histories,
21
20
  coresdk::{
22
21
  ActivityTaskCompletion,
23
22
  activity_result::ActivityExecutionResult,
24
- nexus::NexusTaskCompletion,
23
+ nexus::{NexusOperationErrorState, NexusTaskCompletion, nexus_task_completion},
25
24
  workflow_activation::workflow_activation_job,
26
25
  workflow_commands::{CompleteWorkflowExecution, StartTimer, workflow_command},
27
26
  workflow_completion::WorkflowActivationCompletion,
28
27
  },
29
28
  temporal::api::{
30
29
  common::v1::{ActivityType, WorkflowExecution},
31
- nexus::v1::{
32
- Request as NexusRequest, Response as NexusResponse, StartOperationRequest,
33
- StartOperationResponse, start_operation_response,
30
+ enums::v1::NexusHandlerErrorRetryBehavior,
31
+ failure::v1::{
32
+ ApplicationFailureInfo, CanceledFailureInfo, Failure, NexusHandlerFailureInfo,
33
+ TimeoutFailureInfo, failure::FailureInfo,
34
+ },
35
+ nexus::{
36
+ self,
37
+ v1::{
38
+ HandlerError, NexusTaskFailure, Request as NexusRequest,
39
+ Response as NexusResponse, StartOperationRequest, StartOperationResponse,
40
+ UnsuccessfulOperationError, response, start_operation_response,
41
+ },
34
42
  },
35
43
  workflowservice::v1::{
36
44
  PollActivityTaskQueueResponse, PollNexusTaskQueueResponse,
37
45
  PollWorkflowTaskQueueResponse, RespondActivityTaskCompletedResponse,
38
- RespondNexusTaskCompletedResponse, RespondWorkflowTaskCompletedResponse,
39
- ShutdownWorkerResponse,
46
+ RespondNexusTaskCompletedResponse, RespondNexusTaskFailedResponse,
47
+ RespondWorkflowTaskCompletedResponse, ShutdownWorkerResponse,
40
48
  },
41
49
  },
42
50
  test_utils::start_timer_cmd,
43
51
  },
44
- worker::{PollerBehavior, WorkerTaskTypes},
52
+ worker::WorkerTaskTypes,
45
53
  };
46
54
  use tokio::sync::{Barrier, watch};
55
+ use uuid::Uuid;
47
56
 
48
57
  #[tokio::test]
49
58
  async fn after_shutdown_of_worker_get_shutdown_err() {
@@ -333,19 +342,17 @@ async fn worker_shutdown_api(#[case] use_cache: bool, #[case] api_success: bool)
333
342
  .returning(|| ("test-core".to_string(), "0.0.0".to_string()));
334
343
  mock.expect_identity()
335
344
  .returning(|| "test-identity".to_string());
336
- if use_cache {
337
- if api_success {
338
- mock.expect_shutdown_worker()
339
- .times(1)
340
- .returning(|_, _| Ok(ShutdownWorkerResponse {}));
341
- } else {
342
- // worker.shutdown() should succeed even if shutdown_worker fails
343
- mock.expect_shutdown_worker()
344
- .times(1)
345
- .returning(|_, _| Err(tonic::Status::unavailable("fake shutdown error")));
346
- }
345
+ mock.expect_worker_grouping_key().returning(Uuid::new_v4);
346
+ mock.expect_worker_instance_key().returning(Uuid::new_v4);
347
+ if api_success {
348
+ mock.expect_shutdown_worker()
349
+ .times(1)
350
+ .returning(|_, _, _, _| Ok(ShutdownWorkerResponse {}));
347
351
  } else {
348
- mock.expect_shutdown_worker().times(0);
352
+ // worker.shutdown() should succeed even if shutdown_worker fails
353
+ mock.expect_shutdown_worker()
354
+ .times(1)
355
+ .returning(|_, _, _, _| Err(tonic::Status::unavailable("fake shutdown error")));
349
356
  }
350
357
 
351
358
  let t = canned_histories::single_timer("1");
@@ -396,11 +403,16 @@ fn create_test_activity_task() -> PollActivityTaskQueueResponse {
396
403
  }
397
404
  }
398
405
 
399
- fn create_test_nexus_task() -> PollNexusTaskQueueResponse {
406
+ fn create_test_nexus_task(
407
+ header: Option<HashMap<String, String>>,
408
+ capabilities: Option<nexus::v1::request::Capabilities>,
409
+ ) -> PollNexusTaskQueueResponse {
400
410
  PollNexusTaskQueueResponse {
401
411
  task_token: b"nex-task".to_vec(),
402
412
  request: Some(NexusRequest {
403
- header: Default::default(),
413
+ capabilities,
414
+ endpoint: "test-endpoint".to_string(),
415
+ header: header.unwrap_or_default(),
404
416
  scheduled_time: None,
405
417
  variant: Some(temporalio_common::protos::temporal::api::nexus::v1::request::Variant::StartOperation(
406
418
  StartOperationRequest {
@@ -501,7 +513,12 @@ async fn test_task_type_combinations_unified(
501
513
  mocks.set_act_poller_from_resps(vec![QueueResponse::from(create_test_activity_task())]);
502
514
  }
503
515
  if enable_nexus {
504
- mocks.set_nexus_poller_from_resps(vec![QueueResponse::from(create_test_nexus_task())]);
516
+ mocks.set_nexus_poller_from_resps(vec![QueueResponse::from(create_test_nexus_task(
517
+ None,
518
+ Some(nexus::v1::request::Capabilities {
519
+ temporal_failure_responses: true,
520
+ }),
521
+ ))]);
505
522
  }
506
523
  mocks
507
524
  } else {
@@ -516,7 +533,12 @@ async fn test_task_type_combinations_unified(
516
533
  None
517
534
  };
518
535
  let nexus_tasks = if enable_nexus && with_task {
519
- Some(vec![QueueResponse::from(create_test_nexus_task())])
536
+ Some(vec![QueueResponse::from(create_test_nexus_task(
537
+ None,
538
+ Some(nexus::v1::request::Capabilities {
539
+ temporal_failure_responses: true,
540
+ }),
541
+ ))])
520
542
  } else {
521
543
  None
522
544
  };
@@ -589,3 +611,601 @@ async fn test_task_type_combinations_unified(
589
611
  worker.shutdown().await;
590
612
  worker.finalize_shutdown().await;
591
613
  }
614
+
615
+ #[tokio::test]
616
+ async fn nexus_request_deadline_missing_header() {
617
+ let mut client = mock_worker_client();
618
+ client
619
+ .expect_complete_nexus_task()
620
+ .returning(|_, _| Ok(RespondNexusTaskCompletedResponse::default()));
621
+ let nexus_task = create_test_nexus_task(None, None); // No headers
622
+ let mut mocks = MocksHolder::from_client_with_custom(
623
+ client,
624
+ None::<stream::Empty<_>>,
625
+ None::<Vec<QueueResponse<PollActivityTaskQueueResponse>>>,
626
+ Some(vec![QueueResponse::from(nexus_task)]),
627
+ );
628
+ mocks.worker_cfg(|w| {
629
+ w.task_queue = "test-queue".to_string();
630
+ w.task_types = WorkerTaskTypes {
631
+ enable_workflows: false,
632
+ enable_local_activities: false,
633
+ enable_remote_activities: false,
634
+ enable_nexus: true,
635
+ };
636
+ w.skip_client_worker_set_check = true;
637
+ });
638
+ let worker = mock_worker(mocks);
639
+
640
+ let nexus_task = worker.poll_nexus_task().await.unwrap();
641
+ assert!(
642
+ nexus_task.request_deadline.is_none(),
643
+ "request_deadline should be None when header is missing"
644
+ );
645
+
646
+ worker
647
+ .complete_nexus_task(create_test_nexus_completion(nexus_task.task_token()))
648
+ .await
649
+ .unwrap();
650
+ worker.initiate_shutdown();
651
+ assert_matches!(
652
+ worker.poll_nexus_task().await.unwrap_err(),
653
+ PollError::ShutDown
654
+ );
655
+ worker.shutdown().await;
656
+ worker.finalize_shutdown().await;
657
+ }
658
+
659
+ #[tokio::test]
660
+ async fn nexus_request_deadline_valid_header() {
661
+ let mut client = mock_worker_client();
662
+ client
663
+ .expect_complete_nexus_task()
664
+ .returning(|_, _| Ok(RespondNexusTaskCompletedResponse::default()));
665
+ let mut headers = std::collections::HashMap::new();
666
+ headers.insert("request-timeout".to_string(), "30s".to_string());
667
+ let nexus_task = create_test_nexus_task(Some(headers), None);
668
+ let mut mocks = MocksHolder::from_client_with_custom(
669
+ client,
670
+ None::<stream::Empty<_>>,
671
+ None::<Vec<QueueResponse<PollActivityTaskQueueResponse>>>,
672
+ Some(vec![QueueResponse::from(nexus_task)]),
673
+ );
674
+ mocks.worker_cfg(|w| {
675
+ w.task_queue = "test-queue".to_string();
676
+ w.task_types = WorkerTaskTypes {
677
+ enable_workflows: false,
678
+ enable_local_activities: false,
679
+ enable_remote_activities: false,
680
+ enable_nexus: true,
681
+ };
682
+ w.skip_client_worker_set_check = true;
683
+ });
684
+ let worker = mock_worker(mocks);
685
+
686
+ let before = std::time::SystemTime::now();
687
+ let nexus_task = worker.poll_nexus_task().await.unwrap();
688
+ let after = std::time::SystemTime::now();
689
+
690
+ assert!(
691
+ nexus_task.request_deadline.is_some(),
692
+ "request_deadline should be Some when valid header is present"
693
+ );
694
+ let deadline: std::time::SystemTime = nexus_task.request_deadline.unwrap().try_into().unwrap();
695
+ // Deadline should be approximately 30s from now
696
+ let expected_min = before + Duration::from_secs(30);
697
+ let expected_max = after + Duration::from_secs(30);
698
+ assert!(
699
+ deadline >= expected_min && deadline <= expected_max,
700
+ "deadline {:?} should be between {:?} and {:?}",
701
+ deadline,
702
+ expected_min,
703
+ expected_max
704
+ );
705
+
706
+ worker
707
+ .complete_nexus_task(create_test_nexus_completion(nexus_task.task_token()))
708
+ .await
709
+ .unwrap();
710
+ worker.initiate_shutdown();
711
+ assert_matches!(
712
+ worker.poll_nexus_task().await.unwrap_err(),
713
+ PollError::ShutDown
714
+ );
715
+ worker.shutdown().await;
716
+ worker.finalize_shutdown().await;
717
+ }
718
+
719
+ #[tokio::test]
720
+ async fn nexus_request_deadline_invalid_header() {
721
+ let mut client = mock_worker_client();
722
+ client
723
+ .expect_complete_nexus_task()
724
+ .returning(|_, _| Ok(RespondNexusTaskCompletedResponse::default()));
725
+ let mut headers = std::collections::HashMap::new();
726
+ headers.insert("request-timeout".to_string(), "invalid".to_string());
727
+ let nexus_task = create_test_nexus_task(Some(headers), None);
728
+ let mut mocks = MocksHolder::from_client_with_custom(
729
+ client,
730
+ None::<stream::Empty<_>>,
731
+ None::<Vec<QueueResponse<PollActivityTaskQueueResponse>>>,
732
+ Some(vec![QueueResponse::from(nexus_task)]),
733
+ );
734
+ mocks.worker_cfg(|w| {
735
+ w.task_queue = "test-queue".to_string();
736
+ w.task_types = WorkerTaskTypes {
737
+ enable_workflows: false,
738
+ enable_local_activities: false,
739
+ enable_remote_activities: false,
740
+ enable_nexus: true,
741
+ };
742
+ w.skip_client_worker_set_check = true;
743
+ });
744
+ let worker = mock_worker(mocks);
745
+
746
+ let nexus_task = worker.poll_nexus_task().await.unwrap();
747
+ assert!(
748
+ nexus_task.request_deadline.is_none(),
749
+ "request_deadline should be None when header is invalid"
750
+ );
751
+
752
+ worker
753
+ .complete_nexus_task(create_test_nexus_completion(nexus_task.task_token()))
754
+ .await
755
+ .unwrap();
756
+ worker.initiate_shutdown();
757
+ assert_matches!(
758
+ worker.poll_nexus_task().await.unwrap_err(),
759
+ PollError::ShutDown
760
+ );
761
+ worker.shutdown().await;
762
+ worker.finalize_shutdown().await;
763
+ }
764
+
765
+ #[tokio::test]
766
+ async fn nexus_task_completion_with_failure_status() {
767
+ let mut client = mock_worker_client();
768
+ client
769
+ .expect_fail_nexus_task()
770
+ .times(1)
771
+ .withf(|_, error| {
772
+
773
+ matches!(error,
774
+ NexusTaskFailure::Temporal(Failure{ message, failure_info, .. })
775
+ if message == "handler failed" &&
776
+ matches!(failure_info,
777
+ Some(FailureInfo::NexusHandlerFailureInfo(NexusHandlerFailureInfo{ r#type, retry_behavior }))
778
+ if r#type == "INTERNAL" &&
779
+ *retry_behavior == NexusHandlerErrorRetryBehavior::NonRetryable as i32
780
+ )
781
+ )
782
+
783
+ })
784
+ .returning(|_, _| Ok(RespondNexusTaskFailedResponse::default()));
785
+
786
+ let mocks = MocksHolder::from_client_with_custom(
787
+ client,
788
+ None::<stream::Empty<PollWorkflowTaskQueueResponse>>,
789
+ None::<Vec<QueueResponse<PollActivityTaskQueueResponse>>>,
790
+ Some(vec![QueueResponse::from(create_test_nexus_task(
791
+ None,
792
+ Some(nexus::v1::request::Capabilities {
793
+ temporal_failure_responses: true,
794
+ }),
795
+ ))]),
796
+ );
797
+ let worker = mock_worker(mocks);
798
+
799
+ let nexus_task = worker.poll_nexus_task().await.unwrap();
800
+ worker
801
+ .complete_nexus_task(NexusTaskCompletion {
802
+ task_token: nexus_task.task_token().to_vec(),
803
+ status: Some(nexus_task_completion::Status::Failure(Failure {
804
+ message: "handler failed".to_string(),
805
+ failure_info: Some(FailureInfo::NexusHandlerFailureInfo(
806
+ NexusHandlerFailureInfo {
807
+ r#type: "INTERNAL".to_string(),
808
+ retry_behavior: NexusHandlerErrorRetryBehavior::NonRetryable.into(),
809
+ },
810
+ )),
811
+ ..Default::default()
812
+ })),
813
+ })
814
+ .await
815
+ .unwrap();
816
+
817
+ worker.initiate_shutdown();
818
+ assert_matches!(
819
+ worker.poll_nexus_task().await.unwrap_err(),
820
+ PollError::ShutDown
821
+ );
822
+ worker.shutdown().await;
823
+ worker.finalize_shutdown().await;
824
+ }
825
+
826
+ #[tokio::test]
827
+ async fn nexus_task_completion_with_failure_converts_to_legacy_for_old_server() {
828
+ let mut client = mock_worker_client();
829
+ client
830
+ .expect_fail_nexus_task()
831
+ .times(1)
832
+ .withf(|_, error| {
833
+ matches!(error,
834
+ NexusTaskFailure::Legacy(
835
+ HandlerError{
836
+ error_type,
837
+ failure: Some(f),
838
+ retry_behavior,
839
+ }
840
+ )
841
+ if error_type == "INTERNAL" &&
842
+ f.message == "handler failed" &&
843
+ *retry_behavior == NexusHandlerErrorRetryBehavior::NonRetryable as i32
844
+ )
845
+ })
846
+ .returning(|_, _| Ok(RespondNexusTaskFailedResponse::default()));
847
+
848
+ let mocks = MocksHolder::from_client_with_custom(
849
+ client,
850
+ None::<stream::Empty<PollWorkflowTaskQueueResponse>>,
851
+ None::<Vec<QueueResponse<PollActivityTaskQueueResponse>>>,
852
+ Some(vec![QueueResponse::from(create_test_nexus_task(
853
+ None,
854
+ Some(nexus::v1::request::Capabilities {
855
+ temporal_failure_responses: false,
856
+ }),
857
+ ))]),
858
+ );
859
+ let worker = mock_worker(mocks);
860
+
861
+ let nexus_task = worker.poll_nexus_task().await.unwrap();
862
+ worker
863
+ .complete_nexus_task(NexusTaskCompletion {
864
+ task_token: nexus_task.task_token().to_vec(),
865
+ status: Some(nexus_task_completion::Status::Failure(Failure {
866
+ message: "handler failed".to_string(),
867
+ failure_info: Some(FailureInfo::NexusHandlerFailureInfo(
868
+ NexusHandlerFailureInfo {
869
+ r#type: "INTERNAL".to_string(),
870
+ retry_behavior: NexusHandlerErrorRetryBehavior::NonRetryable.into(),
871
+ },
872
+ )),
873
+ ..Default::default()
874
+ })),
875
+ })
876
+ .await
877
+ .unwrap();
878
+
879
+ worker.initiate_shutdown();
880
+ assert_matches!(
881
+ worker.poll_nexus_task().await.unwrap_err(),
882
+ PollError::ShutDown
883
+ );
884
+ worker.shutdown().await;
885
+ worker.finalize_shutdown().await;
886
+ }
887
+
888
+ #[rstest::rstest]
889
+ #[case::with_temporal_failure_responses(true)]
890
+ #[case::without_temporal_failure_responses(false)]
891
+ #[tokio::test]
892
+ async fn nexus_task_completion_with_failure_status_missing_handler_info_fails(
893
+ #[case] temporal_failure_responses: bool,
894
+ ) {
895
+ let client = mock_worker_client();
896
+
897
+ let mocks = MocksHolder::from_client_with_custom(
898
+ client,
899
+ None::<stream::Empty<PollWorkflowTaskQueueResponse>>,
900
+ None::<Vec<QueueResponse<PollActivityTaskQueueResponse>>>,
901
+ Some(vec![QueueResponse::from(create_test_nexus_task(
902
+ None,
903
+ Some(nexus::v1::request::Capabilities {
904
+ temporal_failure_responses,
905
+ }),
906
+ ))]),
907
+ );
908
+ let worker = mock_worker(mocks);
909
+
910
+ let nexus_task = worker.poll_nexus_task().await.unwrap();
911
+ let result = worker
912
+ .complete_nexus_task(NexusTaskCompletion {
913
+ task_token: nexus_task.task_token().to_vec(),
914
+ status: Some(nexus_task_completion::Status::Failure(Failure {
915
+ message: "handler failed".to_string(),
916
+ // Missing NexusHandlerFailureInfo - should fail validation
917
+ failure_info: None,
918
+ ..Default::default()
919
+ })),
920
+ })
921
+ .await;
922
+
923
+ // Should fail validation because NexusHandlerFailureInfo is required
924
+ assert_matches!(
925
+ result,
926
+ Err(CompleteNexusError::MalformedNexusCompletion { reason }) if reason.contains("NexusHandlerFailureInfo")
927
+ );
928
+
929
+ worker.initiate_shutdown();
930
+ assert_matches!(
931
+ worker.poll_nexus_task().await.unwrap_err(),
932
+ PollError::ShutDown
933
+ );
934
+ worker.shutdown().await;
935
+ worker.finalize_shutdown().await;
936
+ }
937
+
938
+ fn create_nexus_completion_with_start_op_failure(
939
+ task_token: &[u8],
940
+ failure: Failure,
941
+ ) -> NexusTaskCompletion {
942
+ NexusTaskCompletion {
943
+ task_token: task_token.to_vec(),
944
+ status: Some(nexus_task_completion::Status::Completed(NexusResponse {
945
+ variant: Some(response::Variant::StartOperation(StartOperationResponse {
946
+ variant: Some(start_operation_response::Variant::Failure(failure)),
947
+ })),
948
+ })),
949
+ }
950
+ }
951
+
952
+ #[tokio::test]
953
+ async fn nexus_start_operation_failure_with_application_failure_info() {
954
+ let mut client = mock_worker_client();
955
+ client
956
+ .expect_complete_nexus_task()
957
+ .times(1)
958
+ .withf(|_, response| {
959
+ matches!(response,
960
+ nexus::v1::Response{
961
+ variant: Some(response::Variant::StartOperation(StartOperationResponse {
962
+ variant: Some(start_operation_response::Variant::Failure(
963
+ Failure {
964
+ message,
965
+ failure_info: Some(FailureInfo::ApplicationFailureInfo(ApplicationFailureInfo { r#type, non_retryable, ..})),
966
+ .. }
967
+ ))
968
+ }))
969
+ }
970
+ if message == "operation failed" &&
971
+ r#type == "MyAppError" &&
972
+ *non_retryable
973
+ )
974
+ })
975
+ .returning(|_, _| Ok(RespondNexusTaskCompletedResponse::default()));
976
+
977
+ let mocks = MocksHolder::from_client_with_custom(
978
+ client,
979
+ None::<stream::Empty<PollWorkflowTaskQueueResponse>>,
980
+ None::<Vec<QueueResponse<PollActivityTaskQueueResponse>>>,
981
+ Some(vec![QueueResponse::from(create_test_nexus_task(
982
+ None,
983
+ Some(nexus::v1::request::Capabilities {
984
+ temporal_failure_responses: true,
985
+ }),
986
+ ))]),
987
+ );
988
+ let worker = mock_worker(mocks);
989
+
990
+ let nexus_task = worker.poll_nexus_task().await.unwrap();
991
+ worker
992
+ .complete_nexus_task(create_nexus_completion_with_start_op_failure(
993
+ nexus_task.task_token(),
994
+ Failure {
995
+ message: "operation failed".to_string(),
996
+ failure_info: Some(FailureInfo::ApplicationFailureInfo(
997
+ ApplicationFailureInfo {
998
+ r#type: "MyAppError".to_string(),
999
+ non_retryable: true,
1000
+ ..Default::default()
1001
+ },
1002
+ )),
1003
+ ..Default::default()
1004
+ },
1005
+ ))
1006
+ .await
1007
+ .unwrap();
1008
+
1009
+ worker.initiate_shutdown();
1010
+ assert_matches!(
1011
+ worker.poll_nexus_task().await.unwrap_err(),
1012
+ PollError::ShutDown
1013
+ );
1014
+ worker.shutdown().await;
1015
+ worker.finalize_shutdown().await;
1016
+ }
1017
+
1018
+ #[tokio::test]
1019
+ async fn nexus_start_operation_failure_with_canceled_failure_info() {
1020
+ let mut client = mock_worker_client();
1021
+ client
1022
+ .expect_complete_nexus_task()
1023
+ .times(1)
1024
+ .withf(|_, response| {
1025
+ matches!(response,
1026
+ nexus::v1::Response{
1027
+ variant: Some(response::Variant::StartOperation(StartOperationResponse {
1028
+ variant: Some(start_operation_response::Variant::Failure(
1029
+ Failure {
1030
+ message,
1031
+ failure_info: Some(FailureInfo::CanceledFailureInfo(_)),
1032
+ .. }
1033
+ ))
1034
+ }))
1035
+ }
1036
+ if message == "operation canceled"
1037
+ )
1038
+ })
1039
+ .returning(|_, _| Ok(RespondNexusTaskCompletedResponse::default()));
1040
+
1041
+ let mocks = MocksHolder::from_client_with_custom(
1042
+ client,
1043
+ None::<stream::Empty<PollWorkflowTaskQueueResponse>>,
1044
+ None::<Vec<QueueResponse<PollActivityTaskQueueResponse>>>,
1045
+ Some(vec![QueueResponse::from(create_test_nexus_task(
1046
+ None,
1047
+ Some(nexus::v1::request::Capabilities {
1048
+ temporal_failure_responses: true,
1049
+ }),
1050
+ ))]),
1051
+ );
1052
+ let worker = mock_worker(mocks);
1053
+
1054
+ let nexus_task = worker.poll_nexus_task().await.unwrap();
1055
+ worker
1056
+ .complete_nexus_task(create_nexus_completion_with_start_op_failure(
1057
+ nexus_task.task_token(),
1058
+ Failure {
1059
+ message: "operation canceled".to_string(),
1060
+ failure_info: Some(FailureInfo::CanceledFailureInfo(CanceledFailureInfo {
1061
+ details: None,
1062
+ })),
1063
+ ..Default::default()
1064
+ },
1065
+ ))
1066
+ .await
1067
+ .unwrap();
1068
+
1069
+ worker.initiate_shutdown();
1070
+ assert_matches!(
1071
+ worker.poll_nexus_task().await.unwrap_err(),
1072
+ PollError::ShutDown
1073
+ );
1074
+ worker.shutdown().await;
1075
+ worker.finalize_shutdown().await;
1076
+ }
1077
+
1078
+ #[rstest::rstest]
1079
+ #[case::missing_failure_info(None)]
1080
+ #[case::invalid_failure_info_type(Some(FailureInfo::TimeoutFailureInfo(
1081
+ TimeoutFailureInfo::default()
1082
+ )))]
1083
+ #[tokio::test]
1084
+ async fn nexus_start_operation_failure_with_invalid_failure_info(
1085
+ #[case] failure_info: Option<FailureInfo>,
1086
+ ) {
1087
+ let client = mock_worker_client();
1088
+
1089
+ let mocks = MocksHolder::from_client_with_custom(
1090
+ client,
1091
+ None::<stream::Empty<PollWorkflowTaskQueueResponse>>,
1092
+ None::<Vec<QueueResponse<PollActivityTaskQueueResponse>>>,
1093
+ Some(vec![QueueResponse::from(create_test_nexus_task(
1094
+ None,
1095
+ Some(nexus::v1::request::Capabilities {
1096
+ temporal_failure_responses: true,
1097
+ }),
1098
+ ))]),
1099
+ );
1100
+ let worker = mock_worker(mocks);
1101
+
1102
+ let nexus_task = worker.poll_nexus_task().await.unwrap();
1103
+ let result = worker
1104
+ .complete_nexus_task(create_nexus_completion_with_start_op_failure(
1105
+ nexus_task.task_token(),
1106
+ Failure {
1107
+ message: "operation failed".to_string(),
1108
+ failure_info,
1109
+ ..Default::default()
1110
+ },
1111
+ ))
1112
+ .await;
1113
+
1114
+ assert_matches!(
1115
+ result,
1116
+ Err(CompleteNexusError::MalformedNexusCompletion { reason })
1117
+ if reason.contains("ApplicationFailureInfo") && reason.contains("CanceledFailureInfo")
1118
+ );
1119
+
1120
+ worker.initiate_shutdown();
1121
+ assert_matches!(
1122
+ worker.poll_nexus_task().await.unwrap_err(),
1123
+ PollError::ShutDown
1124
+ );
1125
+ worker.shutdown().await;
1126
+ worker.finalize_shutdown().await;
1127
+ }
1128
+
1129
+ #[rstest::rstest]
1130
+ #[case::application_failure(
1131
+ FailureInfo::ApplicationFailureInfo(ApplicationFailureInfo {
1132
+ r#type: "MyAppError".to_string(),
1133
+ non_retryable: true,
1134
+ ..Default::default()
1135
+ }),
1136
+ NexusOperationErrorState::Failed
1137
+ )]
1138
+ #[case::canceled_failure(
1139
+ FailureInfo::CanceledFailureInfo(CanceledFailureInfo {
1140
+ details: None,
1141
+ }),
1142
+ NexusOperationErrorState::Canceled
1143
+ )]
1144
+ #[tokio::test]
1145
+ async fn nexus_start_operation_failure_converts_to_legacy_for_old_server(
1146
+ #[case] failure_info: FailureInfo,
1147
+ #[case] expected_operation_state: NexusOperationErrorState,
1148
+ ) {
1149
+ let expected_state = expected_operation_state.to_string();
1150
+ let mut client = mock_worker_client();
1151
+ client
1152
+ .expect_complete_nexus_task()
1153
+ .times(1)
1154
+ .withf(move |_, response| {
1155
+ matches!(response,
1156
+ nexus::v1::Response{
1157
+ variant: Some(response::Variant::StartOperation(StartOperationResponse {
1158
+ #[allow(deprecated)]
1159
+ variant: Some(
1160
+ start_operation_response::Variant::OperationError(
1161
+ UnsuccessfulOperationError{
1162
+ operation_state,
1163
+ failure: Some(nexus::v1::Failure{
1164
+ message,
1165
+ metadata,
1166
+ ..}),
1167
+ }
1168
+ ))
1169
+ }))
1170
+ }
1171
+ if message == "operation failed" &&
1172
+ operation_state.as_str() == expected_state &&
1173
+ metadata.get("type").unwrap() == "temporal.api.failure.v1.Failure"
1174
+ )
1175
+ })
1176
+ .returning(|_, _| Ok(RespondNexusTaskCompletedResponse::default()));
1177
+
1178
+ let mocks = MocksHolder::from_client_with_custom(
1179
+ client,
1180
+ None::<stream::Empty<PollWorkflowTaskQueueResponse>>,
1181
+ None::<Vec<QueueResponse<PollActivityTaskQueueResponse>>>,
1182
+ Some(vec![QueueResponse::from(create_test_nexus_task(
1183
+ None,
1184
+ Some(nexus::v1::request::Capabilities {
1185
+ temporal_failure_responses: false,
1186
+ }),
1187
+ ))]),
1188
+ );
1189
+ let worker = mock_worker(mocks);
1190
+
1191
+ let nexus_task = worker.poll_nexus_task().await.unwrap();
1192
+ worker
1193
+ .complete_nexus_task(create_nexus_completion_with_start_op_failure(
1194
+ nexus_task.task_token(),
1195
+ Failure {
1196
+ message: "operation failed".to_string(),
1197
+ failure_info: Some(failure_info),
1198
+ ..Default::default()
1199
+ },
1200
+ ))
1201
+ .await
1202
+ .unwrap();
1203
+
1204
+ worker.initiate_shutdown();
1205
+ assert_matches!(
1206
+ worker.poll_nexus_task().await.unwrap_err(),
1207
+ PollError::ShutDown
1208
+ );
1209
+ worker.shutdown().await;
1210
+ worker.finalize_shutdown().await;
1211
+ }