Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
57b48be
Add Functions gRPC core helpers
YunchuWang Jun 29, 2026
c272a55
Add raw Functions gRPC worker processors
YunchuWang Jun 29, 2026
fb3a55b
Remove extra client task hub shortcut
YunchuWang Jun 29, 2026
fe7c594
Align Functions gRPC support with Python and drop extra surface
YunchuWang Jun 30, 2026
f54138d
Add Azure Functions Durable workspace package
YunchuWang Jul 1, 2026
93f5122
Rename Azure Functions Durable package folder
YunchuWang Jul 1, 2026
9ca4fce
Remove unused requiredQueryStringParameters param from metadata gener…
YunchuWang Jul 1, 2026
ff3ab8f
Add trigger registration with durableRequiresGrpc opt-in and getClien…
YunchuWang Jul 7, 2026
4d26c6b
Add classic (v3) backward-compat layer, v3 client query APIs, and rel…
YunchuWang Jul 7, 2026
91ba76b
Simplify azure-functions-durable tsconfig.build.json
YunchuWang Jul 7, 2026
11a042d
Enhance createHttpManagementPayload to support classic v3 single-argu…
YunchuWang Jul 8, 2026
b98583a
Add classic (v3) lifecycle aliases and purgeInstanceHistoryBy method …
YunchuWang Jul 8, 2026
4ca9a62
Merge branch 'yunchuwang/functions-grpc-support' of https://github.co…
YunchuWang Jul 8, 2026
8d863de
Add classic (v3) entity support and custom status handling in Durable…
YunchuWang Jul 8, 2026
708a950
Add deprecated alias getClientResponseLinks for createHttpManagementP…
YunchuWang Jul 8, 2026
00d705e
Simplify Azure Functions Durable CHANGELOG and README per review
YunchuWang Jul 8, 2026
073bf25
Export v3-compatible ActivityHandler/OrchestrationHandler/Orchestrati…
YunchuWang Jul 8, 2026
cd2b6ff
Fix wrapOrchestrator to drive classic v3 orchestrators via async gene…
YunchuWang Jul 9, 2026
bfc4e3b
Add EntityContext/EntityHandler/DurableClient aliases and replay-safe…
YunchuWang Jul 9, 2026
701cd13
Fix purgeInstanceHistoryBy to accept an OrchestrationFilter object (v…
YunchuWang Jul 9, 2026
834d347
Extract named OrchestrationFilter type and reuse in getStatusBy/purge…
YunchuWang Jul 9, 2026
c7114a9
fix(functions): wire compat rewind() to core rewindInstance() + guard…
Jul 13, 2026
e4fd451
Merge origin/main into functions-grpc-support
YunchuWang Jul 14, 2026
f935bce
Address PR #282 review: arity fix, parseJson, exports, docs, node bump
YunchuWang Jul 14, 2026
8f62a35
Refine PR #282 review items 1-5: arity detection, getStatus v3 parity…
YunchuWang Jul 14, 2026
900064f
Refine getStatus/startNew v3 parity (review item 5)
YunchuWang Jul 14, 2026
0dcc47c
Align getStatus not-found message with v3 wording (review item 5)
YunchuWang Jul 14, 2026
fa2a17c
Correct inaccurate abandon comment re: Python provider
YunchuWang Jul 15, 2026
cc420b8
Make abandon comment self-contained (drop Python reference)
YunchuWang Jul 15, 2026
132dea1
feat(durable-functions): add app.client.* durable client function hel…
YunchuWang Jul 15, 2026
868f3ef
docs(durable-functions): document v3-compatible client method aliases
YunchuWang Jul 15, 2026
940b4a0
Merge remote-tracking branch 'origin/main' into yunchuwang/functions-…
YunchuWang Jul 17, 2026
2982f34
ci(functions-e2e): run on pull_request + build in-repo packages
YunchuWang Jul 17, 2026
f29aa1e
fix(durable-functions): thread entity state type through EntityContex…
YunchuWang Jul 17, 2026
5f05061
test(functions-e2e): point test-app at in-repo durable-functions v4 SDK
YunchuWang Jul 17, 2026
273868c
ci(functions-e2e): target preview extension bundle for gRPC path + sk…
YunchuWang Jul 17, 2026
f8fec89
ci(functions-e2e): keep suite on workflow_dispatch while error-fideli…
YunchuWang Jul 17, 2026
92d0d54
ci(functions-e2e): run suite on pull_request for the Functions surface
YunchuWang Jul 17, 2026
c13cb60
fix(functions-compat): map opaque gRPC control-plane errors to v3 sur…
YunchuWang Jul 17, 2026
a347d18
test(functions-e2e): skip terminal-instance control-plane ops pending…
YunchuWang Jul 17, 2026
c6c9ddf
test(functions-e2e): align expected error strings with v4 gRPC-core f…
YunchuWang Jul 17, 2026
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
55 changes: 37 additions & 18 deletions .github/workflows/functions-e2e-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,31 @@ name: 🧪 Functions Host E2E Tests
# test/e2e-functions/test-app (backed by Azurite / AzureStorage) and drives the
# app over HTTP, porting the extension repo's `BasicNode` app + xUnit tests.
#
# The test-app depends on the PUBLISHED `durable-functions` + `@azure/functions`
# packages, so it installs and runs without any in-repo package build. The suite
# self-gates: each spec SKIPS cleanly when the Azure Functions Core Tools (`func`)
# or the Azurite storage emulator are unavailable, and RUNS when both are present.
# In CI below we install and start both, so the suite runs for real; the self-skip
# is the safety net that keeps the job green if a prerequisite fails to come up.
# The test-app consumes the IN-REPO `durable-functions` (compat) package and core
# `@microsoft/durabletask-js` via `file:` links, so those packages must be BUILT
# before the test-app install (see the build step below). The suite self-gates:
# each spec SKIPS cleanly when the Azure Functions Core Tools (`func`) or the
# Azurite storage emulator are unavailable, and RUNS when both are present. In CI
# below we install and start both, so the suite runs for real; the self-skip is
# the safety net that keeps the job green if a prerequisite fails to come up.
#
# Triggering: this suite is run ad hoc (manual dispatch) for now while it beds in,
# so it does not gate day-to-day PRs. Start it from the Actions tab via "Run
# workflow" (workflow_dispatch). To re-enable automatic runs on pull requests
# later, add a `pull_request` trigger scoped to `test/e2e-functions/**` and this
# workflow file. NOTE: workflow_dispatch only appears in the Actions UI once this
# file exists on the repository's default branch.
# Triggering: this suite runs automatically on pull requests that touch the
# Functions surface (`test/e2e-functions/**`, `packages/azure-functions-durable/**`,
# or this workflow file), and can also be started ad hoc from the Actions tab via
# "Run workflow" (workflow_dispatch). It is intentionally scoped to the Functions
# surface and does NOT gate core-only PRs, which have their own suites. A small set
# of terminal/invalid-state control-plane specs are skipped pending a server-side
# gRPC status-detail fix (tracked separately); everything else runs for real. NOTE:
# workflow_dispatch only appears in the Actions UI once this file exists on the
# repository's default branch.

on:
workflow_dispatch:
pull_request:
paths:
- "test/e2e-functions/**"
- "packages/azure-functions-durable/**"
- ".github/workflows/functions-e2e-tests.yaml"

permissions:
contents: read
Expand All @@ -43,19 +52,28 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: "https://registry.npmjs.org"

# Root install provides jest + ts-jest used to run the spec files. The specs
# do not depend on the core durabletask-js packages, so no workspace build is
# required here.
# Root install provides jest + ts-jest used to run the spec files, and lets
# the workspace build below resolve the in-repo packages the test-app links
# via `file:` refs.
- name: ⚙️ Install dependencies
run: npm ci

# Build the in-repo compat package (`durable-functions`); its build script
# runs `build:core` first, so this also builds `packages/durabletask-js` into
# dist/. Both must exist before the test-app's `file:`-linked install below.
- name: "🏗️ Build in-repo durable-functions (+ core) for file: linking"
run: npm run build -w durable-functions

- name: 🔧 Install Azurite and Azure Functions Core Tools
run: npm install -g azurite azure-functions-core-tools@4

# --skipApiVersionCheck: the preview extension bundle's Azure Storage SDK
# targets a newer REST API version than current Azurite accepts; without the
# flag Azurite rejects the calls and every orchestration times out.
- name: 🗄️ Start Azurite
run: |
mkdir -p /tmp/azurite
azurite --silent --location /tmp/azurite \
azurite --silent --skipApiVersionCheck --location /tmp/azurite \
--blobPort 10000 --queuePort 10001 --tablePort 10002 &
echo "Waiting for Azurite blob endpoint..."
for i in $(seq 1 30); do
Expand All @@ -66,8 +84,9 @@ jobs:
sleep 1
done

# Installs the PUBLISHED durable-functions / @azure/functions packages and
# compiles the ported BasicNode app to dist/ (consumed by `func start`).
# Installs the in-repo `durable-functions` (+ core `@microsoft/durabletask-js`)
# packages via the test-app's `file:` refs and compiles the ported BasicNode
# app to dist/ (consumed by `func start`).
- name: 📦 Install + build test-app
working-directory: test/e2e-functions/test-app
run: |
Expand Down
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,23 @@

This repo contains a JavaScript/TypeScript SDK for use with the [Azure Durable Task Scheduler](https://github.com/Azure/Durable-Task-Scheduler). With this SDK, you can define, schedule, and manage durable orchestrations using ordinary TypeScript/JavaScript code.

> Note that this SDK is **not** currently compatible with [Azure Durable Functions](https://learn.microsoft.com/azure/azure-functions/durable/durable-functions-overview). If you are looking for a JavaScript SDK for Azure Durable Functions, please see [this repo](https://github.com/Azure/azure-functions-durable-js).
> Note that this SDK does **not** provide the [Azure Durable Functions](https://learn.microsoft.com/azure/azure-functions/durable/durable-functions-overview) programming model, decorators, or worker-indexing metadata. If you are looking for a JavaScript SDK for Azure Durable Functions, please see [this repo](https://github.com/Azure/azure-functions-durable-js). This package exposes low-level TaskHubSidecarService gRPC/protobuf helpers that host integrations can reuse; those helpers follow this package's Node.js 22+ requirement.

## Low-level host integration APIs

Host integrations that already own trigger metadata and transport encoding can depend on the `@microsoft/durabletask-js` package directly. `TaskHubGrpcWorker` registers orchestrators, activities, and entities, and can process raw TaskHubSidecarService protobuf payloads without starting the long-running gRPC worker loop:

```typescript
const worker = new TaskHubGrpcWorker();
worker.addOrchestrator(myOrchestrator);
worker.addActivity(myActivity);
worker.addEntity(myEntity);

const orchestrationResponseBytes = await worker.processOrchestratorRequest(orchestrationRequestBytes);
const entityResponseBytes = await worker.processEntityBatchRequest(entityBatchRequestBytes);
```

`TaskHubGrpcClient` already exposes orchestration start/query/event/terminate/suspend/resume/purge APIs and entity signal/read/query/clean APIs through its existing `hostAddress` and `metadataGenerator` options. Host integrations that need task-hub routing metadata should provide it through `metadataGenerator`, keeping host-specific metadata policy outside the core client. Azure-managed scheduler connection strings remain in `@microsoft/durabletask-js-azuremanaged`.

## npm packages

Expand Down
31 changes: 31 additions & 0 deletions eng/ci/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,34 @@ extends:
serviceendpointurl: 'https://api.esrp.microsoft.com'
mainpublisher: 'durabletask-java'
domaintenantid: '33e01921-4d64-4f8c-a055-5bdaffd5e33d'

- job: durable_functions
displayName: 'Release durable-functions'
templateContext:
type: releaseJob
isProduction: true
inputs:
- input: pipelineArtifact
pipeline: DurableTaskJSBuildPipeline
artifactName: drop
targetPath: $(System.DefaultWorkingDirectory)/drop

steps:
- task: SFP.release-tasks.custom-build-release-task.EsrpRelease@9
displayName: 'ESRP Release durable-functions'
inputs:
connectedservicename: 'dtfx-internal-esrp-prod'
usemanagedidentity: true
keyvaultname: 'durable-esrp-akv'
signcertname: 'dts-esrp-cert'
clientid: '0b3ed1a4-0727-4a50-b82a-02c2bd9dec89'
intent: 'PackageDistribution'
contenttype: 'npm'
contentsource: 'Folder'
folderlocation: '$(System.DefaultWorkingDirectory)/drop/buildoutputs/azure-functions-durable'
waitforreleasecompletion: true
owners: 'wangbill@microsoft.com'
approvers: 'kaibocai@microsoft.com'
serviceendpointurl: 'https://api.esrp.microsoft.com'
mainpublisher: 'durabletask-java'
domaintenantid: '33e01921-4d64-4f8c-a055-5bdaffd5e33d'
14 changes: 13 additions & 1 deletion eng/templates/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ jobs:
npm pack
displayName: "pack @microsoft/durabletask-js-azuremanaged"

# Pack durable-functions
- script: |
cd packages/azure-functions-durable
npm pack
displayName: "pack durable-functions"

# Copy each package to its own staging subfolder
- task: CopyFiles@2
displayName: "Copy durabletask-js to staging"
Expand All @@ -56,4 +62,10 @@ jobs:
inputs:
SourceFolder: $(System.DefaultWorkingDirectory)/packages/durabletask-js-azuremanaged
Contents: "*.tgz"
TargetFolder: $(Build.ArtifactStagingDirectory)/buildoutputs/durabletask-js-azuremanaged
TargetFolder: $(Build.ArtifactStagingDirectory)/buildoutputs/durabletask-js-azuremanaged
- task: CopyFiles@2
displayName: "Copy azure-functions-durable to staging"
inputs:
SourceFolder: $(System.DefaultWorkingDirectory)/packages/azure-functions-durable
Contents: "*.tgz"
TargetFolder: $(Build.ArtifactStagingDirectory)/buildoutputs/azure-functions-durable
72 changes: 72 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

49 changes: 49 additions & 0 deletions packages/azure-functions-durable/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Changelog

## 0.4.0

Initial gRPC-consolidated Azure Functions Durable provider, built on `@microsoft/durabletask-js`.

### Added

- `app.client.*` durable client function registration helpers (`http`, `timer`, `storageBlob`,
`storageQueue`, `serviceBusQueue`, `serviceBusTopic`, `eventHub`, `eventGrid`, `cosmosDB`,
`generic`), restoring v3 parity. Each registers a normal trigger and injects a
`DurableFunctionsClient` as the handler's second argument, so the client-starter signature
`(trigger, client, context)` works without manually wiring
`extraInputs: [df.input.durableClient()]` + `df.getClient(context)`.

### Requirements

- Node.js >= 22 (drops the Node 18/20 that `durable-functions` v3 supported).

### Breaking changes vs `durable-functions` v3

- Classic orchestration and entity contexts no longer extend `InvocationContext`; they expose only
`df` plus replay-safe log helpers (no `invocationId` / `functionName` / `extraInputs`), and the
classic entity context exposes only `{ df }`. Rationale: reading `InvocationContext` members such as
`invocationId` / `extraInputs` inside an orchestrator is replay-nondeterministic and was never
recommended, so they are intentionally not surfaced. The classic entity context stays generic over
its state type (`EntityContext<TState>`), so a bare `context.df.getState()` returns `TState | undefined`
as in v3; the per-call `getState<T>()` generic still overrides it.
- Task result shape follows the core SDK: use `isComplete` / `isFailed` / `getResult()` (v3 used
`isCompleted` / `isFaulted` / `result`). `context.df.createTimer(...)` returns a cancelable
`TimerTask`, so the timeout-race pattern (`Task.any` then `timer.cancel()`) keeps working.
- `client.getStatus()` matches the v3 signature: it returns a non-optional `DurableOrchestrationStatus`
and throws when the instance does not exist. `showInput` suppresses only the top-level input (output
and custom status are always returned, as in v3); `showHistory` populates `history`, and
`showHistoryOutput` toggles whether those entries keep their input/result payloads. One
consolidated-path note: `history` entries are core `HistoryEvent`s (v3 types `history` as
`Array<unknown>`), not the classic .NET extension's history serialization.
- `client.startNew()` supports the v3 `version` option (forwarded to the core scheduler).
- Removed top-level exports: `DummyOrchestrationContext`, `DummyEntityContext`, `DurableError`,
`AggregatedError`, `ManagedIdentityTokenSource`, `TokenSource`. `TaskFailedError` is re-exported
from the core SDK and aggregate failures surface as JS-native `AggregateError`. For orchestration
unit tests, use the core `TestOrchestrationWorker` / `TestOrchestrationClient` in place of the v3
dummy contexts.

### Release order

- Publish `@microsoft/durabletask-js` (0.3.0) before this package.
- Confirm the target `@azure/functions` (^4.16.1) build includes the Durable extension changes
(`DurableRequiresGrpc`) required by the consolidated gRPC path.
21 changes: 21 additions & 0 deletions packages/azure-functions-durable/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) Microsoft Corporation.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Loading
Loading