@temporalio/core-bridge 1.10.2 → 1.11.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 (126) hide show
  1. package/Cargo.lock +563 -676
  2. package/Cargo.toml +3 -3
  3. package/lib/index.d.ts +16 -5
  4. package/lib/index.js.map +1 -1
  5. package/lib/worker-tuner.d.ts +57 -0
  6. package/lib/worker-tuner.js +3 -0
  7. package/lib/worker-tuner.js.map +1 -0
  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 +6 -11
  15. package/sdk-core/.github/workflows/per-pr.yml +23 -41
  16. package/sdk-core/Cargo.toml +5 -5
  17. package/sdk-core/README.md +2 -0
  18. package/sdk-core/client/Cargo.toml +4 -2
  19. package/sdk-core/client/src/lib.rs +60 -17
  20. package/sdk-core/client/src/metrics.rs +1 -1
  21. package/sdk-core/client/src/proxy.rs +17 -12
  22. package/sdk-core/client/src/raw.rs +218 -69
  23. package/sdk-core/client/src/retry.rs +19 -9
  24. package/sdk-core/core/Cargo.toml +12 -12
  25. package/sdk-core/core/src/abstractions.rs +3 -3
  26. package/sdk-core/core/src/core_tests/activity_tasks.rs +2 -1
  27. package/sdk-core/core/src/core_tests/determinism.rs +1 -1
  28. package/sdk-core/core/src/core_tests/local_activities.rs +73 -10
  29. package/sdk-core/core/src/core_tests/queries.rs +2 -1
  30. package/sdk-core/core/src/core_tests/updates.rs +162 -4
  31. package/sdk-core/core/src/core_tests/workers.rs +38 -2
  32. package/sdk-core/core/src/core_tests/workflow_tasks.rs +158 -27
  33. package/sdk-core/core/src/internal_flags.rs +17 -7
  34. package/sdk-core/core/src/lib.rs +9 -3
  35. package/sdk-core/core/src/pollers/poll_buffer.rs +1 -10
  36. package/sdk-core/core/src/protosext/mod.rs +0 -1
  37. package/sdk-core/core/src/protosext/protocol_messages.rs +105 -16
  38. package/sdk-core/core/src/retry_logic.rs +22 -2
  39. package/sdk-core/core/src/telemetry/otel.rs +44 -12
  40. package/sdk-core/core/src/test_help/mod.rs +65 -12
  41. package/sdk-core/core/src/worker/activities/local_activities.rs +1 -4
  42. package/sdk-core/core/src/worker/activities.rs +3 -4
  43. package/sdk-core/core/src/worker/client/mocks.rs +7 -6
  44. package/sdk-core/core/src/worker/client.rs +11 -2
  45. package/sdk-core/core/src/worker/mod.rs +49 -24
  46. package/sdk-core/core/src/worker/tuner/resource_based.rs +48 -48
  47. package/sdk-core/core/src/worker/tuner.rs +124 -4
  48. package/sdk-core/core/src/worker/workflow/driven_workflow.rs +1 -1
  49. package/sdk-core/core/src/worker/workflow/history_update.rs +11 -2
  50. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +18 -3
  51. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +1 -0
  52. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +1 -0
  53. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +1 -0
  54. package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +1 -0
  55. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +1 -0
  56. package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +1 -0
  57. package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +4 -4
  58. package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +1 -0
  59. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +1 -0
  60. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +1 -0
  61. package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +3 -1
  62. package/sdk-core/core/src/worker/workflow/machines/update_state_machine.rs +38 -28
  63. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +4 -2
  64. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +95 -71
  65. package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +1 -1
  66. package/sdk-core/core/src/worker/workflow/managed_run.rs +214 -14
  67. package/sdk-core/core/src/worker/workflow/mod.rs +49 -36
  68. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +1 -2
  69. package/sdk-core/core-api/src/errors.rs +13 -7
  70. package/sdk-core/core-api/src/lib.rs +9 -1
  71. package/sdk-core/sdk/Cargo.toml +1 -1
  72. package/sdk-core/sdk/src/activity_context.rs +3 -4
  73. package/sdk-core/sdk/src/lib.rs +96 -49
  74. package/sdk-core/sdk/src/workflow_context/options.rs +8 -4
  75. package/sdk-core/sdk/src/workflow_context.rs +53 -49
  76. package/sdk-core/sdk/src/workflow_future.rs +10 -4
  77. package/sdk-core/sdk-core-protos/Cargo.toml +4 -3
  78. package/sdk-core/sdk-core-protos/build.rs +2 -0
  79. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/.github/workflows/build.yaml +18 -0
  80. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/LICENSE +21 -0
  81. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/Makefile +59 -0
  82. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/README.md +25 -0
  83. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/VERSION +1 -0
  84. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/buf.gen.yaml +14 -0
  85. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/buf.lock +8 -0
  86. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/buf.yaml +9 -0
  87. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/cloudservice/v1/request_response.proto +520 -0
  88. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/cloudservice/v1/service.proto +263 -0
  89. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/identity/v1/message.proto +173 -0
  90. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/namespace/v1/message.proto +164 -0
  91. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/operation/v1/message.proto +36 -0
  92. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/region/v1/message.proto +22 -0
  93. package/sdk-core/sdk-core-protos/protos/api_upstream/.github/workflows/trigger-api-go-update.yml +50 -8
  94. package/sdk-core/sdk-core-protos/protos/api_upstream/.gitmodules +3 -0
  95. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv2.json +132 -54
  96. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv3.yaml +177 -81
  97. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/command/v1/message.proto +13 -0
  98. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +2 -0
  99. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +8 -3
  100. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/history/v1/message.proto +10 -0
  101. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/nexus/v1/message.proto +3 -3
  102. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +6 -6
  103. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/enhanced_stack_trace.proto +96 -0
  104. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/user_metadata.proto +49 -0
  105. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/workflow_metadata.proto +6 -7
  106. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +55 -24
  107. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflow/v1/message.proto +7 -0
  108. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +21 -4
  109. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +64 -45
  110. package/sdk-core/sdk-core-protos/src/history_builder.rs +8 -1
  111. package/sdk-core/sdk-core-protos/src/lib.rs +40 -10
  112. package/sdk-core/test-utils/src/canned_histories.rs +1 -1
  113. package/sdk-core/tests/fuzzy_workflow.rs +4 -2
  114. package/sdk-core/tests/heavy_tests.rs +3 -3
  115. package/sdk-core/tests/integ_tests/activity_functions.rs +2 -2
  116. package/sdk-core/tests/integ_tests/client_tests.rs +234 -6
  117. package/sdk-core/tests/integ_tests/update_tests.rs +180 -47
  118. package/sdk-core/tests/integ_tests/worker_tests.rs +32 -0
  119. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +47 -3
  120. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +10 -10
  121. package/sdk-core/tests/main.rs +1 -0
  122. package/src/conversions.rs +84 -11
  123. package/src/runtime.rs +5 -17
  124. package/src/worker.rs +27 -6
  125. package/ts/index.ts +24 -5
  126. package/ts/worker-tuner.ts +71 -0
@@ -1,5 +1,6 @@
1
1
  use crate::{
2
2
  abstractions::dbg_panic,
3
+ internal_flags::CoreInternalFlags,
3
4
  protosext::{protocol_messages::IncomingProtocolMessage, WorkflowActivationExt},
4
5
  telemetry::metrics,
5
6
  worker::{
@@ -422,20 +423,7 @@ impl ManagedRun {
422
423
  );
423
424
  Ok(None)
424
425
  } else {
425
- // First strip out query responses from other commands that actually affect machines
426
- // Would be prettier with `drain_filter`
427
- let mut query_responses = vec![];
428
- commands = std::mem::take(&mut commands)
429
- .into_iter()
430
- .filter_map(|x| {
431
- if let WFCommand::QueryResponse(qr) = x {
432
- query_responses.push(qr);
433
- None
434
- } else {
435
- Some(x)
436
- }
437
- })
438
- .collect();
426
+ let (commands, query_responses) = self.preprocess_command_sequence(commands);
439
427
 
440
428
  if activation_was_only_eviction && !commands.is_empty() {
441
429
  dbg_panic!("Reply to an eviction included commands");
@@ -479,6 +467,38 @@ impl ManagedRun {
479
467
  }
480
468
  }
481
469
 
470
+ /// Core has received from lang a sequence containing all commands generated
471
+ /// by all workflow coroutines. Return a command sequence containing all
472
+ /// non-terminal (i.e. non-workflow-terminating) commands, followed by the
473
+ /// first terminal command if there are any. Also strip out and return query
474
+ /// results (these don't affect machines and are handled separately
475
+ /// downstream)
476
+ ///
477
+ /// The reordering is done in order that all non-terminal commands generated
478
+ /// by workflow coroutines are given a chance for the server to honor them.
479
+ /// For example, in order to deliver an update result to a client as the
480
+ /// workflow completes.
481
+ ///
482
+ /// Behavior here has changed backwards-incompatibly, so a flag is set if
483
+ /// the outcome differs from what the outcome would have been previously.
484
+ /// See also CoreInternalFlags::MoveTerminalCommands docstring and
485
+ /// https://github.com/temporalio/features/issues/481.
486
+ fn preprocess_command_sequence(
487
+ &mut self,
488
+ commands: Vec<WFCommand>,
489
+ ) -> (Vec<WFCommand>, Vec<QueryResult>) {
490
+ if self.wfm.machines.replaying
491
+ && !self
492
+ .wfm
493
+ .machines
494
+ .try_use_flag(CoreInternalFlags::MoveTerminalCommands, false)
495
+ {
496
+ preprocess_command_sequence_old_behavior(commands)
497
+ } else {
498
+ preprocess_command_sequence(commands)
499
+ }
500
+ }
501
+
482
502
  /// Called after the higher-up machinery has fetched more pages of event history needed to apply
483
503
  /// the next workflow task. The history update and paginator used to perform the fetch are
484
504
  /// passed in, with the update being used to apply the task, and the paginator stored to be
@@ -1169,6 +1189,60 @@ impl ManagedRun {
1169
1189
  }
1170
1190
  }
1171
1191
 
1192
+ // Construct a new command sequence with query responses removed, and any
1193
+ // terminal responses removed, except for the first terminal response, which is
1194
+ // placed at the end. Return new command sequence and query commands. Note that
1195
+ // multiple coroutines may have generated a terminal command, leading to
1196
+ // multiple terminal commands in the input to this function.
1197
+ fn preprocess_command_sequence(commands: Vec<WFCommand>) -> (Vec<WFCommand>, Vec<QueryResult>) {
1198
+ let mut query_results = vec![];
1199
+ let mut terminals = vec![];
1200
+
1201
+ let mut commands: Vec<_> = commands
1202
+ .into_iter()
1203
+ .filter_map(|c| {
1204
+ if let WFCommand::QueryResponse(qr) = c {
1205
+ query_results.push(qr);
1206
+ None
1207
+ } else if c.is_terminal() {
1208
+ terminals.push(c);
1209
+ None
1210
+ } else {
1211
+ Some(c)
1212
+ }
1213
+ })
1214
+ .collect();
1215
+ if let Some(first_terminal) = terminals.into_iter().next() {
1216
+ commands.push(first_terminal);
1217
+ }
1218
+ (commands, query_results)
1219
+ }
1220
+
1221
+ fn preprocess_command_sequence_old_behavior(
1222
+ commands: Vec<WFCommand>,
1223
+ ) -> (Vec<WFCommand>, Vec<QueryResult>) {
1224
+ let mut query_results = vec![];
1225
+ let mut seen_terminal = false;
1226
+
1227
+ let commands: Vec<_> = commands
1228
+ .into_iter()
1229
+ .filter_map(|c| {
1230
+ if let WFCommand::QueryResponse(qr) = c {
1231
+ query_results.push(qr);
1232
+ None
1233
+ } else if seen_terminal {
1234
+ None
1235
+ } else {
1236
+ if c.is_terminal() {
1237
+ seen_terminal = true;
1238
+ }
1239
+ Some(c)
1240
+ }
1241
+ })
1242
+ .collect();
1243
+ (commands, query_results)
1244
+ }
1245
+
1172
1246
  /// Drains pending queries from the workflow task and appends them to the activation's jobs
1173
1247
  fn put_queries_in_act(act: &mut WorkflowActivation, wft: &mut OutstandingTask) {
1174
1248
  // Nothing to do if there are no pending queries
@@ -1397,3 +1471,129 @@ impl From<WFMachinesError> for RunUpdateErr {
1397
1471
  }
1398
1472
  }
1399
1473
  }
1474
+
1475
+ #[cfg(test)]
1476
+ mod tests {
1477
+ use crate::worker::workflow::WFCommand;
1478
+ use std::mem::{discriminant, Discriminant};
1479
+
1480
+ use command_utils::*;
1481
+
1482
+ #[rstest::rstest]
1483
+ #[case::empty(
1484
+ vec![],
1485
+ vec![])]
1486
+ #[case::non_terminal_is_retained(
1487
+ vec![update_response()],
1488
+ vec![update_response()])]
1489
+ #[case::terminal_is_retained(
1490
+ vec![complete()],
1491
+ vec![complete()])]
1492
+ #[case::post_terminal_is_retained(
1493
+ vec![complete(), update_response()],
1494
+ vec![update_response(), complete()])]
1495
+ #[case::second_terminal_is_discarded(
1496
+ vec![cancel(), complete()],
1497
+ vec![cancel()])]
1498
+ #[case::move_terminals_to_end_and_retain_first(
1499
+ vec![update_response(), complete(), update_response(), cancel(), update_response()],
1500
+ vec![update_response(), update_response(), update_response(), complete()])]
1501
+ #[test]
1502
+ fn preprocess_command_sequence(
1503
+ #[case] commands_in: Vec<WFCommand>,
1504
+ #[case] expected_commands: Vec<WFCommand>,
1505
+ ) {
1506
+ let (commands, _) = super::preprocess_command_sequence(commands_in);
1507
+ assert_eq!(command_types(&commands), command_types(&expected_commands));
1508
+ }
1509
+
1510
+ #[rstest::rstest]
1511
+ #[case::query_responses_extracted(
1512
+ vec![query_response(), update_response(), query_response(), complete(), query_response()],
1513
+ 3,
1514
+ )]
1515
+ #[test]
1516
+ fn preprocess_command_sequence_extracts_queries(
1517
+ #[case] commands_in: Vec<WFCommand>,
1518
+ #[case] expected_queries_out: usize,
1519
+ ) {
1520
+ let (_, query_responses_out) = super::preprocess_command_sequence(commands_in);
1521
+ assert_eq!(query_responses_out.len(), expected_queries_out);
1522
+ }
1523
+
1524
+ #[rstest::rstest]
1525
+ #[case::empty(
1526
+ vec![],
1527
+ vec![])]
1528
+ #[case::non_terminal_is_retained(
1529
+ vec![update_response()],
1530
+ vec![update_response()])]
1531
+ #[case::terminal_is_retained(
1532
+ vec![complete()],
1533
+ vec![complete()])]
1534
+ #[case::post_terminal_is_discarded(
1535
+ vec![complete(), update_response()],
1536
+ vec![complete()])]
1537
+ #[case::second_terminal_is_discarded(
1538
+ vec![cancel(), complete()],
1539
+ vec![cancel()])]
1540
+ #[case::truncate_at_first_complete(
1541
+ vec![update_response(), complete(), update_response(), cancel()],
1542
+ vec![update_response(), complete()])]
1543
+ #[test]
1544
+ fn preprocess_command_sequence_old_behavior(
1545
+ #[case] commands_in: Vec<WFCommand>,
1546
+ #[case] expected_out: Vec<WFCommand>,
1547
+ ) {
1548
+ let (commands_out, _) = super::preprocess_command_sequence_old_behavior(commands_in);
1549
+ assert_eq!(command_types(&commands_out), command_types(&expected_out));
1550
+ }
1551
+
1552
+ #[rstest::rstest]
1553
+ #[case::query_responses_extracted(
1554
+ vec![query_response(), update_response(), query_response(), complete(), query_response()],
1555
+ 3,
1556
+ )]
1557
+ #[test]
1558
+ fn preprocess_command_sequence_old_behavior_extracts_queries(
1559
+ #[case] commands_in: Vec<WFCommand>,
1560
+ #[case] expected_queries_out: usize,
1561
+ ) {
1562
+ let (_, query_responses_out) = super::preprocess_command_sequence_old_behavior(commands_in);
1563
+ assert_eq!(query_responses_out.len(), expected_queries_out);
1564
+ }
1565
+
1566
+ mod command_utils {
1567
+ use temporal_sdk_core_protos::coresdk::workflow_commands::{
1568
+ CancelWorkflowExecution, CompleteWorkflowExecution, QueryResult, UpdateResponse,
1569
+ };
1570
+
1571
+ use super::*;
1572
+
1573
+ pub(crate) fn complete() -> WFCommand {
1574
+ WFCommand::CompleteWorkflow(CompleteWorkflowExecution { result: None })
1575
+ }
1576
+
1577
+ pub(crate) fn cancel() -> WFCommand {
1578
+ WFCommand::CancelWorkflow(CancelWorkflowExecution {})
1579
+ }
1580
+
1581
+ pub(crate) fn query_response() -> WFCommand {
1582
+ WFCommand::QueryResponse(QueryResult {
1583
+ query_id: "".into(),
1584
+ variant: None,
1585
+ })
1586
+ }
1587
+
1588
+ pub(crate) fn update_response() -> WFCommand {
1589
+ WFCommand::UpdateResponse(UpdateResponse {
1590
+ protocol_instance_id: "".into(),
1591
+ response: None,
1592
+ })
1593
+ }
1594
+
1595
+ pub(crate) fn command_types(commands: &[WFCommand]) -> Vec<Discriminant<WFCommand>> {
1596
+ commands.iter().map(discriminant).collect()
1597
+ }
1598
+ }
1599
+ }
@@ -40,6 +40,7 @@ use crate::{
40
40
  use anyhow::anyhow;
41
41
  use futures::{stream::BoxStream, Stream, StreamExt};
42
42
  use futures_util::{future::abortable, stream};
43
+ use itertools::Itertools;
43
44
  use prost_types::TimestampError;
44
45
  use std::{
45
46
  cell::RefCell,
@@ -223,9 +224,11 @@ impl Workflows {
223
224
  .expect("Activation processor channel not dropped");
224
225
  }
225
226
  }
226
- Err(e) => activation_tx
227
- .send(Err(e))
228
- .expect("Activation processor channel not dropped"),
227
+ Err(e) => {
228
+ let _ = activation_tx.send(Err(e)).inspect_err(|e| {
229
+ error!(activation=?e.0, "Activation processor channel dropped");
230
+ });
231
+ }
229
232
  }
230
233
  }
231
234
  });
@@ -267,33 +270,41 @@ impl Workflows {
267
270
  break Ok(act);
268
271
  }
269
272
  ActivationOrAuto::Autocomplete { run_id } => {
270
- self.activation_completed(
271
- WorkflowActivationCompletion {
272
- run_id,
273
- status: Some(
274
- workflow_completion::Success::from_variants(vec![]).into(),
275
- ),
276
- },
277
- true,
278
- // We need to say a type, but the type is irrelevant, so imagine some
279
- // boxed function we'll never call.
280
- Option::<Box<dyn Fn(PostActivateHookData) + Send>>::None,
281
- )
282
- .await?;
273
+ if let Err(e) = self
274
+ .activation_completed(
275
+ WorkflowActivationCompletion {
276
+ run_id,
277
+ status: Some(
278
+ workflow_completion::Success::from_variants(vec![]).into(),
279
+ ),
280
+ },
281
+ true,
282
+ // We need to say a type, but the type is irrelevant, so imagine some
283
+ // boxed function we'll never call.
284
+ Option::<Box<dyn Fn(PostActivateHookData) + Send>>::None,
285
+ )
286
+ .await
287
+ {
288
+ error!(error=?e, "Error while auto-completing workflow task");
289
+ }
283
290
  }
284
291
  ActivationOrAuto::AutoFail {
285
292
  run_id,
286
293
  machines_err,
287
294
  } => {
288
- self.activation_completed(
289
- WorkflowActivationCompletion {
290
- run_id,
291
- status: Some(machines_err.as_failure().into()),
292
- },
293
- true,
294
- Option::<Box<dyn Fn(PostActivateHookData) + Send>>::None,
295
- )
296
- .await?;
295
+ if let Err(e) = self
296
+ .activation_completed(
297
+ WorkflowActivationCompletion {
298
+ run_id,
299
+ status: Some(machines_err.as_failure().into()),
300
+ },
301
+ true,
302
+ Option::<Box<dyn Fn(PostActivateHookData) + Send>>::None,
303
+ )
304
+ .await
305
+ {
306
+ error!(error=?e, "Error while auto-failing workflow task");
307
+ }
297
308
  }
298
309
  }
299
310
  }
@@ -793,6 +804,18 @@ impl PreparedWFT {
793
804
  let no_new_history = self.update.wft_started_id == 0;
794
805
  no_new_history && self.legacy_query.is_some()
795
806
  }
807
+
808
+ /// Useful for showing detailed info on incoming WFTs
809
+ #[allow(dead_code)]
810
+ fn print_details(&self) -> String {
811
+ format!(
812
+ "WFT events: [{}], messages: {:?}, legacy_query: {:?}, queries: {:?}",
813
+ self.update.get_events().iter().format(", "),
814
+ &self.messages,
815
+ &self.legacy_query,
816
+ &self.query_requests
817
+ )
818
+ }
796
819
  }
797
820
 
798
821
  #[derive(Debug)]
@@ -1020,7 +1043,7 @@ fn validate_completion(
1020
1043
  match completion.status {
1021
1044
  Some(workflow_activation_completion::Status::Successful(success)) => {
1022
1045
  // Convert to wf commands
1023
- let mut commands = success
1046
+ let commands = success
1024
1047
  .commands
1025
1048
  .into_iter()
1026
1049
  .map(|c| c.try_into())
@@ -1047,16 +1070,6 @@ fn validate_completion(
1047
1070
  });
1048
1071
  }
1049
1072
 
1050
- // Any non-query-response commands after a terminal command should be ignored
1051
- if let Some(term_cmd_pos) = commands.iter().position(|c| c.is_terminal()) {
1052
- // Query responses are just fine, so keep them.
1053
- let queries = commands
1054
- .split_off(term_cmd_pos + 1)
1055
- .into_iter()
1056
- .filter(|c| matches!(c, WFCommand::QueryResponse(_)));
1057
- commands.extend(queries);
1058
- }
1059
-
1060
1073
  Ok(ValidatedCompletion::Success {
1061
1074
  run_id: completion.run_id,
1062
1075
  commands,
@@ -87,7 +87,7 @@ impl WFStream {
87
87
  buffered_polls_need_cache_slot: Default::default(),
88
88
  runs: RunCache::new(
89
89
  basics.worker_config.clone(),
90
- basics.server_capabilities.clone(),
90
+ basics.server_capabilities,
91
91
  local_activity_request_sink,
92
92
  basics.metrics.clone(),
93
93
  ),
@@ -165,7 +165,6 @@ impl WFStream {
165
165
  None
166
166
  }
167
167
  WFStreamInput::PollerError(e) => {
168
- warn!("WFT poller errored, shutting down");
169
168
  return Err(PollWfError::TonicError(e));
170
169
  }
171
170
  };
@@ -2,23 +2,29 @@
2
2
 
3
3
  use temporal_sdk_core_protos::coresdk::activity_result::ActivityExecutionResult;
4
4
 
5
+ /// Errors thrown by [crate::Worker::validate]
6
+ #[derive(thiserror::Error, Debug)]
7
+ pub enum WorkerValidationError {
8
+ /// The namespace provided to the worker does not exist on the server.
9
+ #[error("Namespace {namespace} was not found or otherwise could not be described: {source:?}")]
10
+ NamespaceDescribeError {
11
+ source: tonic::Status,
12
+ namespace: String,
13
+ },
14
+ }
15
+
5
16
  /// Errors thrown by [crate::Worker::poll_workflow_activation]
6
17
  #[derive(thiserror::Error, Debug)]
7
18
  pub enum PollWfError {
8
19
  /// [crate::Worker::shutdown] was called, and there are no more replay tasks to be handled. Lang
9
- /// must call [crate::Worker::complete_workflow_activation] for any remaining tasks, and then may
10
- /// exit.
20
+ /// must call [crate::Worker::complete_workflow_activation] for any remaining tasks, and then
21
+ /// may exit.
11
22
  #[error("Core is shut down and there are no more workflow replay tasks")]
12
23
  ShutDown,
13
24
  /// Unhandled error when calling the temporal server. Core will attempt to retry any non-fatal
14
25
  /// errors, so lang should consider this fatal.
15
26
  #[error("Unhandled grpc error when workflow polling: {0:?}")]
16
27
  TonicError(#[from] tonic::Status),
17
- /// Unhandled error when completing a workflow during a poll -- this can happen when there is no
18
- /// work for lang to perform, but the server sent us a workflow task (EX: An activity completed
19
- /// even though we already cancelled it)
20
- #[error("Unhandled error when auto-completing workflow task: {0:?}")]
21
- AutocompleteError(#[from] CompleteWfError),
22
28
  }
23
29
 
24
30
  /// Errors thrown by [crate::Worker::poll_activity_task]
@@ -3,7 +3,10 @@ pub mod telemetry;
3
3
  pub mod worker;
4
4
 
5
5
  use crate::{
6
- errors::{CompleteActivityError, CompleteWfError, PollActivityError, PollWfError},
6
+ errors::{
7
+ CompleteActivityError, CompleteWfError, PollActivityError, PollWfError,
8
+ WorkerValidationError,
9
+ },
7
10
  worker::WorkerConfig,
8
11
  };
9
12
  use temporal_sdk_core_protos::coresdk::{
@@ -16,6 +19,11 @@ use temporal_sdk_core_protos::coresdk::{
16
19
  /// and is bound to a specific task queue.
17
20
  #[async_trait::async_trait]
18
21
  pub trait Worker: Send + Sync {
22
+ /// Validate that the worker can properly connect to server, plus any other validation that
23
+ /// needs to be done asynchronously. Lang SDKs should call this function once before calling
24
+ /// any others.
25
+ async fn validate(&self) -> Result<(), WorkerValidationError>;
26
+
19
27
  /// Ask the worker for some work, returning a [WorkflowActivation]. It is then the language
20
28
  /// SDK's responsibility to call the appropriate workflow code with the provided inputs. Blocks
21
29
  /// indefinitely until such work is available or [Worker::shutdown] is called.
@@ -18,7 +18,7 @@ crossbeam-channel = "0.5"
18
18
  derive_more = { workspace = true }
19
19
  futures = "0.3"
20
20
  parking_lot = { version = "0.12", features = ["send_guard"] }
21
- prost-types = { version = "0.5", package = "prost-wkt-types" }
21
+ prost-types = { version = "0.6", package = "prost-wkt-types" }
22
22
  serde = "1.0"
23
23
  tokio = { version = "1.26", features = ["rt", "rt-multi-thread", "parking_lot", "time", "fs"] }
24
24
  tokio-util = { version = "0.7" }
@@ -188,10 +188,9 @@ fn calculate_deadline(
188
188
  ) => {
189
189
  let scheduled: SystemTime = maybe_convert_timestamp(scheduled)?;
190
190
  let started: SystemTime = maybe_convert_timestamp(started)?;
191
- let start_to_close_timeout: StdDuration =
192
- start_to_close_timeout.clone().try_into().ok()?;
191
+ let start_to_close_timeout: StdDuration = (*start_to_close_timeout).try_into().ok()?;
193
192
  let schedule_to_close_timeout: StdDuration =
194
- schedule_to_close_timeout.clone().try_into().ok()?;
193
+ (*schedule_to_close_timeout).try_into().ok()?;
195
194
 
196
195
  let start_to_close_deadline: SystemTime =
197
196
  started.checked_add(start_to_close_timeout)?;
@@ -215,7 +214,7 @@ fn calculate_deadline(
215
214
  /// Helper function lifted from prost_types::Timestamp implementation to prevent double cloning in
216
215
  /// error construction
217
216
  fn maybe_convert_timestamp(timestamp: &Timestamp) -> Option<SystemTime> {
218
- let mut timestamp = timestamp.clone();
217
+ let mut timestamp = *timestamp;
219
218
  timestamp.normalize();
220
219
 
221
220
  let system_time = if timestamp.seconds >= 0 {