@temporalio/core-bridge 1.7.4 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/Cargo.lock +245 -247
  2. package/Cargo.toml +1 -1
  3. package/lib/errors.d.ts +9 -0
  4. package/lib/errors.js +13 -0
  5. package/lib/errors.js.map +1 -1
  6. package/lib/index.d.ts +19 -3
  7. package/lib/index.js.map +1 -1
  8. package/package.json +3 -3
  9. package/releases/aarch64-apple-darwin/index.node +0 -0
  10. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  11. package/releases/x86_64-apple-darwin/index.node +0 -0
  12. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  13. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  14. package/sdk-core/.github/workflows/heavy.yml +1 -1
  15. package/sdk-core/.github/workflows/semgrep.yml +25 -0
  16. package/sdk-core/README.md +2 -0
  17. package/sdk-core/cargo-tokio-console.sh +5 -0
  18. package/sdk-core/client/src/lib.rs +6 -41
  19. package/sdk-core/client/src/raw.rs +9 -0
  20. package/sdk-core/client/src/retry.rs +0 -16
  21. package/sdk-core/core/Cargo.toml +9 -5
  22. package/sdk-core/core/src/abstractions.rs +7 -75
  23. package/sdk-core/core/src/core_tests/activity_tasks.rs +16 -8
  24. package/sdk-core/core/src/core_tests/local_activities.rs +97 -5
  25. package/sdk-core/core/src/core_tests/mod.rs +1 -1
  26. package/sdk-core/core/src/core_tests/workers.rs +16 -16
  27. package/sdk-core/core/src/core_tests/workflow_tasks.rs +247 -28
  28. package/sdk-core/core/src/lib.rs +2 -3
  29. package/sdk-core/core/src/pollers/mod.rs +30 -3
  30. package/sdk-core/core/src/pollers/poll_buffer.rs +166 -77
  31. package/sdk-core/core/src/protosext/mod.rs +4 -8
  32. package/sdk-core/core/src/replay/mod.rs +1 -1
  33. package/sdk-core/core/src/telemetry/metrics.rs +9 -0
  34. package/sdk-core/core/src/telemetry/mod.rs +3 -0
  35. package/sdk-core/core/src/test_help/mod.rs +9 -16
  36. package/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +6 -31
  37. package/sdk-core/core/src/worker/activities/local_activities.rs +214 -110
  38. package/sdk-core/core/src/worker/activities.rs +72 -47
  39. package/sdk-core/core/src/worker/client/mocks.rs +1 -1
  40. package/sdk-core/core/src/worker/client.rs +45 -32
  41. package/sdk-core/core/src/worker/mod.rs +170 -122
  42. package/sdk-core/core/src/worker/workflow/driven_workflow.rs +0 -4
  43. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +9 -2
  44. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +9 -2
  45. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +6 -3
  46. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +74 -22
  47. package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +3 -2
  48. package/sdk-core/core/src/worker/workflow/managed_run.rs +16 -3
  49. package/sdk-core/core/src/worker/workflow/mod.rs +13 -22
  50. package/sdk-core/core/src/worker/workflow/run_cache.rs +5 -0
  51. package/sdk-core/core/src/worker/workflow/wft_extraction.rs +4 -7
  52. package/sdk-core/core/src/worker/workflow/wft_poller.rs +38 -8
  53. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +1 -0
  54. package/sdk-core/core-api/src/worker.rs +43 -2
  55. package/sdk-core/protos/api_upstream/Makefile +1 -1
  56. package/sdk-core/protos/api_upstream/buf.yaml +1 -6
  57. package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +12 -0
  58. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +11 -0
  59. package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +13 -2
  60. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +1 -0
  61. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +2 -0
  62. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +9 -0
  63. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +19 -0
  64. package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +5 -0
  65. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +36 -4
  66. package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +24 -7
  67. package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +4 -0
  68. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +76 -44
  69. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +23 -1
  70. package/sdk-core/protos/google/rpc/status.proto +52 -0
  71. package/sdk-core/protos/local/temporal/sdk/core/common/common.proto +16 -0
  72. package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +4 -0
  73. package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +6 -0
  74. package/sdk-core/sdk/src/lib.rs +31 -10
  75. package/sdk-core/sdk/src/workflow_future.rs +7 -5
  76. package/sdk-core/sdk-core-protos/src/history_builder.rs +2 -0
  77. package/sdk-core/sdk-core-protos/src/history_info.rs +1 -0
  78. package/sdk-core/sdk-core-protos/src/lib.rs +82 -73
  79. package/sdk-core/test-utils/Cargo.toml +1 -1
  80. package/sdk-core/test-utils/src/lib.rs +50 -37
  81. package/sdk-core/tests/integ_tests/metrics_tests.rs +143 -10
  82. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +26 -15
  83. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +1 -1
  84. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +2 -2
  85. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +5 -1
  86. package/sdk-core/tests/integ_tests/workflow_tests.rs +1 -0
  87. package/src/conversions.rs +9 -2
  88. package/src/runtime.rs +5 -7
  89. package/ts/errors.ts +15 -0
  90. package/ts/index.ts +22 -4
@@ -1,3 +1,4 @@
1
+ use assert_matches::assert_matches;
1
2
  use std::{sync::Arc, time::Duration};
2
3
  use temporal_client::{WorkflowClientTrait, WorkflowOptions, WorkflowService};
3
4
  use temporal_sdk_core::{init_worker, CoreRuntime};
@@ -5,14 +6,24 @@ use temporal_sdk_core_api::{telemetry::MetricsExporter, worker::WorkerConfigBuil
5
6
  use temporal_sdk_core_protos::{
6
7
  coresdk::{
7
8
  activity_result::ActivityExecutionResult,
8
- workflow_commands::{ScheduleActivity, ScheduleLocalActivity},
9
+ workflow_activation::{workflow_activation_job, WorkflowActivationJob},
10
+ workflow_commands::{
11
+ workflow_command, CancelWorkflowExecution, CompleteWorkflowExecution,
12
+ ContinueAsNewWorkflowExecution, FailWorkflowExecution, QueryResult, QuerySuccess,
13
+ ScheduleActivity, ScheduleLocalActivity,
14
+ },
9
15
  workflow_completion::WorkflowActivationCompletion,
10
16
  ActivityTaskCompletion,
11
17
  },
12
- temporal::api::{enums::v1::WorkflowIdReusePolicy, workflowservice::v1::ListNamespacesRequest},
18
+ temporal::api::{
19
+ enums::v1::WorkflowIdReusePolicy, failure::v1::Failure, query::v1::WorkflowQuery,
20
+ workflowservice::v1::ListNamespacesRequest,
21
+ },
22
+ };
23
+ use temporal_sdk_core_test_utils::{
24
+ get_integ_server_options, get_integ_telem_options, CoreWfStarter, NAMESPACE,
13
25
  };
14
- use temporal_sdk_core_test_utils::{get_integ_server_options, get_integ_telem_options, NAMESPACE};
15
- use tokio::sync::Barrier;
26
+ use tokio::{join, sync::Barrier};
16
27
 
17
28
  static ANY_PORT: &str = "127.0.0.1:0";
18
29
 
@@ -59,10 +70,12 @@ async fn one_slot_worker_reports_available_slot() {
59
70
  .namespace(NAMESPACE)
60
71
  .task_queue(tq)
61
72
  .worker_build_id("test_build_id")
62
- .max_cached_workflows(1_usize)
73
+ .max_cached_workflows(2_usize)
63
74
  .max_outstanding_activities(1_usize)
64
75
  .max_outstanding_local_activities(1_usize)
65
- .max_outstanding_workflow_tasks(1_usize)
76
+ // Need to use two for WFTs because there are a minimum of 2 pollers b/c of sticky polling
77
+ .max_outstanding_workflow_tasks(2_usize)
78
+ .max_concurrent_wft_polls(1_usize)
66
79
  .build()
67
80
  .unwrap();
68
81
 
@@ -146,7 +159,7 @@ async fn one_slot_worker_reports_available_slot() {
146
159
  assert!(body.contains(&format!(
147
160
  "temporal_worker_task_slots_available{{namespace=\"{NAMESPACE}\",\
148
161
  service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
149
- worker_type=\"WorkflowWorker\"}} 1"
162
+ worker_type=\"WorkflowWorker\"}} 2"
150
163
  )));
151
164
 
152
165
  // Start a workflow so that a task will get delivered
@@ -174,7 +187,7 @@ async fn one_slot_worker_reports_available_slot() {
174
187
  assert!(body.contains(&format!(
175
188
  "temporal_worker_task_slots_available{{namespace=\"{NAMESPACE}\",\
176
189
  service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
177
- worker_type=\"WorkflowWorker\"}} 0"
190
+ worker_type=\"WorkflowWorker\"}} 1"
178
191
  )));
179
192
  assert!(body.contains(&format!(
180
193
  "temporal_worker_task_slots_available{{namespace=\"{NAMESPACE}\",\
@@ -197,7 +210,7 @@ async fn one_slot_worker_reports_available_slot() {
197
210
  assert!(body.contains(&format!(
198
211
  "temporal_worker_task_slots_available{{namespace=\"{NAMESPACE}\",\
199
212
  service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
200
- worker_type=\"WorkflowWorker\"}} 1"
213
+ worker_type=\"WorkflowWorker\"}} 2"
201
214
  )));
202
215
  assert!(body.contains(&format!(
203
216
  "temporal_worker_task_slots_available{{namespace=\"{NAMESPACE}\",\
@@ -235,5 +248,125 @@ async fn one_slot_worker_reports_available_slot() {
235
248
  worker_type=\"LocalActivityWorker\"}} 1"
236
249
  )));
237
250
  };
238
- tokio::join!(wf_polling, act_polling, testing);
251
+ join!(wf_polling, act_polling, testing);
252
+ }
253
+
254
+ #[rstest::rstest]
255
+ #[tokio::test]
256
+ async fn query_of_closed_workflow_doesnt_tick_terminal_metric(
257
+ #[values(
258
+ CompleteWorkflowExecution { result: None }.into(),
259
+ FailWorkflowExecution {
260
+ failure: Some(Failure::application_failure("I'm ded".to_string(), false)),
261
+ }.into(),
262
+ ContinueAsNewWorkflowExecution::default().into(),
263
+ CancelWorkflowExecution { }.into()
264
+ )]
265
+ completion: workflow_command::Variant,
266
+ ) {
267
+ let mut telemopts = get_integ_telem_options();
268
+ telemopts.metrics = Some(MetricsExporter::Prometheus(ANY_PORT.parse().unwrap()));
269
+ let rt = CoreRuntime::new_assume_tokio(telemopts).unwrap();
270
+ let addr = rt.telemetry().prom_port().unwrap();
271
+ let mut starter =
272
+ CoreWfStarter::new_with_runtime("query_of_closed_workflow_doesnt_tick_terminal_metric", rt);
273
+ // Disable cache to ensure replay happens completely
274
+ starter.max_cached_workflows(0);
275
+ let worker = starter.get_worker().await;
276
+ let run_id = starter.start_wf().await;
277
+ let task = worker.poll_workflow_activation().await.unwrap();
278
+ // Immediately complete the workflow
279
+ worker
280
+ .complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
281
+ task.run_id,
282
+ completion.clone(),
283
+ ))
284
+ .await
285
+ .unwrap();
286
+
287
+ let metric_name = match &completion {
288
+ workflow_command::Variant::CompleteWorkflowExecution(_) => "temporal_workflow_completed",
289
+ workflow_command::Variant::FailWorkflowExecution(_) => "temporal_workflow_failed",
290
+ workflow_command::Variant::ContinueAsNewWorkflowExecution(_) => {
291
+ "temporal_workflow_continue_as_new"
292
+ }
293
+ workflow_command::Variant::CancelWorkflowExecution(_) => "temporal_workflow_canceled",
294
+ _ => unreachable!(),
295
+ };
296
+
297
+ // Verify there is one tick for the completion metric
298
+ let body = get_text(format!("http://{addr}/metrics")).await;
299
+ let matching_line = body
300
+ .lines()
301
+ .find(|l| l.starts_with(metric_name))
302
+ .expect("Must find matching metric");
303
+ assert!(matching_line.ends_with('1'));
304
+
305
+ // Handle cache eviction
306
+ let task = worker.poll_workflow_activation().await.unwrap();
307
+ worker
308
+ .complete_workflow_activation(WorkflowActivationCompletion::empty(task.run_id))
309
+ .await
310
+ .unwrap();
311
+
312
+ // Query the now-closed workflow
313
+ let client = starter.get_client().await;
314
+ let queryer = async {
315
+ client
316
+ .query_workflow_execution(
317
+ starter.get_wf_id().to_string(),
318
+ run_id,
319
+ WorkflowQuery {
320
+ query_type: "fake_query".to_string(),
321
+ query_args: None,
322
+ header: None,
323
+ },
324
+ )
325
+ .await
326
+ .unwrap();
327
+ };
328
+ let query_reply = async {
329
+ // Need to re-complete b/c replay
330
+ let task = worker.poll_workflow_activation().await.unwrap();
331
+ worker
332
+ .complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
333
+ task.run_id,
334
+ completion,
335
+ ))
336
+ .await
337
+ .unwrap();
338
+
339
+ let task = worker.poll_workflow_activation().await.unwrap();
340
+ let query = assert_matches!(
341
+ task.jobs.as_slice(),
342
+ [WorkflowActivationJob {
343
+ variant: Some(workflow_activation_job::Variant::QueryWorkflow(q)),
344
+ }] => q
345
+ );
346
+ worker
347
+ .complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
348
+ task.run_id,
349
+ QueryResult {
350
+ query_id: query.query_id.clone(),
351
+ variant: Some(
352
+ QuerySuccess {
353
+ response: Some("hi".into()),
354
+ }
355
+ .into(),
356
+ ),
357
+ }
358
+ .into(),
359
+ ))
360
+ .await
361
+ .unwrap()
362
+ };
363
+ join!(query_reply, queryer);
364
+
365
+ // Verify there is still only one tick
366
+ let body = get_text(format!("http://{addr}/metrics")).await;
367
+ let matching_line = body
368
+ .lines()
369
+ .find(|l| l.starts_with(metric_name))
370
+ .expect("Must find matching metric");
371
+ assert!(matching_line.ends_with('1'));
239
372
  }
@@ -17,7 +17,9 @@ use temporal_sdk_core_protos::{
17
17
  workflow_activation::{
18
18
  workflow_activation_job, FireTimer, ResolveActivity, WorkflowActivationJob,
19
19
  },
20
- workflow_commands::{ActivityCancellationType, RequestCancelActivity, StartTimer},
20
+ workflow_commands::{
21
+ ActivityCancellationType, RequestCancelActivity, ScheduleActivity, StartTimer,
22
+ },
21
23
  workflow_completion::WorkflowActivationCompletion,
22
24
  ActivityHeartbeat, ActivityTaskCompletion, AsJsonPayloadExt, FromJsonPayloadExt,
23
25
  IntoCompletion,
@@ -728,17 +730,24 @@ async fn activity_cancelled_after_heartbeat_times_out() {
728
730
  let activity_id = "act-1";
729
731
  let task = core.poll_workflow_activation().await.unwrap();
730
732
  // Complete workflow task and schedule activity
731
- core.complete_workflow_activation(
732
- schedule_activity_cmd(
733
- 0,
734
- &task_q,
735
- activity_id,
736
- ActivityCancellationType::WaitCancellationCompleted,
737
- Duration::from_secs(60),
738
- Duration::from_secs(1),
739
- )
740
- .into_completion(task.run_id),
741
- )
733
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
734
+ task.run_id,
735
+ ScheduleActivity {
736
+ seq: 0,
737
+ activity_id: activity_id.to_string(),
738
+ activity_type: "dontcare".to_string(),
739
+ task_queue: task_q.clone(),
740
+ schedule_to_close_timeout: Some(prost_dur!(from_secs(10))),
741
+ heartbeat_timeout: Some(prost_dur!(from_secs(1))),
742
+ retry_policy: Some(RetryPolicy {
743
+ maximum_attempts: 2,
744
+ initial_interval: Some(prost_dur!(from_secs(5))),
745
+ ..Default::default()
746
+ }),
747
+ ..Default::default()
748
+ }
749
+ .into(),
750
+ ))
742
751
  .await
743
752
  .unwrap();
744
753
  // Poll activity and verify that it's been scheduled
@@ -753,8 +762,8 @@ async fn activity_cancelled_after_heartbeat_times_out() {
753
762
 
754
763
  // Verify activity got cancelled
755
764
  let cancel_task = core.poll_activity_task().await.unwrap();
756
- assert_eq!(cancel_task.task_token, task.task_token.clone());
757
765
  assert_matches!(cancel_task.variant, Some(act_task::Variant::Cancel(_)));
766
+ assert_eq!(cancel_task.task_token, task.task_token.clone());
758
767
 
759
768
  // Complete activity with cancelled result
760
769
  core.complete_activity_task(ActivityTaskCompletion {
@@ -770,7 +779,7 @@ async fn activity_cancelled_after_heartbeat_times_out() {
770
779
  starter
771
780
  .get_client()
772
781
  .await
773
- .terminate_workflow_execution(task_q.clone(), None)
782
+ .terminate_workflow_execution(task_q, None)
774
783
  .await
775
784
  .unwrap();
776
785
  }
@@ -905,7 +914,9 @@ async fn it_can_complete_async() {
905
914
  async fn graceful_shutdown() {
906
915
  let wf_name = "graceful_shutdown";
907
916
  let mut starter = CoreWfStarter::new(wf_name);
908
- starter.worker_config.graceful_shutdown_period = Some(Duration::from_millis(500));
917
+ starter
918
+ .worker_config
919
+ .graceful_shutdown_period(Some(Duration::from_millis(500)));
909
920
  let mut worker = starter.worker().await;
910
921
  let client = starter.get_client().await;
911
922
  worker.register_wf(wf_name.to_owned(), |ctx: WfContext| async move {
@@ -91,7 +91,7 @@ async fn abandoned_child_bug_repro() {
91
91
  );
92
92
  worker.register_wf(CHILD_WF_TYPE.to_string(), |mut ctx: WfContext| async move {
93
93
  ctx.cancelled().await;
94
- Ok(WfExitValue::Cancelled)
94
+ Ok(WfExitValue::<()>::Cancelled)
95
95
  });
96
96
 
97
97
  worker
@@ -43,8 +43,8 @@ async fn continue_as_new_multiple_concurrent() {
43
43
  let mut starter = CoreWfStarter::new(wf_name);
44
44
  starter
45
45
  .no_remote_activities()
46
- .max_cached_workflows(3)
47
- .max_wft(3);
46
+ .max_cached_workflows(5)
47
+ .max_wft(5);
48
48
  let mut worker = starter.worker().await;
49
49
  worker.register_wf(wf_name.to_string(), continue_as_new_wf);
50
50
 
@@ -55,7 +55,11 @@ async fn timer_workflow_timeout_on_sticky() {
55
55
  async fn cache_miss_ok() {
56
56
  let wf_name = "cache_miss_ok";
57
57
  let mut starter = CoreWfStarter::new(wf_name);
58
- starter.no_remote_activities().max_wft(1);
58
+ starter
59
+ .no_remote_activities()
60
+ .max_wft(2)
61
+ .max_cached_workflows(0);
62
+ starter.worker_config.max_concurrent_wft_polls(1_usize);
59
63
  let mut worker = starter.worker().await;
60
64
 
61
65
  let barr: &'static Barrier = Box::leak(Box::new(Barrier::new(2)));
@@ -434,6 +434,7 @@ async fn wft_timeout_doesnt_create_unsolvable_autocomplete() {
434
434
  // Test needs eviction on and a short timeout
435
435
  .max_cached_workflows(0)
436
436
  .max_wft(1);
437
+ wf_starter.worker_config.max_concurrent_wft_polls(1_usize);
437
438
  wf_starter.workflow_options.task_timeout = Some(Duration::from_secs(1));
438
439
  let core = wf_starter.get_worker().await;
439
440
  let client = wf_starter.get_client().await;
@@ -294,6 +294,10 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
294
294
  js_value_getter!(cx, self, "maxConcurrentLocalActivityExecutions", JsNumber) as usize;
295
295
  let max_outstanding_workflow_tasks =
296
296
  js_value_getter!(cx, self, "maxConcurrentWorkflowTaskExecutions", JsNumber) as usize;
297
+ let max_concurrent_wft_polls =
298
+ js_value_getter!(cx, self, "maxConcurrentWorkflowTaskPolls", JsNumber) as usize;
299
+ let max_concurrent_at_polls =
300
+ js_value_getter!(cx, self, "maxConcurrentActivityTaskPolls", JsNumber) as usize;
297
301
  let sticky_queue_schedule_to_start_timeout = Duration::from_millis(js_value_getter!(
298
302
  cx,
299
303
  self,
@@ -319,10 +323,10 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
319
323
 
320
324
  let max_worker_activities_per_second =
321
325
  js_optional_getter!(cx, self, "maxActivitiesPerSecond", JsNumber)
322
- .map(|num| num.value(cx) as f64);
326
+ .map(|num| num.value(cx));
323
327
  let max_task_queue_activities_per_second =
324
328
  js_optional_getter!(cx, self, "maxTaskQueueActivitiesPerSecond", JsNumber)
325
- .map(|num| num.value(cx) as f64);
329
+ .map(|num| num.value(cx));
326
330
 
327
331
  let graceful_shutdown_period =
328
332
  js_optional_getter!(cx, self, "shutdownGraceTimeMs", JsNumber)
@@ -331,10 +335,13 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
331
335
  match WorkerConfigBuilder::default()
332
336
  .worker_build_id(js_value_getter!(cx, self, "buildId", JsString))
333
337
  .client_identity_override(Some(js_value_getter!(cx, self, "identity", JsString)))
338
+ .use_worker_versioning(js_value_getter!(cx, self, "useVersioning", JsBoolean))
334
339
  .no_remote_activities(!enable_remote_activities)
335
340
  .max_outstanding_workflow_tasks(max_outstanding_workflow_tasks)
336
341
  .max_outstanding_activities(max_outstanding_activities)
337
342
  .max_outstanding_local_activities(max_outstanding_local_activities)
343
+ .max_concurrent_wft_polls(max_concurrent_wft_polls)
344
+ .max_concurrent_at_polls(max_concurrent_at_polls)
338
345
  .max_cached_workflows(max_cached_workflows)
339
346
  .sticky_queue_schedule_to_start_timeout(sticky_queue_schedule_to_start_timeout)
340
347
  .graceful_shutdown_period(graceful_shutdown_period)
package/src/runtime.rs CHANGED
@@ -120,8 +120,9 @@ pub fn start_bridge_loop(
120
120
  ) {
121
121
  let mut tokio_builder = tokio::runtime::Builder::new_multi_thread();
122
122
  tokio_builder.enable_all().thread_name("core");
123
- let core_runtime =
124
- CoreRuntime::new(telemetry_options, tokio_builder).expect("Failed to create CoreRuntime");
123
+ let core_runtime = Arc::new(
124
+ CoreRuntime::new(telemetry_options, tokio_builder).expect("Failed to create CoreRuntime"),
125
+ );
125
126
 
126
127
  core_runtime.tokio_handle().block_on(async {
127
128
  loop {
@@ -144,14 +145,11 @@ pub fn start_bridge_loop(
144
145
  headers,
145
146
  callback,
146
147
  } => {
147
- // `metrics_meter` can be None here since we don't use the returned client
148
- // directly at the moment, when we repurpose the client to be used by a Worker,
149
- // `init_worker` will attach the correct metrics meter for us.
148
+ let runtime_clone = core_runtime.clone();
150
149
  core_runtime.tokio_handle().spawn(async move {
151
- let metrics_meter = None;
152
150
  match options
153
151
  .connect_no_namespace(
154
- metrics_meter,
152
+ runtime_clone.metric_meter().as_deref(),
155
153
  headers.map(|h| Arc::new(RwLock::new(h))),
156
154
  )
157
155
  .await
package/ts/errors.ts CHANGED
@@ -1,10 +1,24 @@
1
1
  import { IllegalStateError } from '@temporalio/common';
2
2
 
3
+ const isShutdownError: unique symbol = Symbol.for('__temporal_isShutdownError');
4
+
3
5
  /**
4
6
  * The worker has been shut down
5
7
  */
6
8
  export class ShutdownError extends Error {
7
9
  public readonly name = 'ShutdownError';
10
+
11
+ /**
12
+ * Marker to determine whether an error is an instance of TerminatedFailure.
13
+ */
14
+ protected readonly [isShutdownError] = true;
15
+
16
+ /**
17
+ * Instanceof check that works when multiple versions of @temporalio/core-bridge are installed.
18
+ */
19
+ static is(error: unknown): error is ShutdownError {
20
+ return error instanceof ShutdownError || (error as any)?.[isShutdownError] === true;
21
+ }
8
22
  }
9
23
 
10
24
  /**
@@ -21,6 +35,7 @@ export class TransportError extends Error {
21
35
  export class UnexpectedError extends Error {
22
36
  public readonly name = 'UnexpectedError';
23
37
  }
38
+
24
39
  export { IllegalStateError };
25
40
 
26
41
  export function convertFromNamedError(e: unknown, keepStackTrace: boolean): unknown {
package/ts/index.ts CHANGED
@@ -1,8 +1,12 @@
1
1
  import { SpanContext } from '@opentelemetry/api';
2
+ import { LogLevel, Duration } from '@temporalio/common';
2
3
  import type { TLSConfig } from '@temporalio/common/lib/internal-non-workflow';
3
4
 
4
5
  export { TLSConfig };
5
6
 
7
+ /** @deprecated Import from @temporalio/common instead */
8
+ export { LogLevel };
9
+
6
10
  type Shadow<Base, New> = Base extends object
7
11
  ? New extends object
8
12
  ? {
@@ -118,7 +122,7 @@ export interface OtelCollectorExporter {
118
122
  * @format number of milliseconds or {@link https://www.npmjs.com/package/ms | ms-formatted string}
119
123
  * @defaults 1 second
120
124
  */
121
- metricsExportInterval?: string | number;
125
+ metricsExportInterval?: Duration;
122
126
  };
123
127
  }
124
128
 
@@ -266,6 +270,13 @@ export interface WorkerOptions {
266
270
  * A string that should be unique to the exact worker code/binary being executed
267
271
  */
268
272
  buildId: string;
273
+ /**
274
+ * If set true, this worker opts into the worker versioning feature. This ensures it only receives
275
+ * workflow tasks for workflows which it claims to be compatible with.
276
+ *
277
+ * For more information, see https://docs.temporal.io/workers#worker-versioning
278
+ */
279
+ useVersioning: boolean;
269
280
 
270
281
  /**
271
282
  * The task queue the worker will pull from
@@ -276,6 +287,16 @@ export interface WorkerOptions {
276
287
  maxConcurrentWorkflowTaskExecutions: number;
277
288
  maxConcurrentLocalActivityExecutions: number;
278
289
 
290
+ /**
291
+ * Maximum number of Workflow tasks to poll concurrently.
292
+ */
293
+ maxConcurrentWorkflowTaskPolls: number;
294
+
295
+ /**
296
+ * Maximum number of Activity tasks to poll concurrently.
297
+ */
298
+ maxConcurrentActivityTaskPolls: number;
299
+
279
300
  /**
280
301
  * If set to `false` this worker will only handle workflow tasks and local activities, it will not
281
302
  * poll for activity tasks.
@@ -323,9 +344,6 @@ export interface WorkerOptions {
323
344
  maxActivitiesPerSecond?: number;
324
345
  }
325
346
 
326
- /** Log level - must match rust log level names */
327
- export type LogLevel = 'TRACE' | 'DEBUG' | 'INFO' | 'WARN' | 'ERROR';
328
-
329
347
  export interface LogEntry {
330
348
  /** Log message */
331
349
  message: string;