@temporalio/core-bridge 0.16.3 → 0.16.4

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/index.node CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@temporalio/core-bridge",
3
- "version": "0.16.3",
3
+ "version": "0.16.4",
4
4
  "description": "Temporal.io SDK Core<>Node bridge",
5
5
  "main": "index.node",
6
6
  "types": "index.d.ts",
@@ -19,7 +19,7 @@
19
19
  "license": "MIT",
20
20
  "dependencies": {
21
21
  "@opentelemetry/api": "^1.0.3",
22
- "@temporalio/common": "^0.16.0",
22
+ "@temporalio/common": "^0.16.4",
23
23
  "arg": "^5.0.1",
24
24
  "cargo-cp-artifact": "^0.1.4",
25
25
  "which": "^2.0.2"
@@ -40,5 +40,5 @@
40
40
  "publishConfig": {
41
41
  "access": "public"
42
42
  },
43
- "gitHead": "af54140a4da7e191c06627c5e06b92a3fd929bcc"
43
+ "gitHead": "884a10970cdbc3e8d7991709e0fa3fe79fce71bd"
44
44
  }
@@ -1665,3 +1665,72 @@ async fn failing_wft_doesnt_eat_permit_forever() {
1665
1665
 
1666
1666
  core.shutdown().await;
1667
1667
  }
1668
+
1669
+ #[tokio::test]
1670
+ async fn cache_miss_doesnt_eat_permit_forever() {
1671
+ let mut t = TestHistoryBuilder::default();
1672
+ t.add_by_type(EventType::WorkflowExecutionStarted);
1673
+ t.add_full_wf_task();
1674
+ t.add_we_signaled("sig", vec![]);
1675
+ t.add_full_wf_task();
1676
+ t.add_workflow_execution_completed();
1677
+
1678
+ let mut mh = MockPollCfg::from_resp_batches(
1679
+ "fake_wf_id",
1680
+ t,
1681
+ [
1682
+ ResponseType::ToTaskNum(1),
1683
+ ResponseType::OneTask(2),
1684
+ ResponseType::ToTaskNum(1),
1685
+ ResponseType::OneTask(2),
1686
+ ResponseType::ToTaskNum(1),
1687
+ ResponseType::OneTask(2),
1688
+ // Last one to complete successfully
1689
+ ResponseType::ToTaskNum(1),
1690
+ ],
1691
+ MockServerGatewayApis::new(),
1692
+ );
1693
+ mh.num_expected_fails = Some(3);
1694
+ mh.expect_fail_wft_matcher =
1695
+ Box::new(|_, cause, _| matches!(cause, WorkflowTaskFailedCause::ResetStickyTaskQueue));
1696
+ let mut mock = build_mock_pollers(mh);
1697
+ mock.worker_cfg(TEST_Q, |cfg| {
1698
+ cfg.max_outstanding_workflow_tasks = 2;
1699
+ });
1700
+ let core = mock_core(mock);
1701
+
1702
+ // Spin missing the cache to verify that we don't get stuck
1703
+ for _ in 1..=3 {
1704
+ // Start
1705
+ let activation = core.poll_workflow_activation(TEST_Q).await.unwrap();
1706
+ core.complete_workflow_activation(WfActivationCompletion::empty(TEST_Q, activation.run_id))
1707
+ .await
1708
+ .unwrap();
1709
+ // Evict
1710
+ let activation = core.poll_workflow_activation(TEST_Q).await.unwrap();
1711
+ assert_matches!(
1712
+ activation.jobs.as_slice(),
1713
+ [WfActivationJob {
1714
+ variant: Some(wf_activation_job::Variant::RemoveFromCache(_)),
1715
+ },]
1716
+ );
1717
+ core.complete_workflow_activation(WfActivationCompletion::empty(TEST_Q, activation.run_id))
1718
+ .await
1719
+ .unwrap();
1720
+ assert_eq!(core.outstanding_wfts(TEST_Q), 0);
1721
+ assert_eq!(core.available_wft_permits(TEST_Q), 2);
1722
+ // When we loop back up, the poll will trigger a cache miss, which we should immediately
1723
+ // reply to WFT with failure, and then poll again, which will deliver the from-the-start
1724
+ // history
1725
+ }
1726
+ let activation = core.poll_workflow_activation(TEST_Q).await.unwrap();
1727
+ core.complete_workflow_activation(WfActivationCompletion::from_cmd(
1728
+ TEST_Q,
1729
+ activation.run_id,
1730
+ CompleteWorkflowExecution { result: None }.into(),
1731
+ ))
1732
+ .await
1733
+ .unwrap();
1734
+
1735
+ core.shutdown().await;
1736
+ }
@@ -342,6 +342,16 @@ impl TestHistoryBuilder {
342
342
  HistoryInfo::new_from_history(&self.events.clone().into(), None)
343
343
  }
344
344
 
345
+ pub(crate) fn get_one_wft(
346
+ &self,
347
+ from_wft_number: usize,
348
+ ) -> Result<HistoryInfo, HistoryInfoError> {
349
+ let mut histinfo =
350
+ HistoryInfo::new_from_history(&self.events.clone().into(), Some(from_wft_number))?;
351
+ histinfo.make_incremental();
352
+ Ok(histinfo)
353
+ }
354
+
345
355
  fn build_and_push_event(&mut self, event_type: EventType, attribs: Attributes) {
346
356
  self.current_event_id += 1;
347
357
  let evt = HistoryEvent {
@@ -100,6 +100,18 @@ impl HistoryInfo {
100
100
  unreachable!()
101
101
  }
102
102
 
103
+ /// Remove events from the beginning of this history such that it looks like what would've been
104
+ /// delivered on a sticky queue where the previously started task was the one before the last
105
+ /// task in this history.
106
+ pub(crate) fn make_incremental(&mut self) {
107
+ let last_complete_ix = self
108
+ .events
109
+ .iter()
110
+ .rposition(|he| he.event_type() == EventType::WorkflowTaskCompleted)
111
+ .expect("Must be a WFT completed event in history");
112
+ self.events.drain(0..=last_complete_ix);
113
+ }
114
+
103
115
  pub(crate) fn events(&self) -> &[HistoryEvent] {
104
116
  &self.events
105
117
  }
@@ -135,4 +147,11 @@ mod tests {
135
147
  let history_info = t.get_history_info(2).unwrap();
136
148
  assert_eq!(8, history_info.events.len());
137
149
  }
150
+
151
+ #[test]
152
+ fn incremental_works() {
153
+ let t = canned_histories::single_timer("timer1");
154
+ let hi = t.get_one_wft(2).unwrap();
155
+ dbg!(hi.events);
156
+ }
138
157
  }
@@ -53,6 +53,10 @@ pub static NO_MORE_WORK_ERROR_MSG: &str = "No more work to do";
53
53
  #[derive(derive_more::From, Debug, Clone, Copy, Eq, PartialEq, Hash)]
54
54
  pub enum ResponseType {
55
55
  ToTaskNum(usize),
56
+ /// Returns just the history after the WFT completed of the provided task number - 1, through to
57
+ /// the next WFT started. Simulating the incremental history for just the provided task number
58
+ #[from(ignore)]
59
+ OneTask(usize),
56
60
  AllHistory,
57
61
  }
58
62
 
@@ -495,6 +499,7 @@ pub fn hist_to_poll_resp(
495
499
  };
496
500
  let hist_info = match response_type {
497
501
  ResponseType::ToTaskNum(tn) => t.get_history_info(tn).unwrap(),
502
+ ResponseType::OneTask(tn) => t.get_one_wft(tn).unwrap(),
498
503
  ResponseType::AllHistory => t.get_full_history_info().unwrap(),
499
504
  };
500
505
  let batch = hist_info.events().to_vec();
@@ -488,6 +488,7 @@ impl Worker {
488
488
  }),
489
489
  )
490
490
  .await?;
491
+ self.return_workflow_task_permit();
491
492
  None
492
493
  }
493
494
  NewWfTaskOutcome::Evict(e) => {