@temporalio/core-bridge 1.5.2 → 1.7.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 (194) hide show
  1. package/Cargo.lock +304 -112
  2. package/lib/index.d.ts +8 -6
  3. package/lib/index.js.map +1 -1
  4. package/package.json +9 -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/.buildkite/docker/Dockerfile +2 -2
  11. package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
  12. package/sdk-core/.buildkite/pipeline.yml +2 -4
  13. package/sdk-core/.cargo/config.toml +5 -2
  14. package/sdk-core/.github/workflows/heavy.yml +29 -0
  15. package/sdk-core/Cargo.toml +1 -1
  16. package/sdk-core/README.md +20 -10
  17. package/sdk-core/client/src/lib.rs +215 -39
  18. package/sdk-core/client/src/metrics.rs +17 -8
  19. package/sdk-core/client/src/raw.rs +4 -4
  20. package/sdk-core/client/src/retry.rs +32 -20
  21. package/sdk-core/core/Cargo.toml +25 -12
  22. package/sdk-core/core/src/abstractions/take_cell.rs +28 -0
  23. package/sdk-core/core/src/abstractions.rs +204 -14
  24. package/sdk-core/core/src/core_tests/activity_tasks.rs +143 -50
  25. package/sdk-core/core/src/core_tests/child_workflows.rs +6 -5
  26. package/sdk-core/core/src/core_tests/determinism.rs +165 -2
  27. package/sdk-core/core/src/core_tests/local_activities.rs +431 -43
  28. package/sdk-core/core/src/core_tests/queries.rs +34 -16
  29. package/sdk-core/core/src/core_tests/workers.rs +8 -5
  30. package/sdk-core/core/src/core_tests/workflow_tasks.rs +588 -55
  31. package/sdk-core/core/src/ephemeral_server/mod.rs +113 -12
  32. package/sdk-core/core/src/internal_flags.rs +155 -0
  33. package/sdk-core/core/src/lib.rs +16 -9
  34. package/sdk-core/core/src/protosext/mod.rs +1 -1
  35. package/sdk-core/core/src/replay/mod.rs +16 -27
  36. package/sdk-core/core/src/telemetry/log_export.rs +1 -1
  37. package/sdk-core/core/src/telemetry/metrics.rs +69 -35
  38. package/sdk-core/core/src/telemetry/mod.rs +60 -21
  39. package/sdk-core/core/src/telemetry/prometheus_server.rs +19 -13
  40. package/sdk-core/core/src/test_help/mod.rs +73 -14
  41. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +119 -160
  42. package/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
  43. package/sdk-core/core/src/worker/activities/local_activities.rs +379 -129
  44. package/sdk-core/core/src/worker/activities.rs +350 -175
  45. package/sdk-core/core/src/worker/client/mocks.rs +22 -2
  46. package/sdk-core/core/src/worker/client.rs +18 -2
  47. package/sdk-core/core/src/worker/mod.rs +183 -64
  48. package/sdk-core/core/src/worker/workflow/bridge.rs +1 -3
  49. package/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -5
  50. package/sdk-core/core/src/worker/workflow/history_update.rs +916 -277
  51. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +216 -183
  52. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +9 -12
  53. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +7 -9
  54. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +160 -87
  55. package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +13 -14
  56. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +7 -9
  57. package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +14 -17
  58. package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +242 -110
  59. package/sdk-core/core/src/worker/workflow/machines/mod.rs +27 -19
  60. package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +9 -11
  61. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +321 -206
  62. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +13 -18
  63. package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +20 -29
  64. package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +2 -2
  65. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +257 -51
  66. package/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +6 -17
  67. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +310 -150
  68. package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +17 -20
  69. package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +31 -15
  70. package/sdk-core/core/src/worker/workflow/managed_run.rs +1052 -380
  71. package/sdk-core/core/src/worker/workflow/mod.rs +598 -390
  72. package/sdk-core/core/src/worker/workflow/run_cache.rs +40 -57
  73. package/sdk-core/core/src/worker/workflow/wft_extraction.rs +137 -0
  74. package/sdk-core/core/src/worker/workflow/wft_poller.rs +1 -4
  75. package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +117 -0
  76. package/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +24 -0
  77. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +469 -718
  78. package/sdk-core/core-api/Cargo.toml +2 -1
  79. package/sdk-core/core-api/src/errors.rs +1 -34
  80. package/sdk-core/core-api/src/lib.rs +19 -9
  81. package/sdk-core/core-api/src/telemetry.rs +4 -6
  82. package/sdk-core/core-api/src/worker.rs +19 -1
  83. package/sdk-core/etc/deps.svg +115 -140
  84. package/sdk-core/etc/regen-depgraph.sh +5 -0
  85. package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +86 -61
  86. package/sdk-core/fsm/rustfsm_trait/src/lib.rs +29 -71
  87. package/sdk-core/histories/ends_empty_wft_complete.bin +0 -0
  88. package/sdk-core/histories/evict_while_la_running_no_interference-16_history.bin +0 -0
  89. package/sdk-core/histories/old_change_marker_format.bin +0 -0
  90. package/sdk-core/protos/api_upstream/.github/CODEOWNERS +2 -1
  91. package/sdk-core/protos/api_upstream/Makefile +6 -6
  92. package/sdk-core/protos/api_upstream/build/go.mod +7 -0
  93. package/sdk-core/protos/api_upstream/build/go.sum +5 -0
  94. package/sdk-core/protos/api_upstream/build/tools.go +29 -0
  95. package/sdk-core/protos/api_upstream/go.mod +6 -0
  96. package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +9 -2
  97. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +7 -26
  98. package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +13 -2
  99. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +3 -2
  100. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +3 -7
  101. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +3 -2
  102. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +8 -8
  103. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +25 -2
  104. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +2 -2
  105. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +2 -2
  106. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +2 -2
  107. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +2 -2
  108. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +2 -2
  109. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +24 -19
  110. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +2 -2
  111. package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +2 -2
  112. package/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +2 -2
  113. package/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +2 -2
  114. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +49 -26
  115. package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +4 -2
  116. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +5 -2
  117. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +2 -2
  118. package/sdk-core/protos/api_upstream/temporal/api/protocol/v1/message.proto +57 -0
  119. package/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +2 -2
  120. package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +2 -2
  121. package/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +2 -2
  122. package/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
  123. package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -2
  124. package/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +71 -6
  125. package/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +2 -2
  126. package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +2 -2
  127. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +64 -28
  128. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +4 -4
  129. package/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +7 -8
  130. package/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +10 -7
  131. package/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +19 -30
  132. package/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
  133. package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
  134. package/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +8 -0
  135. package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +67 -60
  136. package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +85 -84
  137. package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +9 -3
  138. package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +2 -2
  139. package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +2 -2
  140. package/sdk-core/sdk/Cargo.toml +5 -4
  141. package/sdk-core/sdk/src/lib.rs +108 -26
  142. package/sdk-core/sdk/src/workflow_context/options.rs +7 -1
  143. package/sdk-core/sdk/src/workflow_context.rs +24 -17
  144. package/sdk-core/sdk/src/workflow_future.rs +16 -15
  145. package/sdk-core/sdk-core-protos/Cargo.toml +5 -2
  146. package/sdk-core/sdk-core-protos/build.rs +36 -2
  147. package/sdk-core/sdk-core-protos/src/history_builder.rs +138 -106
  148. package/sdk-core/sdk-core-protos/src/history_info.rs +10 -1
  149. package/sdk-core/sdk-core-protos/src/lib.rs +272 -87
  150. package/sdk-core/sdk-core-protos/src/task_token.rs +12 -2
  151. package/sdk-core/test-utils/Cargo.toml +3 -1
  152. package/sdk-core/test-utils/src/canned_histories.rs +106 -296
  153. package/sdk-core/test-utils/src/histfetch.rs +1 -1
  154. package/sdk-core/test-utils/src/lib.rs +82 -23
  155. package/sdk-core/test-utils/src/wf_input_saver.rs +50 -0
  156. package/sdk-core/test-utils/src/workflows.rs +29 -0
  157. package/sdk-core/tests/fuzzy_workflow.rs +130 -0
  158. package/sdk-core/tests/{load_tests.rs → heavy_tests.rs} +125 -51
  159. package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
  160. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +10 -5
  161. package/sdk-core/tests/integ_tests/metrics_tests.rs +218 -16
  162. package/sdk-core/tests/integ_tests/polling_tests.rs +4 -47
  163. package/sdk-core/tests/integ_tests/queries_tests.rs +5 -128
  164. package/sdk-core/tests/integ_tests/visibility_tests.rs +83 -25
  165. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +161 -72
  166. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
  167. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +6 -13
  168. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +80 -3
  169. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +6 -2
  170. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -10
  171. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +94 -200
  172. package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +2 -4
  173. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +34 -28
  174. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +76 -7
  175. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
  176. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +18 -14
  177. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +6 -20
  178. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +10 -21
  179. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +7 -8
  180. package/sdk-core/tests/integ_tests/workflow_tests.rs +13 -14
  181. package/sdk-core/tests/main.rs +3 -13
  182. package/sdk-core/tests/runner.rs +75 -36
  183. package/sdk-core/tests/wf_input_replay.rs +32 -0
  184. package/src/conversions.rs +14 -8
  185. package/src/runtime.rs +9 -8
  186. package/ts/index.ts +8 -6
  187. package/sdk-core/bridge-ffi/Cargo.toml +0 -24
  188. package/sdk-core/bridge-ffi/LICENSE.txt +0 -23
  189. package/sdk-core/bridge-ffi/build.rs +0 -25
  190. package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +0 -224
  191. package/sdk-core/bridge-ffi/src/lib.rs +0 -746
  192. package/sdk-core/bridge-ffi/src/wrappers.rs +0 -221
  193. package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +0 -210
  194. package/sdk-core/sdk/src/conversions.rs +0 -8
@@ -14,21 +14,22 @@ categories = ["development-tools"]
14
14
 
15
15
  [dependencies]
16
16
  async-trait = "0.1"
17
+ thiserror = "1.0"
17
18
  anyhow = "1.0"
18
- base64 = "0.13"
19
+ base64 = "0.21"
19
20
  crossbeam = "0.8"
20
21
  derive_more = "0.99"
21
22
  futures = "0.3"
22
23
  once_cell = "1.10"
23
24
  parking_lot = { version = "0.12", features = ["send_guard"] }
24
- prost-types = "0.11"
25
+ prost-types = { version = "0.4", package = "prost-wkt-types" }
25
26
  sha2 = "0.10"
26
27
  serde = "1.0"
27
- tokio = { version = "1.1", features = ["rt", "rt-multi-thread", "parking_lot", "time", "fs"] }
28
+ tokio = { version = "1.26", features = ["rt", "rt-multi-thread", "parking_lot", "time", "fs"] }
28
29
  tokio-util = { version = "0.7" }
29
30
  tokio-stream = "0.1"
30
31
  tonic = "0.8"
31
- tracing = { version = "0.1", features = ["log-always"] }
32
+ tracing = "0.1"
32
33
 
33
34
  [dependencies.temporal-sdk-core]
34
35
  path = "../core"
@@ -46,7 +46,6 @@ extern crate tracing;
46
46
 
47
47
  mod activity_context;
48
48
  mod app_data;
49
- mod conversions;
50
49
  pub mod interceptors;
51
50
  mod payload_converter;
52
51
  mod workflow_context;
@@ -67,10 +66,12 @@ use anyhow::{anyhow, bail, Context};
67
66
  use app_data::AppData;
68
67
  use futures::{future::BoxFuture, FutureExt, StreamExt, TryFutureExt, TryStreamExt};
69
68
  use std::{
69
+ any::{Any, TypeId},
70
70
  cell::RefCell,
71
71
  collections::HashMap,
72
72
  fmt::{Debug, Display, Formatter},
73
73
  future::Future,
74
+ panic::AssertUnwindSafe,
74
75
  sync::Arc,
75
76
  };
76
77
  use temporal_client::ClientOptionsBuilder;
@@ -87,7 +88,7 @@ use temporal_sdk_core_protos::{
87
88
  common::NamespacedWorkflowExecution,
88
89
  workflow_activation::{
89
90
  resolve_child_workflow_execution_start::Status as ChildWorkflowStartStatus,
90
- workflow_activation_job::Variant, WorkflowActivation, WorkflowActivationJob,
91
+ workflow_activation_job::Variant, WorkflowActivation,
91
92
  },
92
93
  workflow_commands::{workflow_command, ContinueAsNewWorkflowExecution},
93
94
  workflow_completion::WorkflowActivationCompletion,
@@ -307,22 +308,17 @@ impl Worker {
307
308
  // makes tests which use mocks dramatically more manageable.
308
309
  async {
309
310
  if !act_half.activity_fns.is_empty() {
310
- let shutdown_token = shutdown_token.clone();
311
311
  loop {
312
- tokio::select! {
313
- activity = common.worker.poll_activity_task() => {
314
- if matches!(activity, Err(PollActivityError::ShutDown)) {
315
- break;
316
- }
317
- act_half.activity_task_handler(
318
- common.worker.clone(),
319
- safe_app_data.clone(),
320
- common.task_queue.clone(),
321
- activity?
322
- )?;
323
- },
324
- _ = shutdown_token.cancelled() => { break }
312
+ let activity = common.worker.poll_activity_task().await;
313
+ if matches!(activity, Err(PollActivityError::ShutDown)) {
314
+ break;
325
315
  }
316
+ act_half.activity_task_handler(
317
+ common.worker.clone(),
318
+ safe_app_data.clone(),
319
+ common.task_queue.clone(),
320
+ activity?,
321
+ )?;
326
322
  }
327
323
  };
328
324
  Result::<_, anyhow::Error>::Ok(())
@@ -336,6 +332,7 @@ impl Worker {
336
332
  i.on_shutdown(self);
337
333
  }
338
334
  self.common.worker.shutdown().await;
335
+ debug!("Worker shutdown complete");
339
336
  self.app_data = Some(
340
337
  Arc::try_unwrap(safe_app_data)
341
338
  .map_err(|_| anyhow!("some references of AppData exist on worker shutdown"))?,
@@ -394,10 +391,10 @@ impl WorkflowHalf {
394
391
 
395
392
  // If the activation is to start a workflow, create a new workflow driver for it,
396
393
  // using the function associated with that workflow id
397
- if let Some(WorkflowActivationJob {
398
- variant: Some(Variant::StartWorkflow(sw)),
399
- }) = activation.jobs.get(0)
400
- {
394
+ if let Some(sw) = activation.jobs.iter().find_map(|j| match j.variant {
395
+ Some(Variant::StartWorkflow(ref sw)) => Some(sw),
396
+ _ => None,
397
+ }) {
401
398
  let workflow_type = &sw.workflow_type;
402
399
  let wf_fns_borrow = self.workflow_fns.borrow();
403
400
  let wf_function = wf_fns_borrow
@@ -413,7 +410,7 @@ impl WorkflowHalf {
413
410
  );
414
411
  let jh = tokio::spawn(async move {
415
412
  tokio::select! {
416
- r = wff => r,
413
+ r = wff.fuse() => r,
417
414
  // TODO: This probably shouldn't abort early, as it could cause an in-progress
418
415
  // complete to abort. Send synthetic remove activation
419
416
  _ = shutdown_token.cancelled() => {
@@ -486,15 +483,30 @@ impl ActivityHalf {
486
483
  start,
487
484
  );
488
485
  tokio::spawn(async move {
489
- let output = (act_fn.act_func)(ctx, arg).await;
486
+ let output = AssertUnwindSafe((act_fn.act_func)(ctx, arg))
487
+ .catch_unwind()
488
+ .await;
490
489
  let result = match output {
491
- Ok(ActExitValue::Normal(p)) => ActivityExecutionResult::ok(p),
492
- Ok(ActExitValue::WillCompleteAsync) => {
490
+ Err(e) => ActivityExecutionResult::fail(Failure::application_failure(
491
+ format!("Activity function panicked: {}", panic_formatter(e)),
492
+ true,
493
+ )),
494
+ Ok(Ok(ActExitValue::Normal(p))) => ActivityExecutionResult::ok(p),
495
+ Ok(Ok(ActExitValue::WillCompleteAsync)) => {
493
496
  ActivityExecutionResult::will_complete_async()
494
497
  }
495
- Err(err) => match err.downcast::<ActivityCancelledError>() {
498
+ Ok(Err(err)) => match err.downcast::<ActivityCancelledError>() {
496
499
  Ok(ce) => ActivityExecutionResult::cancel_from_details(ce.details),
497
- Err(other_err) => ActivityExecutionResult::fail(other_err.into()),
500
+ Err(other_err) => {
501
+ match other_err.downcast::<NonRetryableActivityError>() {
502
+ Ok(nre) => ActivityExecutionResult::fail(
503
+ Failure::application_failure_from_error(nre.into(), true),
504
+ ),
505
+ Err(other_err) => ActivityExecutionResult::fail(
506
+ Failure::application_failure_from_error(other_err, false),
507
+ ),
508
+ }
509
+ }
498
510
  },
499
511
  };
500
512
  worker
@@ -537,11 +549,13 @@ pub enum TimerResult {
537
549
  }
538
550
 
539
551
  /// Successful result of sending a signal to an external workflow
552
+ #[derive(Debug)]
540
553
  pub struct SignalExternalOk;
541
554
  /// Result of awaiting on sending a signal to an external workflow
542
555
  pub type SignalExternalWfResult = Result<SignalExternalOk, Failure>;
543
556
 
544
557
  /// Successful result of sending a cancel request to an external workflow
558
+ #[derive(Debug)]
545
559
  pub struct CancelExternalOk;
546
560
  /// Result of awaiting on sending a cancel request to an external workflow
547
561
  pub type CancelExternalWfResult = Result<CancelExternalOk, Failure>;
@@ -644,6 +658,20 @@ pub enum CancellableID {
644
658
  },
645
659
  }
646
660
 
661
+ impl CancellableID {
662
+ /// Returns the type-specific sequence number used for this command
663
+ pub fn seq_num(&self) -> u32 {
664
+ match self {
665
+ CancellableID::Timer(seq) => *seq,
666
+ CancellableID::Activity(seq) => *seq,
667
+ CancellableID::LocalActivity(seq) => *seq,
668
+ CancellableID::ChildWorkflow(seq) => *seq,
669
+ CancellableID::SignalExternalWorkflow(seq) => *seq,
670
+ CancellableID::ExternalWorkflow { seqnum, .. } => *seqnum,
671
+ }
672
+ }
673
+ }
674
+
647
675
  #[derive(derive_more::From)]
648
676
  #[allow(clippy::large_enum_variant)]
649
677
  enum RustWfCmd {
@@ -749,6 +777,14 @@ pub struct ActivityFunction {
749
777
  pub struct ActivityCancelledError {
750
778
  details: Option<Payload>,
751
779
  }
780
+ impl ActivityCancelledError {
781
+ /// Include some details as part of concluding the activity as cancelled
782
+ pub fn with_details(payload: Payload) -> Self {
783
+ Self {
784
+ details: Some(payload),
785
+ }
786
+ }
787
+ }
752
788
  impl std::error::Error for ActivityCancelledError {}
753
789
  impl Display for ActivityCancelledError {
754
790
  fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
@@ -756,6 +792,16 @@ impl Display for ActivityCancelledError {
756
792
  }
757
793
  }
758
794
 
795
+ /// Return this error to indicate that your activity non-retryable
796
+ /// this is a transparent wrapper around anyhow Error so essentially any type of error
797
+ /// could be used here.
798
+ ///
799
+ /// In your activity function. Return something along the lines of:
800
+ /// `Err(NonRetryableActivityError(anyhow::anyhow!("This should *not* be retried")).into())`
801
+ #[derive(Debug, thiserror::Error)]
802
+ #[error(transparent)]
803
+ pub struct NonRetryableActivityError(pub anyhow::Error);
804
+
759
805
  /// Closures / functions which can be turned into activity functions implement this trait
760
806
  pub trait IntoActivityFunc<Args, Res, Out> {
761
807
  /// Consume the closure or fn pointer and turned it into a boxed activity function
@@ -793,3 +839,39 @@ where
793
839
  Arc::new(wrapper)
794
840
  }
795
841
  }
842
+
843
+ /// Attempts to turn caught panics into something printable
844
+ fn panic_formatter(panic: Box<dyn Any>) -> Box<dyn Display> {
845
+ _panic_formatter::<&str>(panic)
846
+ }
847
+ fn _panic_formatter<T: 'static + PrintablePanicType>(panic: Box<dyn Any>) -> Box<dyn Display> {
848
+ match panic.downcast::<T>() {
849
+ Ok(d) => d,
850
+ Err(orig) => {
851
+ if TypeId::of::<<T as PrintablePanicType>::NextType>()
852
+ == TypeId::of::<EndPrintingAttempts>()
853
+ {
854
+ return Box::new("Couldn't turn panic into a string");
855
+ }
856
+ _panic_formatter::<T::NextType>(orig)
857
+ }
858
+ }
859
+ }
860
+ trait PrintablePanicType: Display {
861
+ type NextType: PrintablePanicType;
862
+ }
863
+ impl PrintablePanicType for &str {
864
+ type NextType = String;
865
+ }
866
+ impl PrintablePanicType for String {
867
+ type NextType = EndPrintingAttempts;
868
+ }
869
+ struct EndPrintingAttempts {}
870
+ impl Display for EndPrintingAttempts {
871
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
872
+ write!(f, "Will never be printed")
873
+ }
874
+ }
875
+ impl PrintablePanicType for EndPrintingAttempts {
876
+ type NextType = EndPrintingAttempts;
877
+ }
@@ -9,7 +9,10 @@ use temporal_sdk_core_protos::{
9
9
  StartChildWorkflowExecution,
10
10
  },
11
11
  },
12
- temporal::api::common::v1::{Payload, RetryPolicy},
12
+ temporal::api::{
13
+ common::v1::{Payload, RetryPolicy},
14
+ enums::v1::ParentClosePolicy,
15
+ },
13
16
  };
14
17
 
15
18
  // TODO: Before release, probably best to avoid using proto types entirely here. They're awkward.
@@ -180,6 +183,8 @@ pub struct ChildWorkflowOptions {
180
183
  pub cancel_type: ChildWorkflowCancellationType,
181
184
  /// Common options
182
185
  pub options: WorkflowOptions,
186
+ /// How to respond to parent workflow ending
187
+ pub parent_close_policy: ParentClosePolicy,
183
188
  }
184
189
 
185
190
  impl IntoWorkflowCommand for ChildWorkflowOptions {
@@ -203,6 +208,7 @@ impl IntoWorkflowCommand for ChildWorkflowOptions {
203
208
  workflow_task_timeout: self.options.task_timeout.and_then(|d| d.try_into().ok()),
204
209
  search_attributes: self.options.search_attributes.unwrap_or_default(),
205
210
  cron_schedule: self.options.cron_schedule.unwrap_or_default(),
211
+ parent_close_policy: self.parent_close_policy as i32,
206
212
  ..Default::default()
207
213
  }
208
214
  }
@@ -34,7 +34,8 @@ use temporal_sdk_core_protos::{
34
34
  workflow_commands::{
35
35
  request_cancel_external_workflow_execution as cancel_we,
36
36
  signal_external_workflow_execution as sig_we, workflow_command,
37
- ModifyWorkflowProperties, RequestCancelExternalWorkflowExecution, SetPatchMarker,
37
+ CancelChildWorkflowExecution, ModifyWorkflowProperties,
38
+ RequestCancelExternalWorkflowExecution, SetPatchMarker,
38
39
  SignalExternalWorkflowExecution, StartTimer, UpsertWorkflowSearchAttributes,
39
40
  },
40
41
  },
@@ -98,6 +99,7 @@ pub struct WfContextSharedData {
98
99
  pub changes: HashMap<String, bool>,
99
100
  pub is_replaying: bool,
100
101
  pub wf_time: Option<SystemTime>,
102
+ pub history_length: u32,
101
103
  }
102
104
 
103
105
  // TODO: Dataconverter type interface to replace Payloads here. Possibly just use serde
@@ -148,6 +150,11 @@ impl WfContext {
148
150
  self.shared.read().wf_time
149
151
  }
150
152
 
153
+ /// Return the length of history so far at this point in the workflow
154
+ pub fn history_length(&self) -> u32 {
155
+ self.shared.read().history_length
156
+ }
157
+
151
158
  pub(crate) fn get_shared_data(&self) -> Arc<RwLock<WfContextSharedData>> {
152
159
  self.shared.clone()
153
160
  }
@@ -550,16 +557,16 @@ impl<'a> Future for LATimerBackoffFut<'a> {
550
557
  }
551
558
  let poll_res = self.current_fut.poll_unpin(cx);
552
559
  if let Poll::Ready(ref r) = poll_res {
553
- // If we've already said we want to cancel, don't schedule the backoff timer. Just
554
- // return cancel status. This can happen if cancel comes after the LA says it wants to
555
- // back off but before we have scheduled the timer.
556
- if self.did_cancel.load(Ordering::Acquire) {
557
- return Poll::Ready(ActivityResolution {
558
- status: Some(activity_resolution::Status::Cancelled(Default::default())),
559
- });
560
- }
561
-
562
560
  if let Some(activity_resolution::Status::Backoff(b)) = r.status.as_ref() {
561
+ // If we've already said we want to cancel, don't schedule the backoff timer. Just
562
+ // return cancel status. This can happen if cancel comes after the LA says it wants
563
+ // to back off but before we have scheduled the timer.
564
+ if self.did_cancel.load(Ordering::Acquire) {
565
+ return Poll::Ready(ActivityResolution {
566
+ status: Some(activity_resolution::Status::Cancelled(Default::default())),
567
+ });
568
+ }
569
+
563
570
  let timer_f = self.ctx.timer(
564
571
  b.backoff_duration
565
572
  .clone()
@@ -673,13 +680,13 @@ impl StartedChildWorkflow {
673
680
  }
674
681
 
675
682
  /// Cancel the child workflow
676
- pub fn cancel(&self, cx: &WfContext) -> impl Future<Output = CancelExternalWfResult> {
677
- let target = NamespacedWorkflowExecution {
678
- namespace: cx.namespace().to_string(),
679
- workflow_id: self.common.workflow_id.clone(),
680
- ..Default::default()
681
- };
682
- cx.cancel_external(target)
683
+ pub fn cancel(&self, cx: &WfContext) {
684
+ cx.send(RustWfCmd::NewNonblockingCmd(
685
+ CancelChildWorkflowExecution {
686
+ child_workflow_seq: self.common.result_future.cancellable_id.seq_num(),
687
+ }
688
+ .into(),
689
+ ));
683
690
  }
684
691
 
685
692
  /// Signal the child workflow
@@ -1,7 +1,6 @@
1
1
  use crate::{
2
- conversions::anyhow_to_fail, workflow_context::WfContextSharedData, CancellableID, RustWfCmd,
3
- SignalData, TimerResult, UnblockEvent, WfContext, WfExitValue, WorkflowFunction,
4
- WorkflowResult,
2
+ panic_formatter, workflow_context::WfContextSharedData, CancellableID, RustWfCmd, SignalData,
3
+ TimerResult, UnblockEvent, WfContext, WfExitValue, WorkflowFunction, WorkflowResult,
5
4
  };
6
5
  use anyhow::{anyhow, bail, Context as AnyhowContext, Error};
7
6
  use crossbeam::channel::Receiver;
@@ -63,7 +62,9 @@ impl WorkflowFunction {
63
62
  // We need to mark the workflow future as unconstrained, otherwise Tokio will impose
64
63
  // an artificial limit on how many commands we can unblock in one poll round.
65
64
  // TODO: Now we *need* deadlock detection or we could hose the whole system
66
- inner: tokio::task::unconstrained((self.wf_func)(wf_context)).boxed(),
65
+ inner: tokio::task::unconstrained((self.wf_func)(wf_context))
66
+ .fuse()
67
+ .boxed(),
67
68
  incoming_commands: cmd_receiver,
68
69
  outgoing_completions,
69
70
  incoming_activations,
@@ -132,10 +133,7 @@ impl WorkflowFuture {
132
133
  fn fail_wft(&self, run_id: String, fail: Error) {
133
134
  warn!("Workflow task failed for {}: {}", run_id, fail);
134
135
  self.outgoing_completions
135
- .send(WorkflowActivationCompletion::fail(
136
- run_id,
137
- anyhow_to_fail(fail),
138
- ))
136
+ .send(WorkflowActivationCompletion::fail(run_id, fail.into()))
139
137
  .expect("Completion channel intact");
140
138
  }
141
139
 
@@ -183,8 +181,11 @@ impl WorkflowFuture {
183
181
  Box::new(result.context("Child Workflow execution must have a result")?),
184
182
  ))?,
185
183
  Variant::UpdateRandomSeed(_) => (),
186
- Variant::QueryWorkflow(_) => {
187
- todo!()
184
+ Variant::QueryWorkflow(q) => {
185
+ error!(
186
+ "Queries are not implemented in the Rust SDK. Got query '{}'",
187
+ q.query_id
188
+ );
188
189
  }
189
190
  Variant::CancelWorkflow(_) => {
190
191
  // TODO: Cancel pending futures, etc
@@ -218,6 +219,9 @@ impl WorkflowFuture {
218
219
  }
219
220
 
220
221
  Variant::RemoveFromCache(_) => {
222
+ // TODO: Need to abort any spawned tasks, etc. See also cancel WF.
223
+ // How best to do this in executor agnostic way? Is that possible?
224
+ // -- tokio JoinSet does this in a nice way.
221
225
  return Ok(true);
222
226
  }
223
227
  }
@@ -253,6 +257,7 @@ impl Future for WorkflowFuture {
253
257
  let mut wlock = self.ctx_shared.write();
254
258
  wlock.is_replaying = activation.is_replaying;
255
259
  wlock.wf_time = activation.timestamp.try_into_or_none();
260
+ wlock.history_length = activation.history_length;
256
261
  }
257
262
 
258
263
  let mut die_of_eviction_when_done = false;
@@ -283,11 +288,7 @@ impl Future for WorkflowFuture {
283
288
  .poll_unpin(cx)
284
289
  {
285
290
  Poll::Ready(Err(e)) => {
286
- let errmsg = format!(
287
- "Workflow function panicked: {:?}",
288
- // Panics are typically strings
289
- e.downcast::<String>()
290
- );
291
+ let errmsg = format!("Workflow function panicked: {}", panic_formatter(e));
291
292
  warn!("{}", errmsg);
292
293
  self.outgoing_completions
293
294
  .send(WorkflowActivationCompletion::fail(
@@ -12,13 +12,15 @@ categories = ["development-tools"]
12
12
 
13
13
  [features]
14
14
  history_builders = ["uuid", "rand"]
15
+ serde_serialize = []
15
16
 
16
17
  [dependencies]
17
18
  anyhow = "1.0"
18
- base64 = "0.13"
19
+ base64 = "0.21"
19
20
  derive_more = "0.99"
20
21
  prost = "0.11"
21
- prost-types = "0.11"
22
+ prost-wkt = "0.4"
23
+ prost-wkt-types = "0.4"
22
24
  rand = { version = "0.8", optional = true }
23
25
  serde = { version = "1.0", features = ["derive"] }
24
26
  serde_json = "1.0"
@@ -28,3 +30,4 @@ uuid = { version = "1.1", features = ["v4"], optional = true }
28
30
 
29
31
  [build-dependencies]
30
32
  tonic-build = "0.8"
33
+ prost-wkt-build = "0.4"
@@ -1,5 +1,9 @@
1
+ use std::{env, path::PathBuf};
2
+
1
3
  fn main() -> Result<(), Box<dyn std::error::Error>> {
2
4
  println!("cargo:rerun-if-changed=../protos");
5
+ let out = PathBuf::from(env::var("OUT_DIR").unwrap());
6
+ let descriptor_file = out.join("descriptors.bin");
3
7
  tonic_build::configure()
4
8
  // We don't actually want to build the grpc definitions - we don't need them (for now).
5
9
  // Just build the message structs.
@@ -74,7 +78,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
74
78
  // All external data is useful to be able to JSON serialize, so it can render in web UI
75
79
  .type_attribute(
76
80
  ".coresdk.external_data",
77
- "#[derive(::serde::Serialize, ::serde::Deserialize)]",
81
+ "#[cfg_attr(not(feature = \"serde_serialize\"), derive(::serde::Serialize, ::serde::Deserialize))]",
82
+ )
83
+ .type_attribute(
84
+ ".",
85
+ "#[cfg_attr(feature = \"serde_serialize\", derive(::serde::Serialize, ::serde::Deserialize))]",
78
86
  )
79
87
  .field_attribute(
80
88
  "coresdk.external_data.LocalActivityMarkerData.complete_time",
@@ -88,10 +96,26 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
88
96
  "coresdk.external_data.LocalActivityMarkerData.backoff",
89
97
  "#[serde(with = \"opt_duration\")]",
90
98
  )
99
+ .extern_path(
100
+ ".google.protobuf.Any",
101
+ "::prost_wkt_types::Any"
102
+ )
103
+ .extern_path(
104
+ ".google.protobuf.Timestamp",
105
+ "::prost_wkt_types::Timestamp"
106
+ )
107
+ .extern_path(
108
+ ".google.protobuf.Duration",
109
+ "::prost_wkt_types::Duration"
110
+ )
111
+ .extern_path(
112
+ ".google.protobuf.Value",
113
+ "::prost_wkt_types::Value"
114
+ )
115
+ .file_descriptor_set_path(#[allow(clippy::needless_borrow)] &descriptor_file)
91
116
  .compile(
92
117
  &[
93
118
  "../protos/local/temporal/sdk/core/core_interface.proto",
94
- "../protos/local/temporal/sdk/core/bridge/bridge.proto",
95
119
  "../protos/api_upstream/temporal/api/workflowservice/v1/service.proto",
96
120
  "../protos/api_upstream/temporal/api/operatorservice/v1/service.proto",
97
121
  "../protos/testsrv_upstream/temporal/api/testservice/v1/service.proto",
@@ -104,5 +128,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
104
128
  "../protos/grpc",
105
129
  ],
106
130
  )?;
131
+
132
+ #[cfg(feature = "serde_serialize")]
133
+ {
134
+ use prost_wkt_build::{FileDescriptorSet, Message};
135
+
136
+ let descriptor_bytes = std::fs::read(descriptor_file)?;
137
+ let descriptor = FileDescriptorSet::decode(&descriptor_bytes[..])?;
138
+ prost_wkt_build::add_serde(out, descriptor);
139
+ }
140
+
107
141
  Ok(())
108
142
  }