@temporalio/core-bridge 1.0.0-rc.0 → 1.0.0-rc.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@temporalio/core-bridge",
3
- "version": "1.0.0-rc.0",
3
+ "version": "1.0.0-rc.1",
4
4
  "description": "Temporal.io SDK Core<>Node bridge",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -19,10 +19,10 @@
19
19
  "author": "Roey Berman <roey@temporal.io>",
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
- "@opentelemetry/api": "^1.0.3",
23
- "@temporalio/internal-non-workflow-common": "^1.0.0-rc.0",
24
- "arg": "^5.0.1",
25
- "cargo-cp-artifact": "^0.1.4",
22
+ "@opentelemetry/api": "^1.1.0",
23
+ "@temporalio/internal-non-workflow-common": "^1.0.0-rc.1",
24
+ "arg": "^5.0.2",
25
+ "cargo-cp-artifact": "^0.1.6",
26
26
  "which": "^2.0.2"
27
27
  },
28
28
  "bugs": {
@@ -43,5 +43,5 @@
43
43
  "publishConfig": {
44
44
  "access": "public"
45
45
  },
46
- "gitHead": "c25e91309b980f2118df4048d760306982019871"
46
+ "gitHead": "723de0fbc7a04e68084ec99453578e7027eb3803"
47
47
  }
@@ -711,6 +711,17 @@ impl WorkflowMachines {
711
711
  /// to the server. While doing so, [TemporalStateMachine::handle_command] is called on the
712
712
  /// machine associated with the command.
713
713
  fn prepare_commands(&mut self) -> Result<()> {
714
+ // It's possible we might prepare commands more than once before completing a WFT. (Because
715
+ // of local activities, of course). Some commands might have since been cancelled that we
716
+ // already prepared. Rip them out of the outgoing command list if so.
717
+ self.commands.retain(|c| {
718
+ !self
719
+ .all_machines
720
+ .get(c.machine)
721
+ .expect("Machine must exist")
722
+ .was_cancelled_before_sent_to_server()
723
+ });
724
+
714
725
  while let Some(c) = self.current_wf_task_commands.pop_front() {
715
726
  if !self
716
727
  .machine(c.machine)
@@ -122,11 +122,10 @@ impl WorkflowFuture {
122
122
  UnblockEvent::CancelExternal(seq, _) => CommandID::CancelExternal(seq),
123
123
  };
124
124
  let unblocker = self.command_status.remove(&cmd_id);
125
- unblocker
125
+ let _ = unblocker
126
126
  .ok_or_else(|| anyhow!("Command {:?} not found to unblock!", cmd_id))?
127
127
  .unblocker
128
- .send(event)
129
- .expect("Receive half of unblock channel must exist");
128
+ .send(event);
130
129
  Ok(())
131
130
  }
132
131
 
@@ -580,3 +580,55 @@ async fn timer_backoff_concurrent_with_non_timer_backoff() {
580
580
  .unwrap();
581
581
  worker.run_until_done().await.unwrap();
582
582
  }
583
+
584
+ #[tokio::test]
585
+ async fn repro_nondeterminism_with_timer_bug() {
586
+ let wf_name = "repro_nondeterminism_with_timer_bug";
587
+ let mut starter = CoreWfStarter::new(wf_name);
588
+ let mut worker = starter.worker().await;
589
+
590
+ worker.register_wf(wf_name.to_owned(), |ctx: WfContext| async move {
591
+ let t1 = ctx.timer(Duration::from_secs(30));
592
+ let r1 = ctx.local_activity(LocalActivityOptions {
593
+ activity_type: "delay".to_string(),
594
+ input: "hi".as_json_payload().expect("serializes fine"),
595
+ retry_policy: RetryPolicy {
596
+ initial_interval: Some(Duration::from_micros(15).into()),
597
+ backoff_coefficient: 1_000.,
598
+ maximum_interval: Some(Duration::from_millis(1500).into()),
599
+ maximum_attempts: 4,
600
+ non_retryable_error_types: vec![],
601
+ },
602
+ timer_backoff_threshold: Some(Duration::from_secs(1)),
603
+ ..Default::default()
604
+ });
605
+ tokio::pin!(t1);
606
+ tokio::select! {
607
+ _ = &mut t1 => {},
608
+ _ = r1 => {
609
+ t1.cancel(&ctx);
610
+ },
611
+ };
612
+ ctx.timer(Duration::from_secs(1)).await;
613
+ Ok(().into())
614
+ });
615
+ worker.register_activity("delay", |_: ActContext, _: String| async {
616
+ tokio::time::sleep(Duration::from_secs(2)).await;
617
+ Ok(())
618
+ });
619
+
620
+ let run_id = worker
621
+ .submit_wf(
622
+ wf_name.to_owned(),
623
+ wf_name.to_owned(),
624
+ vec![],
625
+ WorkflowOptions::default(),
626
+ )
627
+ .await
628
+ .unwrap();
629
+ worker.run_until_done().await.unwrap();
630
+ starter
631
+ .fetch_history_and_replay(wf_name, run_id, worker.inner_mut())
632
+ .await
633
+ .unwrap();
634
+ }