Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ Task<T> — 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
```

Expand All @@ -123,11 +123,15 @@ Task<T> — 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.

---

Expand Down
28 changes: 23 additions & 5 deletions packages/azure-functions-durable/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Loading