@camunda8/orchestration-cluster-api 10.0.0-alpha.41 → 10.0.0-alpha.43
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/CHANGELOG.md +14 -0
- package/README.md +111 -2
- package/dist/{CamundaClient-HroU9acH.d.cts → CamundaClient-DwHGY8e9.d.cts} +75 -1
- package/dist/{CamundaClient-BlKXG8gE.d.ts → CamundaClient-Dxa-jdNc.d.ts} +75 -1
- package/dist/{chunk-267HUCFY.js → chunk-JKBNNUPT.js} +132 -5
- package/dist/chunk-JKBNNUPT.js.map +1 -0
- package/dist/{chunk-KQ4UL2WX.js → chunk-LXWPMQOS.js} +1 -1
- package/dist/chunk-LXWPMQOS.js.map +1 -0
- package/dist/effect/index.cjs +8 -3
- package/dist/effect/index.cjs.map +1 -1
- package/dist/effect/index.d.cts +1 -1
- package/dist/effect/index.d.ts +1 -1
- package/dist/effect/index.js +2 -2
- package/dist/index.cjs +132 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/logger.cjs.map +1 -1
- package/dist/logger.js +1 -1
- package/dist/threadWorkerEntry.cjs.map +1 -1
- package/dist/threadWorkerEntry.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-267HUCFY.js.map +0 -1
- package/dist/chunk-KQ4UL2WX.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [10.0.0-alpha.43](https://github.com/camunda/orchestration-cluster-api-js/compare/v10.0.0-alpha.42...v10.0.0-alpha.43) (2026-08-28)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* bind SDK cadence to the engine clock with createEngineClock ([#482](https://github.com/camunda/orchestration-cluster-api-js/issues/482)) ([8770212](https://github.com/camunda/orchestration-cluster-api-js/commit/8770212210097606b3400b8b98b6d2b452b1ff83)), closes [#450](https://github.com/camunda/orchestration-cluster-api-js/issues/450) [#450](https://github.com/camunda/orchestration-cluster-api-js/issues/450) [#467](https://github.com/camunda/orchestration-cluster-api-js/issues/467) [#474](https://github.com/camunda/orchestration-cluster-api-js/issues/474) [#476](https://github.com/camunda/orchestration-cluster-api-js/issues/476) [#477](https://github.com/camunda/orchestration-cluster-api-js/issues/477) [#479](https://github.com/camunda/orchestration-cluster-api-js/issues/479)
|
|
7
|
+
|
|
8
|
+
# [10.0.0-alpha.42](https://github.com/camunda/orchestration-cluster-api-js/compare/v10.0.0-alpha.41...v10.0.0-alpha.42) (2026-08-27)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* add createTestClock and a Clock contract conformance suite ([#479](https://github.com/camunda/orchestration-cluster-api-js/issues/479)) ([5beea42](https://github.com/camunda/orchestration-cluster-api-js/commit/5beea4241d27b01194960bda3555874ec0258bef)), closes [#477](https://github.com/camunda/orchestration-cluster-api-js/issues/477) [#476](https://github.com/camunda/orchestration-cluster-api-js/issues/476) [#451](https://github.com/camunda/orchestration-cluster-api-js/issues/451) [#476](https://github.com/camunda/orchestration-cluster-api-js/issues/476) [#474](https://github.com/camunda/orchestration-cluster-api-js/issues/474)
|
|
14
|
+
|
|
1
15
|
# [10.0.0-alpha.41](https://github.com/camunda/orchestration-cluster-api-js/compare/v10.0.0-alpha.40...v10.0.0-alpha.41) (2026-08-27)
|
|
2
16
|
|
|
3
17
|
|
package/README.md
CHANGED
|
@@ -766,6 +766,111 @@ return ack;
|
|
|
766
766
|
const ack2 = await job.ignore();
|
|
767
767
|
```
|
|
768
768
|
|
|
769
|
+
### Deterministic Time (`job.clock`)
|
|
770
|
+
|
|
771
|
+
The SDK resolves its own cadence — worker poll intervals, retry backoff, eventual-consistency
|
|
772
|
+
polling, backpressure decay — through an injectable clock. Pinning that clock runs all of it
|
|
773
|
+
on virtual time, so tests that would otherwise wait out a 30-second poll finish immediately.
|
|
774
|
+
|
|
775
|
+
The clock is configured on the client and available as `client.clock`. Handlers reach it as
|
|
776
|
+
`job.clock`, a narrowed view exposing only `now()` and `sleep(ms, signal?)` — `deadline` is
|
|
777
|
+
withheld because a handler that built one against a pinned clock would hang rather than time
|
|
778
|
+
out:
|
|
779
|
+
|
|
780
|
+
<!-- snippet-source: examples/readme.ts | regions: ReadmeHandlerClock -->
|
|
781
|
+
|
|
782
|
+
```ts
|
|
783
|
+
const startedAt = job.clock.now();
|
|
784
|
+
|
|
785
|
+
// A short back-off around a flaky dependency. Waiting here rather than on
|
|
786
|
+
// setTimeout means a test that pins the client's clock also drives the handler.
|
|
787
|
+
await job.clock.sleep(250);
|
|
788
|
+
|
|
789
|
+
return job.complete({ variables: { waitedMs: job.clock.now() - startedAt } });
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
Read and wait through `job.clock` rather than `Date.now()` / `setTimeout`, and a test that
|
|
793
|
+
pins the client's clock drives your handler too.
|
|
794
|
+
|
|
795
|
+
`job.clock.sleep` is for **short in-handler coordination** — spacing retries within one job,
|
|
796
|
+
backing off around a flaky dependency. Long or business-meaningful waits belong in the
|
|
797
|
+
process as BPMN timers, where they survive a crash and are visible to operations.
|
|
798
|
+
|
|
799
|
+
Pass `createTestClock()` to pin the clock in your own tests:
|
|
800
|
+
|
|
801
|
+
<!-- snippet-source: examples/readme.ts | regions: ReadmeTestClock -->
|
|
802
|
+
|
|
803
|
+
```ts
|
|
804
|
+
// Pin the client's clock and the SDK's own cadence runs on virtual time: poll intervals,
|
|
805
|
+
// retry backoff and backpressure decay all settle without waiting in real time.
|
|
806
|
+
const clock = createTestClock({ start: 0, autoAdvance: false });
|
|
807
|
+
const client = createCamundaClient({ clock });
|
|
808
|
+
|
|
809
|
+
// Nothing settles until the test moves time, so start the wait and advance into it.
|
|
810
|
+
const waiting = client.clock.sleep(30_000);
|
|
811
|
+
await clock.advance(30_000);
|
|
812
|
+
await waiting;
|
|
813
|
+
|
|
814
|
+
console.log(client.clock.now()); // 30000
|
|
815
|
+
console.log(clock.sleeps); // [30000] — every duration the SDK asked to wait
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
`autoAdvance` defaults to `true`, where each sleep settles itself on the next macrotask
|
|
819
|
+
having moved time to its wake point — the SDK's loops make progress without the test driving
|
|
820
|
+
them. Set it to `false`, as above, when you need to assert on state *between* two waits.
|
|
821
|
+
|
|
822
|
+
#### Binding the SDK to the engine clock
|
|
823
|
+
|
|
824
|
+
`createTestClock` pins the SDK in isolation: the engine carries on at real time. When you are
|
|
825
|
+
testing against a live engine, `createEngineClock` binds the two together so they advance as
|
|
826
|
+
one — `sleep` moves engine time forward via `PUT /clock` instead of waiting:
|
|
827
|
+
|
|
828
|
+
<!-- snippet-source: examples/readme.ts | regions: ReadmeEngineClock -->
|
|
829
|
+
|
|
830
|
+
```ts
|
|
831
|
+
// Bind the SDK's cadence to the engine's own clock. `sleep` no longer waits — it moves
|
|
832
|
+
// engine time forward — so a worker polling for something that never arrives advances the
|
|
833
|
+
// engine instead of burning real seconds.
|
|
834
|
+
//
|
|
835
|
+
// Two clients, deliberately. `client` issues the pins and must stay on the live clock:
|
|
836
|
+
// HTTP retry sleeps on whatever clock its client was given, so pointing the engine clock
|
|
837
|
+
// at its own driver would have a failed pin back off through `sleep`, which issues another
|
|
838
|
+
// pin, and so on.
|
|
839
|
+
const client = createCamundaClient();
|
|
840
|
+
const clock = createEngineClock(client, { start: Date.now() });
|
|
841
|
+
const pinned = createCamundaClient({ clock });
|
|
842
|
+
|
|
843
|
+
await clock.pin(Date.now());
|
|
844
|
+
try {
|
|
845
|
+
// A minute of engine time. BPMN timers due inside it fire; the test does not wait.
|
|
846
|
+
await pinned.clock.sleep(60_000);
|
|
847
|
+
} finally {
|
|
848
|
+
await clock.reset(); // hand the engine back to real time
|
|
849
|
+
}
|
|
850
|
+
```
|
|
851
|
+
|
|
852
|
+
This is what makes a worker loop deterministic end to end: the poll interval *drives* engine
|
|
853
|
+
time rather than racing it, so a test that would spend a real minute waiting on something
|
|
854
|
+
that never becomes ready finishes as fast as the requests complete.
|
|
855
|
+
|
|
856
|
+
> [!WARNING]
|
|
857
|
+
> Pinning is global to the cluster. Only point an engine clock at an engine you own —
|
|
858
|
+
> never a shared environment. Always `reset()` in a `finally`.
|
|
859
|
+
|
|
860
|
+
> [!IMPORTANT]
|
|
861
|
+
> The client you hand to `createEngineClock` must not itself be configured with that clock.
|
|
862
|
+
> HTTP retry backs off on whatever clock its client was given, so a self-referential setup
|
|
863
|
+
> would have a failed `pinClock` retry through `sleep`, which issues another `pinClock`.
|
|
864
|
+
> Keep the driving client on the live clock, as in the example above.
|
|
865
|
+
|
|
866
|
+
Prefer `createTestClock` over hand-writing a `Clock`. The contract has clauses that are easy
|
|
867
|
+
to get subtly wrong — most notably that `sleep` must not settle in a microtask, because the
|
|
868
|
+
worker schedules its next poll on resolution and would otherwise spin.
|
|
869
|
+
|
|
870
|
+
Two things deliberately stay on real time even when the clock is pinned, so that pinning it
|
|
871
|
+
cannot hang a process: **liveness bounds** (shutdown drain, request and config-fetch
|
|
872
|
+
timeouts) and **observational timestamps** (log, telemetry and support-bundle records).
|
|
873
|
+
|
|
769
874
|
### Job Corrections (User Task Listeners)
|
|
770
875
|
|
|
771
876
|
When a job worker handles a [user task listener](https://docs.camunda.io/docs/components/concepts/user-task-listeners/), it can correct task properties (assignee, due date, candidate groups, etc.) by passing a `result` to `job.complete()`:
|
|
@@ -1330,7 +1435,9 @@ Exports available from `.../effect`:
|
|
|
1330
1435
|
(`pages()` / `items()` → `Stream`, `toArray()` → `Effect`). See below.
|
|
1331
1436
|
|
|
1332
1437
|
**Clock-class win:** `eventually` / `withTimeout` run on the Effect `Clock`, so `TestClock.adjust`
|
|
1333
|
-
advances eventual/timeout deterministically in tests — no real-clock burn.
|
|
1438
|
+
advances eventual/timeout deterministically in tests — no real-clock burn. The Promise surface
|
|
1439
|
+
has the same property via [`createTestClock`](#deterministic-time-jobclock); the difference is
|
|
1440
|
+
that Effect gives you `TestClock` and the rest of the ecosystem for free.
|
|
1334
1441
|
|
|
1335
1442
|
### Paginated Search as a `Stream`
|
|
1336
1443
|
|
|
@@ -1441,7 +1548,9 @@ Worker exports from `.../effect`:
|
|
|
1441
1548
|
|
|
1442
1549
|
**Clock-class win:** the activation poll interval and the handler-retry `Schedule` run on the Effect
|
|
1443
1550
|
`Clock`, so `TestClock.adjust` bounds activation/retry timing in virtual time — the whole loop is
|
|
1444
|
-
deterministic in tests, with no real-clock burn.
|
|
1551
|
+
deterministic in tests, with no real-clock burn. The Promise worker is equally drivable by pinning
|
|
1552
|
+
the client clock (see [Deterministic Time](#deterministic-time-jobclock)); what Effect adds here is
|
|
1553
|
+
`Schedule` composition over the retry policy.
|
|
1445
1554
|
|
|
1446
1555
|
### Injecting Services into a Handler
|
|
1447
1556
|
|