@temporalio/core-bridge 1.9.2 → 1.10.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 (177) hide show
  1. package/Cargo.lock +754 -473
  2. package/Cargo.toml +3 -3
  3. package/lib/index.d.ts +33 -2
  4. package/lib/index.js.map +1 -1
  5. package/package.json +4 -4
  6. package/releases/aarch64-apple-darwin/index.node +0 -0
  7. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  8. package/releases/x86_64-apple-darwin/index.node +0 -0
  9. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  10. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  11. package/scripts/build.js +4 -3
  12. package/sdk-core/.cargo/config.toml +2 -4
  13. package/sdk-core/.github/workflows/heavy.yml +1 -1
  14. package/sdk-core/.github/workflows/per-pr.yml +6 -4
  15. package/sdk-core/Cargo.toml +10 -3
  16. package/sdk-core/README.md +4 -6
  17. package/sdk-core/client/Cargo.toml +13 -5
  18. package/sdk-core/client/src/lib.rs +123 -34
  19. package/sdk-core/client/src/metrics.rs +70 -18
  20. package/sdk-core/client/src/proxy.rs +85 -0
  21. package/sdk-core/client/src/raw.rs +67 -5
  22. package/sdk-core/client/src/worker_registry/mod.rs +5 -3
  23. package/sdk-core/client/src/workflow_handle/mod.rs +3 -1
  24. package/sdk-core/core/Cargo.toml +31 -37
  25. package/sdk-core/core/src/abstractions/take_cell.rs +3 -3
  26. package/sdk-core/core/src/abstractions.rs +176 -108
  27. package/sdk-core/core/src/core_tests/activity_tasks.rs +4 -13
  28. package/sdk-core/core/src/core_tests/determinism.rs +2 -1
  29. package/sdk-core/core/src/core_tests/local_activities.rs +3 -3
  30. package/sdk-core/core/src/core_tests/mod.rs +3 -3
  31. package/sdk-core/core/src/core_tests/queries.rs +42 -5
  32. package/sdk-core/core/src/core_tests/workers.rs +2 -3
  33. package/sdk-core/core/src/core_tests/workflow_tasks.rs +115 -15
  34. package/sdk-core/core/src/ephemeral_server/mod.rs +109 -136
  35. package/sdk-core/core/src/internal_flags.rs +8 -8
  36. package/sdk-core/core/src/lib.rs +16 -11
  37. package/sdk-core/core/src/pollers/mod.rs +11 -5
  38. package/sdk-core/core/src/pollers/poll_buffer.rs +48 -29
  39. package/sdk-core/core/src/protosext/mod.rs +32 -32
  40. package/sdk-core/core/src/protosext/protocol_messages.rs +14 -24
  41. package/sdk-core/core/src/retry_logic.rs +2 -2
  42. package/sdk-core/core/src/telemetry/log_export.rs +10 -9
  43. package/sdk-core/core/src/telemetry/metrics.rs +233 -330
  44. package/sdk-core/core/src/telemetry/mod.rs +11 -38
  45. package/sdk-core/core/src/telemetry/otel.rs +355 -0
  46. package/sdk-core/core/src/telemetry/prometheus_server.rs +36 -23
  47. package/sdk-core/core/src/test_help/mod.rs +80 -59
  48. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +6 -6
  49. package/sdk-core/core/src/worker/activities/local_activities.rs +46 -43
  50. package/sdk-core/core/src/worker/activities.rs +45 -46
  51. package/sdk-core/core/src/worker/client/mocks.rs +8 -7
  52. package/sdk-core/core/src/worker/client.rs +40 -39
  53. package/sdk-core/core/src/worker/mod.rs +72 -42
  54. package/sdk-core/core/src/worker/slot_provider.rs +28 -28
  55. package/sdk-core/core/src/worker/slot_supplier.rs +1 -0
  56. package/sdk-core/core/src/worker/tuner/fixed_size.rs +52 -0
  57. package/sdk-core/core/src/worker/tuner/resource_based.rs +561 -0
  58. package/sdk-core/core/src/worker/tuner.rs +122 -0
  59. package/sdk-core/core/src/worker/workflow/driven_workflow.rs +6 -6
  60. package/sdk-core/core/src/worker/workflow/history_update.rs +27 -53
  61. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +4 -17
  62. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +1 -10
  63. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +4 -11
  64. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +17 -35
  65. package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +0 -8
  66. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +1 -5
  67. package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +0 -5
  68. package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +0 -5
  69. package/sdk-core/core/src/worker/workflow/machines/mod.rs +0 -14
  70. package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +0 -5
  71. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +0 -5
  72. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +1 -10
  73. package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +3 -10
  74. package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +12 -8
  75. package/sdk-core/core/src/worker/workflow/machines/update_state_machine.rs +0 -10
  76. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +6 -13
  77. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +27 -37
  78. package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +3 -14
  79. package/sdk-core/core/src/worker/workflow/managed_run.rs +84 -54
  80. package/sdk-core/core/src/worker/workflow/mod.rs +63 -160
  81. package/sdk-core/core/src/worker/workflow/run_cache.rs +22 -13
  82. package/sdk-core/core/src/worker/workflow/wft_extraction.rs +16 -3
  83. package/sdk-core/core/src/worker/workflow/wft_poller.rs +15 -12
  84. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +39 -78
  85. package/sdk-core/core-api/Cargo.toml +6 -5
  86. package/sdk-core/core-api/src/errors.rs +8 -0
  87. package/sdk-core/core-api/src/telemetry/metrics.rs +75 -4
  88. package/sdk-core/core-api/src/telemetry.rs +7 -1
  89. package/sdk-core/core-api/src/worker.rs +212 -56
  90. package/sdk-core/fsm/Cargo.toml +3 -0
  91. package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +1 -1
  92. package/sdk-core/sdk/Cargo.toml +5 -7
  93. package/sdk-core/sdk/src/app_data.rs +3 -3
  94. package/sdk-core/sdk/src/lib.rs +5 -3
  95. package/sdk-core/sdk/src/workflow_context/options.rs +1 -1
  96. package/sdk-core/sdk/src/workflow_context.rs +10 -9
  97. package/sdk-core/sdk/src/workflow_future.rs +1 -1
  98. package/sdk-core/sdk-core-protos/Cargo.toml +8 -6
  99. package/sdk-core/sdk-core-protos/build.rs +1 -10
  100. package/sdk-core/sdk-core-protos/protos/api_upstream/.github/PULL_REQUEST_TEMPLATE.md +3 -0
  101. package/sdk-core/sdk-core-protos/protos/api_upstream/.github/workflows/ci.yml +26 -0
  102. package/sdk-core/sdk-core-protos/protos/api_upstream/Makefile +42 -20
  103. package/sdk-core/sdk-core-protos/protos/api_upstream/README.md +2 -0
  104. package/sdk-core/sdk-core-protos/protos/api_upstream/api-linter.yaml +36 -26
  105. package/sdk-core/sdk-core-protos/protos/api_upstream/buf.lock +2 -0
  106. package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/struct.proto +95 -0
  107. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv2.json +9632 -0
  108. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv3.yaml +7337 -0
  109. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/payload_description.txt +2 -0
  110. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/command/v1/message.proto +45 -11
  111. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/common/v1/message.proto +22 -4
  112. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/command_type.proto +2 -0
  113. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/common.proto +44 -0
  114. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/event_type.proto +18 -3
  115. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +20 -0
  116. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +30 -0
  117. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/update.proto +7 -8
  118. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/workflow.proto +23 -5
  119. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/errordetails/v1/message.proto +20 -0
  120. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/failure/v1/message.proto +25 -0
  121. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/history/v1/message.proto +141 -15
  122. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/namespace/v1/message.proto +12 -0
  123. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/nexus/v1/message.proto +193 -0
  124. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +73 -6
  125. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +46 -4
  126. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/schedule/v1/message.proto +4 -0
  127. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/workflow_metadata.proto +2 -2
  128. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +116 -0
  129. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflow/v1/message.proto +134 -0
  130. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +274 -29
  131. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +57 -1
  132. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +10 -12
  133. package/sdk-core/sdk-core-protos/src/history_builder.rs +1 -1
  134. package/sdk-core/sdk-core-protos/src/lib.rs +54 -51
  135. package/sdk-core/sdk-core-protos/src/task_token.rs +11 -2
  136. package/sdk-core/test-utils/Cargo.toml +7 -4
  137. package/sdk-core/test-utils/src/histfetch.rs +1 -1
  138. package/sdk-core/test-utils/src/lib.rs +44 -62
  139. package/sdk-core/tests/fuzzy_workflow.rs +5 -2
  140. package/sdk-core/tests/heavy_tests.rs +114 -17
  141. package/sdk-core/tests/integ_tests/activity_functions.rs +1 -1
  142. package/sdk-core/tests/integ_tests/client_tests.rs +2 -2
  143. package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +38 -26
  144. package/sdk-core/tests/integ_tests/metrics_tests.rs +126 -17
  145. package/sdk-core/tests/integ_tests/polling_tests.rs +118 -2
  146. package/sdk-core/tests/integ_tests/update_tests.rs +3 -5
  147. package/sdk-core/tests/integ_tests/visibility_tests.rs +3 -3
  148. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +1 -1
  149. package/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +1 -1
  150. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -1
  151. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -1
  152. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +3 -3
  153. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +5 -4
  154. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -2
  155. package/sdk-core/tests/integ_tests/workflow_tests/eager.rs +6 -10
  156. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +9 -7
  157. package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +1 -1
  158. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +14 -9
  159. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -1
  160. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +6 -13
  161. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +9 -6
  162. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +5 -5
  163. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +1 -1
  164. package/sdk-core/tests/integ_tests/workflow_tests.rs +115 -11
  165. package/sdk-core/tests/main.rs +2 -2
  166. package/src/conversions.rs +57 -0
  167. package/src/lib.rs +1 -0
  168. package/src/runtime.rs +51 -35
  169. package/ts/index.ts +67 -3
  170. package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +0 -117
  171. package/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +0 -24
  172. package/sdk-core/sdk/src/payload_converter.rs +0 -11
  173. package/sdk-core/sdk-core-protos/protos/api_upstream/.buildkite/Dockerfile +0 -2
  174. package/sdk-core/sdk-core-protos/protos/api_upstream/.buildkite/docker-compose.yml +0 -15
  175. package/sdk-core/sdk-core-protos/protos/api_upstream/.buildkite/pipeline.yml +0 -10
  176. package/sdk-core/test-utils/src/wf_input_saver.rs +0 -50
  177. package/sdk-core/tests/wf_input_replay.rs +0 -32
@@ -24,7 +24,7 @@ async fn sends_upsert() {
24
24
  let wf_name = "sends_upsert_search_attrs";
25
25
  let wf_id = Uuid::new_v4();
26
26
  let mut starter = CoreWfStarter::new(wf_name);
27
- starter.no_remote_activities();
27
+ starter.worker_config.no_remote_activities(true);
28
28
  let mut worker = starter.worker().await;
29
29
  // TODO: this should be supported in server 1.20, remove this condition when CLI is upgraded.
30
30
  if env::var(INTEG_TEMPORAL_DEV_SERVER_USED_ENV_VAR).is_ok() {
@@ -16,11 +16,11 @@ mod stickyness;
16
16
  mod timers;
17
17
  mod upsert_search_attrs;
18
18
 
19
- use crate::integ_tests::activity_functions::echo;
19
+ use crate::integ_tests::{activity_functions::echo, metrics_tests};
20
20
  use assert_matches::assert_matches;
21
21
  use futures::{channel::mpsc::UnboundedReceiver, future, SinkExt, StreamExt};
22
22
  use std::{
23
- collections::HashMap,
23
+ collections::{HashMap, HashSet},
24
24
  sync::{
25
25
  atomic::{AtomicUsize, Ordering},
26
26
  Arc,
@@ -29,8 +29,11 @@ use std::{
29
29
  };
30
30
  use temporal_client::{WorkflowClientTrait, WorkflowOptions};
31
31
  use temporal_sdk::{interceptors::WorkerInterceptor, ActivityOptions, WfContext, WorkflowResult};
32
- use temporal_sdk_core::replay::HistoryForReplay;
33
- use temporal_sdk_core_api::{errors::PollWfError, Worker};
32
+ use temporal_sdk_core::{replay::HistoryForReplay, CoreRuntime};
33
+ use temporal_sdk_core_api::{
34
+ errors::{PollWfError, WorkflowErrorType},
35
+ Worker,
36
+ };
34
37
  use temporal_sdk_core_protos::{
35
38
  coresdk::{
36
39
  activity_result::ActivityExecutionResult,
@@ -41,7 +44,10 @@ use temporal_sdk_core_protos::{
41
44
  workflow_completion::WorkflowActivationCompletion,
42
45
  ActivityTaskCompletion, AsJsonPayloadExt, IntoCompletion,
43
46
  },
44
- temporal::api::{failure::v1::Failure, history::v1::history_event, query::v1::WorkflowQuery},
47
+ temporal::api::{
48
+ enums::v1::EventType, failure::v1::Failure, history::v1::history_event,
49
+ query::v1::WorkflowQuery,
50
+ },
45
51
  };
46
52
  use temporal_sdk_core_test_utils::{
47
53
  drain_pollers_and_shutdown, history_from_proto_binary, init_core_and_create_wf,
@@ -109,7 +115,8 @@ async fn parallel_workflows_same_queue() {
109
115
  }
110
116
 
111
117
  static RUN_CT: AtomicUsize = AtomicUsize::new(0);
112
- pub async fn cache_evictions_wf(command_sink: WfContext) -> WorkflowResult<()> {
118
+
119
+ pub(crate) async fn cache_evictions_wf(command_sink: WfContext) -> WorkflowResult<()> {
113
120
  RUN_CT.fetch_add(1, Ordering::SeqCst);
114
121
  command_sink.timer(Duration::from_secs(1)).await;
115
122
  Ok(().into())
@@ -119,7 +126,11 @@ pub async fn cache_evictions_wf(command_sink: WfContext) -> WorkflowResult<()> {
119
126
  async fn workflow_lru_cache_evictions() {
120
127
  let wf_type = "workflow_lru_cache_evictions";
121
128
  let mut starter = CoreWfStarter::new(wf_type);
122
- starter.no_remote_activities().max_cached_workflows(1);
129
+ starter
130
+ .worker_config
131
+ .max_concurrent_wft_polls(1_usize)
132
+ .no_remote_activities(true)
133
+ .max_cached_workflows(1_usize);
123
134
  let mut worker = starter.worker().await;
124
135
  worker.register_wf(wf_type.to_string(), cache_evictions_wf);
125
136
 
@@ -163,7 +174,7 @@ async fn shutdown_aborts_actively_blocked_poll() {
163
174
  // Begin the poll, and request shutdown from another thread after a small period of time.
164
175
  let tcore = core.clone();
165
176
  let handle = tokio::spawn(async move {
166
- std::thread::sleep(Duration::from_millis(100));
177
+ tokio::time::sleep(Duration::from_millis(100)).await;
167
178
  drain_pollers_and_shutdown(&tcore).await;
168
179
  });
169
180
  assert_matches!(
@@ -434,9 +445,10 @@ async fn wft_timeout_doesnt_create_unsolvable_autocomplete() {
434
445
  let signal_at_complete = "at-complete";
435
446
  let mut wf_starter = CoreWfStarter::new("wft_timeout_doesnt_create_unsolvable_autocomplete");
436
447
  wf_starter
448
+ .worker_config
437
449
  // Test needs eviction on and a short timeout
438
- .max_cached_workflows(0)
439
- .max_wft(1);
450
+ .max_cached_workflows(0_usize)
451
+ .max_outstanding_workflow_tasks(1_usize);
440
452
  wf_starter.worker_config.max_concurrent_wft_polls(1_usize);
441
453
  wf_starter.workflow_options.task_timeout = Some(Duration::from_secs(1));
442
454
  let core = wf_starter.get_worker().await;
@@ -552,7 +564,10 @@ async fn wft_timeout_doesnt_create_unsolvable_autocomplete() {
552
564
  async fn slow_completes_with_small_cache() {
553
565
  let wf_name = "slow_completes_with_small_cache";
554
566
  let mut starter = CoreWfStarter::new(wf_name);
555
- starter.max_wft(5).max_cached_workflows(5);
567
+ starter
568
+ .worker_config
569
+ .max_outstanding_workflow_tasks(5_usize)
570
+ .max_cached_workflows(5_usize);
556
571
  let mut worker = starter.worker().await;
557
572
  worker.register_wf(wf_name.to_owned(), |ctx: WfContext| async move {
558
573
  for _ in 0..3 {
@@ -730,3 +745,92 @@ async fn build_id_correct_in_wf_info() {
730
745
  assert_eq!(res.build_id_for_current_task, "2.0");
731
746
  core.complete_execution(&res.run_id).await;
732
747
  }
748
+
749
+ #[rstest::rstest]
750
+ #[tokio::test]
751
+ async fn nondeterminism_errors_fail_workflow_when_configured_to(
752
+ #[values(true, false)] whole_worker: bool,
753
+ ) {
754
+ let (telemopts, addr, _aborter) = metrics_tests::prom_metrics(false, false);
755
+ let rt = CoreRuntime::new_assume_tokio(telemopts).unwrap();
756
+ let wf_name = "nondeterminism_errors_fail_workflow_when_configured_to";
757
+ let mut starter = CoreWfStarter::new_with_runtime(wf_name, rt);
758
+ starter.worker_config.no_remote_activities(true);
759
+ let typeset = HashSet::from([WorkflowErrorType::Nondeterminism]);
760
+ if whole_worker {
761
+ starter.worker_config.workflow_failure_errors(typeset);
762
+ } else {
763
+ starter
764
+ .worker_config
765
+ .workflow_types_to_failure_errors(HashMap::from([(wf_name.to_owned(), typeset)]));
766
+ }
767
+ let wf_id = starter.get_task_queue().to_owned();
768
+ let mut worker = starter.worker().await;
769
+ worker.fetch_results = false;
770
+
771
+ worker.register_wf(wf_name.to_owned(), move |ctx: WfContext| async move {
772
+ ctx.timer(Duration::from_secs(1000)).await;
773
+ Ok(().into())
774
+ });
775
+ let client = starter.get_client().await;
776
+ let core_worker = worker.core_worker.clone();
777
+ starter.start_with_worker(wf_name, &mut worker).await;
778
+
779
+ let stopper = async {
780
+ // Wait for the timer to show up in history and then stop the worker
781
+ loop {
782
+ let hist = client
783
+ .get_workflow_execution_history(wf_id.clone(), None, vec![])
784
+ .await
785
+ .unwrap()
786
+ .history
787
+ .unwrap();
788
+ let has_timer_event = hist
789
+ .events
790
+ .iter()
791
+ .any(|e| matches!(e.event_type(), EventType::TimerStarted));
792
+ if has_timer_event {
793
+ break;
794
+ }
795
+ tokio::time::sleep(Duration::from_millis(100)).await;
796
+ }
797
+ core_worker.initiate_shutdown();
798
+ };
799
+ let runner = async {
800
+ worker.run_until_done().await.unwrap();
801
+ };
802
+ join!(stopper, runner);
803
+
804
+ // Restart the worker with a new, incompatible wf definition which will cause nondeterminism
805
+ let mut starter = starter.clone_no_worker();
806
+ let mut worker = starter.worker().await;
807
+ worker.register_wf(wf_name.to_owned(), move |ctx: WfContext| async move {
808
+ ctx.activity(ActivityOptions {
809
+ activity_type: "echo_activity".to_string(),
810
+ start_to_close_timeout: Some(Duration::from_secs(5)),
811
+ ..Default::default()
812
+ })
813
+ .await;
814
+ Ok(().into())
815
+ });
816
+ // We need to generate a task so that we'll encounter the error (first avoid WFT timeout)
817
+ client
818
+ .reset_sticky_task_queue(wf_id.clone(), "".to_string())
819
+ .await
820
+ .unwrap();
821
+ client
822
+ .signal_workflow_execution(wf_id.clone(), "".to_string(), "hi".to_string(), None, None)
823
+ .await
824
+ .unwrap();
825
+ worker.expect_workflow_completion(&wf_id, None);
826
+ // If we don't fail the workflow on nondeterminism, we'll get stuck here retrying the WFT
827
+ worker.run_until_done().await.unwrap();
828
+
829
+ let body = metrics_tests::get_text(format!("http://{addr}/metrics")).await;
830
+ let match_this = format!(
831
+ "temporal_workflow_failed{{namespace=\"default\",\
832
+ service_name=\"temporal-core-sdk\",\
833
+ task_queue=\"{wf_id}\",workflow_type=\"{wf_name}\"}} 1"
834
+ );
835
+ assert!(body.contains(&match_this));
836
+ }
@@ -38,7 +38,7 @@ mod integ_tests {
38
38
  let opts = get_integ_server_options();
39
39
  let runtime = CoreRuntime::new_assume_tokio(get_integ_telem_options()).unwrap();
40
40
  let mut retrying_client = opts
41
- .connect_no_namespace(runtime.telemetry().get_temporal_metric_meter(), None)
41
+ .connect_no_namespace(runtime.telemetry().get_temporal_metric_meter())
42
42
  .await
43
43
  .unwrap();
44
44
 
@@ -85,7 +85,7 @@ mod integ_tests {
85
85
  .build()
86
86
  .unwrap();
87
87
  let con = sgo
88
- .connect("spencer.temporal-dev".to_string(), None, None)
88
+ .connect("spencer.temporal-dev".to_string(), None)
89
89
  .await
90
90
  .unwrap();
91
91
  dbg!(con
@@ -6,6 +6,7 @@ use neon::{
6
6
  types::{JsBoolean, JsNumber, JsString},
7
7
  };
8
8
  use std::{collections::HashMap, net::SocketAddr, sync::Arc, time::Duration};
9
+ use temporal_client::HttpConnectProxyOptions;
9
10
  use temporal_sdk_core::{
10
11
  api::telemetry::{Logger, MetricTemporality, TelemetryOptions, TelemetryOptionsBuilder},
11
12
  api::{
@@ -121,6 +122,26 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
121
122
  }
122
123
  };
123
124
 
125
+ let proxy_cfg = match js_optional_getter!(cx, self, "proxy", JsObject) {
126
+ None => None,
127
+ Some(proxy) => {
128
+ let target_addr = js_value_getter!(cx, &proxy, "targetHost", JsString);
129
+
130
+ let basic_auth = match js_optional_getter!(cx, &proxy, "basicAuth", JsObject) {
131
+ None => None,
132
+ Some(proxy_obj) => Some((
133
+ js_value_getter!(cx, &proxy_obj, "username", JsString),
134
+ js_value_getter!(cx, &proxy_obj, "password", JsString),
135
+ )),
136
+ };
137
+
138
+ Some(HttpConnectProxyOptions {
139
+ target_addr,
140
+ basic_auth,
141
+ })
142
+ }
143
+ };
144
+
124
145
  let retry_config = match js_optional_getter!(cx, self, "retry", JsObject) {
125
146
  None => RetryConfig::default(),
126
147
  Some(ref retry_config) => RetryConfig {
@@ -158,6 +179,20 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
158
179
  if let Some(tls_cfg) = tls_cfg {
159
180
  client_options.tls_cfg(tls_cfg);
160
181
  }
182
+ client_options.http_connect_proxy(proxy_cfg);
183
+ let headers = match js_optional_getter!(cx, self, "metadata", JsObject) {
184
+ None => None,
185
+ Some(h) => Some(h.as_hash_map_of_string_to_string(cx).map_err(|reason| {
186
+ cx.throw_type_error::<_, HashMap<String, String>>(format!(
187
+ "Invalid metadata: {}",
188
+ reason
189
+ ))
190
+ .unwrap_err()
191
+ })?),
192
+ };
193
+ client_options.headers(headers);
194
+ let api_key = js_optional_value_getter!(cx, self, "apiKey", JsString);
195
+ client_options.api_key(api_key);
161
196
 
162
197
  Ok(client_options
163
198
  .client_name("temporal-typescript".to_string())
@@ -211,6 +246,22 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
211
246
  }
212
247
  };
213
248
 
249
+ if let Some(counters_total_suffix) =
250
+ js_optional_value_getter!(cx, prom, "countersTotalSuffix", JsBoolean)
251
+ {
252
+ options.counters_total_suffix(counters_total_suffix);
253
+ }
254
+ if let Some(unit_suffix) =
255
+ js_optional_value_getter!(cx, prom, "unitSuffix", JsBoolean)
256
+ {
257
+ options.unit_suffix(unit_suffix);
258
+ }
259
+ if let Some(use_seconds_for_durations) =
260
+ js_optional_value_getter!(cx, prom, "useSecondsForDurations", JsBoolean)
261
+ {
262
+ options.use_seconds_for_durations(use_seconds_for_durations);
263
+ }
264
+
214
265
  let options = options.build().map_err(|e| {
215
266
  cx.throw_type_error::<_, TelemetryOptions>(format!(
216
267
  "Failed to build prometheus exporter options: {:?}",
@@ -240,6 +291,12 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
240
291
  }
241
292
  };
242
293
 
294
+ if let Some(use_seconds_for_durations) =
295
+ js_optional_value_getter!(cx, otel, "useSecondsForDurations", JsBoolean)
296
+ {
297
+ options.use_seconds_for_durations(use_seconds_for_durations);
298
+ }
299
+
243
300
  if let Some(ref headers) = js_optional_getter!(cx, otel, "headers", JsObject) {
244
301
  options.headers(headers.as_hash_map_of_string_to_string(cx)?);
245
302
  };
package/src/lib.rs CHANGED
@@ -16,6 +16,7 @@ fn main(mut cx: ModuleContext) -> NeonResult<()> {
16
16
  cx.export_function("newRuntime", runtime_new)?;
17
17
  cx.export_function("newClient", client_new)?;
18
18
  cx.export_function("clientUpdateHeaders", client_update_headers)?;
19
+ cx.export_function("clientUpdateApiKey", client_update_api_key)?;
19
20
  cx.export_function("newWorker", worker_new)?;
20
21
  cx.export_function("newReplayWorker", replay_worker_new)?;
21
22
  cx.export_function("pushHistory", push_history)?;
package/src/runtime.rs CHANGED
@@ -1,28 +1,24 @@
1
1
  use crate::{conversions::*, errors::*, helpers::*, worker::*};
2
- use neon::context::Context;
3
- use neon::prelude::*;
4
- use parking_lot::RwLock;
5
- use std::cell::Cell;
2
+ use neon::{context::Context, prelude::*};
6
3
  use std::{
7
- cell::RefCell,
4
+ cell::{Cell, RefCell},
8
5
  collections::HashMap,
9
6
  ops::Deref,
7
+ process::Stdio,
10
8
  sync::Arc,
11
9
  time::{Duration, SystemTime, UNIX_EPOCH},
12
10
  };
13
11
  use temporal_client::{ClientInitError, ConfiguredClient, TemporalServiceClientWithMetrics};
14
- use temporal_sdk_core::api::telemetry::CoreTelemetry;
15
- use temporal_sdk_core::CoreRuntime;
16
12
  use temporal_sdk_core::{
13
+ api::telemetry::CoreTelemetry,
17
14
  ephemeral_server::EphemeralServer as CoreEphemeralServer,
18
15
  init_replay_worker, init_worker,
19
16
  replay::{HistoryForReplay, ReplayWorkerInput},
20
- ClientOptions, RetryClient, WorkerConfig,
17
+ ClientOptions, CoreRuntime, RetryClient, WorkerConfig,
21
18
  };
22
- use tokio::sync::oneshot;
23
19
  use tokio::sync::{
24
20
  mpsc::{channel, unbounded_channel, Sender, UnboundedReceiver, UnboundedSender},
25
- Mutex,
21
+ oneshot, Mutex,
26
22
  };
27
23
  use tokio_stream::wrappers::ReceiverStream;
28
24
 
@@ -64,7 +60,6 @@ pub enum RuntimeRequest {
64
60
  CreateClient {
65
61
  runtime: Arc<RuntimeHandle>,
66
62
  options: ClientOptions,
67
- headers: Option<HashMap<String, String>>,
68
63
  /// Used to send the result back into JS
69
64
  callback: Root<JsFunction>,
70
65
  },
@@ -111,6 +106,11 @@ pub enum RuntimeRequest {
111
106
  pushme: HistoryForReplay,
112
107
  callback: Root<JsFunction>,
113
108
  },
109
+ UpdateClientApiKey {
110
+ client: Arc<RawClient>,
111
+ key: String,
112
+ callback: Root<JsFunction>,
113
+ },
114
114
  }
115
115
 
116
116
  /// Builds a tokio runtime and starts polling on [RuntimeRequest]s via an internal channel.
@@ -166,13 +166,12 @@ pub fn start_bridge_loop(
166
166
  RuntimeRequest::CreateClient {
167
167
  runtime,
168
168
  options,
169
- headers,
170
169
  callback,
171
170
  } => {
172
171
  let mm = core_runtime.telemetry().get_metric_meter();
173
172
  core_runtime.tokio_handle().spawn(async move {
174
173
  match options
175
- .connect_no_namespace(mm, headers.map(|h| Arc::new(RwLock::new(h))))
174
+ .connect_no_namespace(mm)
176
175
  .await
177
176
  {
178
177
  Err(err) => {
@@ -211,6 +210,10 @@ pub fn start_bridge_loop(
211
210
  client.get_client().set_headers(headers);
212
211
  send_result(channel.clone(), callback, |cx| Ok(cx.undefined()));
213
212
  }
213
+ RuntimeRequest::UpdateClientApiKey { client, key, callback } => {
214
+ client.get_client().set_api_key(Some(key));
215
+ send_result(channel.clone(), callback, |cx| Ok(cx.undefined()));
216
+ }
214
217
  RuntimeRequest::PollLogs { callback } => {
215
218
  let logs = core_runtime.telemetry().fetch_buffered_logs();
216
219
  send_result(channel.clone(), callback, |cx| {
@@ -297,11 +300,15 @@ pub fn start_bridge_loop(
297
300
  callback,
298
301
  } => {
299
302
  core_runtime.tokio_handle().spawn(async move {
303
+ let stdout = Stdio::from(std::io::stdout());
304
+ let stderr = Stdio::from(std::io::stderr());
300
305
  let result = match config {
301
306
  EphemeralServerConfig::TestServer(config) => {
302
- config.start_server().await
307
+ config.start_server_with_output(stdout, stderr).await
308
+ }
309
+ EphemeralServerConfig::DevServer(config) => {
310
+ config.start_server_with_output(stdout, stderr).await
303
311
  }
304
- EphemeralServerConfig::DevServer(config) => config.start_server().await,
305
312
  };
306
313
  match result {
307
314
  Err(err) => {
@@ -337,8 +344,7 @@ pub fn start_bridge_loop(
337
344
  format!("Failed to start test server: {}", err),
338
345
  )
339
346
  },
340
- )
341
- .await
347
+ ).await
342
348
  });
343
349
  }
344
350
  RuntimeRequest::PushReplayHistory {
@@ -350,8 +356,8 @@ pub fn start_bridge_loop(
350
356
  let sendfut = async move {
351
357
  tx.send(pushme).await.map_err(|e| {
352
358
  format!(
353
- "Receive side of history replay channel is gone. This is an sdk bug. {:?}",
354
- e
359
+ "Receive side of history replay channel is gone. This is an sdk bug. {:?}",
360
+ e
355
361
  )
356
362
  })
357
363
  };
@@ -361,8 +367,7 @@ pub fn start_bridge_loop(
361
367
  UNEXPECTED_ERROR,
362
368
  format!("Error pushing replay history {}", err),
363
369
  )
364
- })
365
- .await
370
+ }).await
366
371
  });
367
372
  }
368
373
  }
@@ -453,24 +458,10 @@ pub fn client_new(mut cx: FunctionContext) -> JsResult<JsUndefined> {
453
458
  let callback = cx.argument::<JsFunction>(2)?;
454
459
 
455
460
  let client_options = opts.as_client_options(&mut cx)?;
456
- let headers = match js_optional_getter!(&mut cx, &opts, "metadata", JsObject) {
457
- None => None,
458
- Some(h) => Some(
459
- h.as_hash_map_of_string_to_string(&mut cx)
460
- .map_err(|reason| {
461
- cx.throw_type_error::<_, HashMap<String, String>>(format!(
462
- "Invalid metadata: {}",
463
- reason
464
- ))
465
- .unwrap_err()
466
- })?,
467
- ),
468
- };
469
461
 
470
462
  let request = RuntimeRequest::CreateClient {
471
463
  runtime: (**runtime).clone(),
472
464
  options: client_options,
473
- headers,
474
465
  callback: callback.root(&mut cx),
475
466
  };
476
467
  if let Err(err) = runtime.sender.send(request) {
@@ -517,6 +508,31 @@ pub fn client_update_headers(mut cx: FunctionContext) -> JsResult<JsUndefined> {
517
508
  Ok(cx.undefined())
518
509
  }
519
510
 
511
+ /// Update a Client's API key
512
+ pub fn client_update_api_key(mut cx: FunctionContext) -> JsResult<JsUndefined> {
513
+ let client = cx.argument::<BoxedClient>(0)?;
514
+ let key = cx.argument::<JsString>(1)?.value(&mut cx);
515
+ let callback = cx.argument::<JsFunction>(2)?;
516
+
517
+ match client.borrow().as_ref() {
518
+ None => {
519
+ callback_with_unexpected_error(&mut cx, callback, "Tried to use closed Client")?;
520
+ }
521
+ Some(client) => {
522
+ let request = RuntimeRequest::UpdateClientApiKey {
523
+ client: client.core_client.clone(),
524
+ key,
525
+ callback: callback.root(&mut cx),
526
+ };
527
+ if let Err(err) = client.runtime.sender.send(request) {
528
+ callback_with_unexpected_error(&mut cx, callback, err)?;
529
+ };
530
+ }
531
+ }
532
+
533
+ Ok(cx.undefined())
534
+ }
535
+
520
536
  pub(crate) struct HistoryForReplayTunnel {
521
537
  pub(crate) runtime: Arc<RuntimeHandle>,
522
538
  sender: Cell<Option<Sender<HistoryForReplay>>>,
package/ts/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { LogLevel, Duration } from '@temporalio/common';
2
- import type { TLSConfig } from '@temporalio/common/lib/internal-non-workflow';
2
+ import type { TLSConfig, ProxyConfig, HttpConnectProxyConfig } from '@temporalio/common/lib/internal-non-workflow';
3
3
 
4
- export { TLSConfig };
4
+ export type { TLSConfig, ProxyConfig, HttpConnectProxyConfig };
5
5
 
6
6
  /** @deprecated Import from @temporalio/common instead */
7
7
  export { LogLevel };
@@ -55,6 +55,13 @@ export interface ClientOptions {
55
55
  */
56
56
  tls?: TLSConfig;
57
57
 
58
+ /**
59
+ * Proxying configuration.
60
+ *
61
+ * @experimental
62
+ */
63
+ proxy?: ProxyConfig;
64
+
58
65
  /**
59
66
  * Optional retry options for server requests.
60
67
  */
@@ -66,6 +73,14 @@ export interface ClientOptions {
66
73
  * Set statically at connection time, can be replaced later using {@link clientUpdateHeaders}.
67
74
  */
68
75
  metadata?: Record<string, string>;
76
+
77
+ /**
78
+ * API key for Temporal. This becomes the "Authorization" HTTP header with "Bearer " prepended.
79
+ * This is only set if RPC metadata doesn't already have an "authorization" key.
80
+ *
81
+ * Set statically at connection time, can be replaced later using {@link clientUpdateApiKey}.
82
+ */
83
+ apiKey?: string;
69
84
  }
70
85
 
71
86
  /**
@@ -122,11 +137,20 @@ export interface OtelCollectorExporter {
122
137
  * @defaults 1 second
123
138
  */
124
139
  metricsExportInterval?: Duration;
140
+ /**
141
+ * If set to true, the exporter will use seconds for durations instead of milliseconds.
142
+ */
143
+ useSecondsForDurations?: boolean;
125
144
  };
126
145
  }
127
146
 
128
147
  /** @experimental */
129
- export type CompiledOtelMetricsExporter = Shadow<OtelCollectorExporter, { otel: { metricsExportInterval: number } }>;
148
+ export type CompiledOtelMetricsExporter = Shadow<
149
+ OtelCollectorExporter,
150
+ {
151
+ otel: { metricsExportInterval: number };
152
+ }
153
+ >;
130
154
 
131
155
  /**
132
156
  * Prometheus metrics exporter options
@@ -142,6 +166,19 @@ export interface PrometheusMetricsExporter {
142
166
  * Metrics will be available for scraping under the standard `/metrics` route.
143
167
  */
144
168
  bindAddress: string;
169
+ /**
170
+ * If set to true, all counter names will include a "_total" suffix.
171
+ */
172
+ countersTotalSuffix?: boolean;
173
+ /**
174
+ * If set to true, all histograms will include the unit in their name as a suffix.
175
+ * EX: "_milliseconds"
176
+ */
177
+ unitSuffix?: boolean;
178
+ /**
179
+ * If set to true, the exporter will use seconds for durations instead of milliseconds.
180
+ */
181
+ useSecondsForDurations?: boolean;
145
182
  };
146
183
  }
147
184
 
@@ -430,18 +467,23 @@ export type EphemeralServerConfig = TimeSkippingServerConfig | DevServerConfig;
430
467
  export interface Worker {
431
468
  type: 'Worker';
432
469
  }
470
+
433
471
  export interface Runtime {
434
472
  type: 'Runtime';
435
473
  }
474
+
436
475
  export interface Client {
437
476
  type: 'Client';
438
477
  }
478
+
439
479
  export interface EphemeralServer {
440
480
  type: 'EphemeralServer';
441
481
  }
482
+
442
483
  export interface HistoryPusher {
443
484
  type: 'HistoryPusher';
444
485
  }
486
+
445
487
  export interface ReplayWorker {
446
488
  type: 'ReplayWorker';
447
489
  worker: Worker;
@@ -457,47 +499,69 @@ export declare type VoidCallback = (err: Error, result: void) => void;
457
499
  export declare type LogsCallback = (err: Error, result: LogEntry[]) => void;
458
500
 
459
501
  export declare function newRuntime(telemOptions: CompiledTelemetryOptions): Runtime;
502
+
460
503
  export declare function newClient(runtime: Runtime, clientOptions: ClientOptions, callback: ClientCallback): void;
504
+
461
505
  export declare function newWorker(client: Client, workerOptions: WorkerOptions, callback: WorkerCallback): void;
506
+
462
507
  export declare function newReplayWorker(
463
508
  runtime: Runtime,
464
509
  workerOptions: WorkerOptions,
465
510
  callback: ReplayWorkerCallback
466
511
  ): void;
512
+
467
513
  export declare function pushHistory(
468
514
  pusher: HistoryPusher,
469
515
  workflowId: string,
470
516
  history: ArrayBuffer,
471
517
  callback: VoidCallback
472
518
  ): void;
519
+
473
520
  export declare function closeHistoryStream(pusher: HistoryPusher): void;
521
+
474
522
  export declare function workerInitiateShutdown(worker: Worker, callback: VoidCallback): void;
523
+
475
524
  export declare function workerFinalizeShutdown(worker: Worker): void;
525
+
476
526
  export declare function clientUpdateHeaders(
477
527
  client: Client,
478
528
  headers: Record<string, string>,
479
529
  callback: VoidCallback
480
530
  ): void;
531
+
532
+ export declare function clientUpdateApiKey(client: Client, apiKey: string, callback: VoidCallback): void;
533
+
481
534
  export declare function clientClose(client: Client): void;
535
+
482
536
  export declare function runtimeShutdown(runtime: Runtime, callback: VoidCallback): void;
537
+
483
538
  export declare function pollLogs(runtime: Runtime, callback: LogsCallback): void;
539
+
484
540
  export declare function workerPollWorkflowActivation(worker: Worker, callback: PollCallback): void;
541
+
485
542
  export declare function workerCompleteWorkflowActivation(
486
543
  worker: Worker,
487
544
  result: ArrayBuffer,
488
545
  callback: VoidCallback
489
546
  ): void;
547
+
490
548
  export declare function workerPollActivityTask(worker: Worker, callback: PollCallback): void;
549
+
491
550
  export declare function workerCompleteActivityTask(worker: Worker, result: ArrayBuffer, callback: VoidCallback): void;
551
+
492
552
  export declare function workerRecordActivityHeartbeat(worker: Worker, heartbeat: ArrayBuffer): void;
553
+
493
554
  export declare function getTimeOfDay(): [number, number];
555
+
494
556
  export declare function startEphemeralServer(
495
557
  runtime: Runtime,
496
558
  config: EphemeralServerConfig,
497
559
  sdkVersion: string,
498
560
  callback: Callback<EphemeralServer>
499
561
  ): void;
562
+
500
563
  export declare function shutdownEphemeralServer(server: EphemeralServer, callback: Callback<EphemeralServer>): void;
564
+
501
565
  export declare function getEphemeralServerTarget(server: EphemeralServer): string;
502
566
 
503
567
  export { ShutdownError, TransportError, UnexpectedError } from './errors';