diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index c8c1501..2e17755 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -113,7 +113,7 @@ Task — Base: result, exception, isComplete, isFailed, parent r │ ├── RetryableTask — Policy-driven retries (exponential backoff) │ └── RetryHandlerTask — Custom retry handler function └── CompositeTask — Holds children with parent backlinks - ├── WhenAllTask — Completes when ALL children done; fails fast on first failure + ├── WhenAllTask — Completes when ALL children are terminal (waits for every child) └── WhenAnyTask — Completes when ANY child done ``` @@ -123,11 +123,15 @@ Task — Base: result, exception, isComplete, isFailed, parent r **Important:** `CompositeTask` checks already-complete children in its constructor. A composite task can be **immediately complete upon construction** — callers must handle this. -### WhenAll Fail-Fast Behavior +### WhenAll Wait-All Behavior -`WhenAllTask` marks itself complete on the **first** failed child. Other children may still -be in flight. The `isComplete` guard prevents double-completion, but the mental model is: -one failure = whole task fails immediately, remaining results ignored. +`WhenAllTask` completes only when **every** child is terminal (`_completedTasks == _tasks.length`) — +a failing child does **not** complete it early. This prevents a later failing sibling's `TaskFailed` +from being dropped against an already-terminal instance (issue #301). `_exception` is set only at +completion, so `isFailed` and `isComplete` flip together — otherwise `resume()` (which checks +`isFailed` before `isComplete`) would throw into the generator before the other siblings finish, +re-introducing fail-fast. On failure, all child exceptions are aggregated into an `AggregateError` +whose message inlines each child message. --- diff --git a/packages/azure-functions-durable/README.md b/packages/azure-functions-durable/README.md index 3d642a0..801cf01 100644 --- a/packages/azure-functions-durable/README.md +++ b/packages/azure-functions-durable/README.md @@ -40,10 +40,13 @@ changed: **`client.startNew()` supports the `version` option.** - **Entity locking / critical sections moved to the core context.** v3's `context.df.lock(...)` / `context.df.isLocked()` and the `DurableLock` / `LockState` / `LockingRulesViolationError` exports - are removed. Acquire locks with the core `context.entities.lockEntities(...entityIds)` (returns a - `LockHandle` — call `release()`, ideally in a `finally`) and query with - `context.entities.isInCriticalSection()`. Restoring the v3 `df.lock` / `isLocked` surface is tracked - in [#317](https://github.com/microsoft/durabletask-js/issues/317). + are removed. Locks live on the core-native `context.entities` surface, which the classic + `{ df, log }` context does **not** expose — an orchestrator that needs locks must first migrate to + the core-native orchestrator/context shape, then acquire locks with + `context.entities.lockEntities(...entityIds)` (returns a `LockHandle` — call `release()`, ideally + in a `finally`) and query with `context.entities.isInCriticalSection()`. Reintroducing the v3 + `df.lock` / `isLocked` surface is **not supported and not planned** + ([#317](https://github.com/microsoft/durabletask-js/issues/317), closed as not planned). - **`context.df.callHttp(...)` is restored** as a worker-side durable HTTP call ([#318](https://github.com/microsoft/durabletask-js/issues/318)) — though **not** as a drop-in, fully v3-equivalent replacement: the known incompatibilities and behavior differences listed below are @@ -106,6 +109,19 @@ changed: sync **generators** (`function*`) using `context.df.*` — are unaffected; convert any non-generator classic orchestrator to generator form, or to the core-native `ctx.*` API. +## Requirements + +This provider reaches the Durable Task backend over the Functions host's **gRPC** channel, which +exists only in newer durable-extension builds. Your app's `host.json` must reference one of: + +- GA bundle — `Microsoft.Azure.Functions.ExtensionBundle` at **`[4.36.0, 5.0.0)`**, or +- Preview bundle — `Microsoft.Azure.Functions.ExtensionBundle.Preview` at **`[4.29.0, 5.0.0)`**. + +Earlier GA v4 bundles (**<= 4.32.0**) predate that gRPC endpoint, so orchestration starters **hang +for ~60 seconds and time out with no error**. A fresh app on the default GA range (`[4.*, 5.0.0)`) +resolves to the latest GA (>= 4.36.0) and works — the trap is an **explicit** pin at or below +4.32.0. + ## Getting started ```typescript @@ -170,4 +186,6 @@ are `@deprecated`): ## Status -This package is an early preview (`4.0.0`); APIs may change before the stable release. +This rewritten `durable-functions` v4 provider is in **preview**, published under the `preview` npm +dist-tag — install it with `npm install durable-functions@preview`. APIs may change before the +GA `4.0.0` release.