Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
7ff1525
Storing changes commit
andystaples Nov 6, 2025
552a2dd
Working orchestrators + activities
andystaples Nov 21, 2025
af0e3c2
Nitpicks and cleanup
andystaples Nov 21, 2025
86ee081
Merge branch 'main' into andystaples/add-functions-support
andystaples Nov 21, 2025
3497148
Save-all nits
andystaples Nov 21, 2025
57de878
Add entity support (needs extension change)
andystaples Nov 24, 2025
18145f8
Refine entity support
andystaples Dec 3, 2025
9965ba4
Finish entity support
andystaples Dec 3, 2025
209443e
Fixes and improvements
andystaples Dec 4, 2025
cc005ae
Bump durabletask version, fix metadata
andystaples Dec 4, 2025
bf6d6f2
Use Protocol for stubs
andystaples Dec 5, 2025
0a03bd1
Merge branch 'main' into andystaples/add-functions-support
andystaples Dec 5, 2025
1176d03
Update to new workflow pattern
andystaples Dec 5, 2025
7bf763a
Rename stub file
andystaples Dec 5, 2025
811653e
Fix import
andystaples Dec 5, 2025
068cb43
Merge branch 'main' into andystaples/add-functions-support
andystaples Dec 5, 2025
827d201
Experimental dependency revision
andystaples Dec 5, 2025
fde02c5
Update to match changes in functions SDK
andystaples Dec 11, 2025
5b9644d
Merge branch 'main' into andystaples/add-functions-support
andystaples Dec 12, 2025
2df96dc
Merge issue fix
andystaples Dec 12, 2025
eac9efd
Various
andystaples Jan 6, 2026
20aacab
Add Functions to requirements
andystaples Jan 6, 2026
5df87b1
Rename to azure-functions-durable v2
andystaples Jan 30, 2026
ea5c2b0
Re-add Orchestrator object/model
andystaples Feb 9, 2026
2d5fd7a
Merge remote-tracking branch 'origin/main' into andystaples/add-funct…
andystaples Jun 23, 2026
0505a0d
Modernize pipelines for functions package
andystaples Jun 23, 2026
c9ea2fb
Cleanup pyright errors
andystaples Jun 23, 2026
5b906bd
Remove non-existent extension call
andystaples Jun 23, 2026
643e6ea
Merge remote-tracking branch 'origin/main' into andystaples/add-funct…
andystaples Jun 30, 2026
df9932d
Serialization compat, fix typing, working again
andystaples Jul 1, 2026
a7bdd01
Use the async client (match old behavior)
andystaples Jul 2, 2026
1891d94
Compat layer V1
andystaples Jul 2, 2026
d4a84bc
Reorganize compat files
andystaples Jul 2, 2026
a1b54bd
Add shims for old orchestration and entity call arg patterns
andystaples Jul 2, 2026
3c05264
Add remaining orchestration surface
andystaples Jul 2, 2026
46570e9
Add missing type coersion, rich client, tests
andystaples Jul 2, 2026
af18afe
Fix gaps found via integration tests
andystaples Jul 2, 2026
013f674
Fix old-name interceptor lookup
andystaples Jul 2, 2026
60b6195
More compat layer stuff
andystaples Jul 2, 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
67 changes: 67 additions & 0 deletions .github/workflows/durabletask-azurefunctions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Durable Task Scheduler SDK (azure-functions-durable)

on:
push:
branches:
- "main"
tags:
- "azurefunctions-v*" # Only run for tags starting with "azurefunctions-v"
pull_request:
branches:
- "main"

permissions:
contents: read

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.14
uses: actions/setup-python@v5
with:
python-version: 3.14
- name: Install dependencies
working-directory: azure-functions-durable
run: |
python -m pip install --upgrade pip
pip install setuptools wheel tox
pip install flake8
- name: Run flake8 Linter
working-directory: azure-functions-durable
run: flake8 .
- name: Run flake8 Linter
working-directory: tests/azure-functions-durable
run: flake8 .

run-tests:
strategy:
fail-fast: false
matrix:
python-version: ["3.13", "3.14"]
needs: lint
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install durabletask locally
run: |
python -m pip install --upgrade pip
pip install pytest
pip install . --force-reinstall

- name: Install azure-functions-durable locally
run: |
pip install ./azure-functions-durable --force-reinstall

- name: Run unit tests
working-directory: tests/azure-functions-durable
run: |
pytest -m "not dts and not azurite" --verbose
23 changes: 23 additions & 0 deletions .github/workflows/typecheck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ on:
tags:
- "v*"
- "azuremanaged-v*"
- "azurefunctions-v*"
pull_request:
branches:
- "main"
Expand Down Expand Up @@ -46,3 +47,25 @@ jobs:

- name: Run pyright (strict, Python 3.10)
run: pyright

pyright-azurefunctions:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Python 3.13 (lowest supported by azure-functions-durable)
uses: actions/setup-python@v5
with:
python-version: "3.13"

- name: Install packages and dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -e ".[azure-blob-payloads,opentelemetry]"
pip install -e ./azure-functions-durable
pip install pyright

- name: Run pyright (strict, Python 3.13)
run: pyright -p azure-functions-durable/pyrightconfig.json
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

ADDED

- Added a `result` property to `Task` as a convenience alias for `get_result()`.

FIXED

- `OrchestrationContext.create_timer` now accepts timezone-aware `datetime`
values, normalizing them to UTC instead of raising when compared against the
orchestration's internal clock.

## v1.7.0

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

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

### Fixed

- `durable_client_input` now injects a rich `DurableFunctionsClient` into the
decorated function's client parameter (the binding's JSON string is converted
to a client object). Previously the client parameter received the raw string.
- `DurableFunctionsClient` now applies the host-provided
`maxGrpcMessageSizeInBytes` to the gRPC channel's send/receive message limits
(when provided), allowing large orchestration payloads to be retrieved. When
the host does not supply a value, the gRPC library defaults are left in place.
- `DurableOrchestrationContext.current_utc_datetime` is now timezone-aware
(UTC), matching v1, so comparisons against timezone-aware datetimes (e.g. a
parsed scheduled-start time) no longer raise.
- `DurableOrchestrationStatus.to_json()` now emits orchestration payloads
(`output`, `input`, `customStatus`) as their raw JSON representation instead
of reconstructed Python objects, so the result is always JSON-serializable
even when payloads are custom types.
- Restored v1 members that were missing on the compatibility types, avoiding
`AttributeError`/`TypeError` for existing code that used them:
- `create_http_management_payload(...)` now returns a `dict`-based
`HttpManagementPayload`, so `json.dumps(payload)` works directly again.
- `RetryOptions.to_json()` returns the v1
`firstRetryIntervalInMilliseconds`/`maxNumberOfAttempts` dictionary, and the
`first_retry_interval_in_milliseconds` / `max_number_of_attempts` getters
remain available.
- `DurableOrchestrationStatus.from_json(...)` reconstructs a status from its
`to_json()` representation (or the equivalent v1 JSON schema).
- `PurgeHistoryResult.from_json(...)` reconstructs a result from its v1 JSON
representation.
- `DurableOrchestrationContext.version` returns the orchestration instance
version (or `None`).

### Added

- The `orchestration_trigger` decorator now accepts an `input_type` argument
(v1 parity). When set, a v1-style `context.get_input()` decodes the input to
that type; a call-site `expected_type` on `get_input` takes precedence.
- One-argument (Azure Functions / v1-style) entity functions
(``def entity(context):``) are now supported. The worker detects the entity's
shape and, for single-argument functions, delivers a functional
`DurableEntityContext` that wraps the durabletask `EntityContext` and exposes
the v1 entity API: `entity_name`, `entity_key`, `operation_name`,
`get_input()`, `get_state()` (with `initializer`), `set_state()`,
`set_result()`, and `destruct_on_exit()`. The operation result is taken from
`set_result(...)`, falling back to the function's return value.
durabletask-native two-argument entity functions and class-based
(`DurableEntity`) entities continue to work unchanged.
- One-argument (Azure Functions / v1-style) orchestrator functions
(``def orchestrator(context):``) are now supported. The worker detects the
orchestrator's arity and, for single-argument functions, delivers a
functional `DurableOrchestrationContext` that wraps the durabletask
`OrchestrationContext` and exposes the v1 context API: `get_input()`,
`call_activity`/`call_activity_with_retry`,
`call_sub_orchestrator`/`call_sub_orchestrator_with_retry`, `create_timer`,
`wait_for_external_event`, `continue_as_new`, `set_custom_status`,
`task_all`/`task_any`, `call_entity`/`signal_entity`, and `new_uuid`/`new_guid`.
Two-argument (durabletask-native) orchestrators continue to work unchanged.
`DurableOrchestrationContext.call_http` raises `NotImplementedError` pending a
durabletask durable-HTTP implementation.
- `DurableOrchestrationContext` also exposes `custom_status` (reflecting the
value set via `set_custom_status`) and `will_continue_as_new` (True once
`continue_as_new` has been called). `parent_instance_id`, `function_context`,
and `histories` raise `NotImplementedError` because durabletask does not
surface that information on the orchestration context.

- Backwards-compatible, deprecated aliases on `DurableFunctionsClient` for the
v1 `DurableOrchestrationClient` method names: `start_new`, `get_status`,
`get_status_all`, `get_status_by`, `raise_event`, `terminate`,
`purge_instance_history`, `purge_instance_history_by`, `suspend`, `resume`,
`restart`, `read_entity_state`, `get_client_response_links`, and
`wait_for_completion_or_create_check_status_response`. Each delegates to the
corresponding durabletask method and emits a `DeprecationWarning`; new code
should use the durabletask names (e.g. `schedule_new_orchestration`,
`get_orchestration_state`).
- `DurableFunctionsClient.signal_entity` now also accepts the v1
`operation_input` keyword (alias for `input`); `task_hub_name` and
`connection_name` are accepted for compatibility and ignored.
- `DurableFunctionsClient.rewind` is present as a deprecated stub that raises
`NotImplementedError`, pending a durabletask rewind implementation.
- Deprecated v1 compatibility aliases are now exported from
`azure.durable_functions`: `DurableOrchestrationClient` (alias for
`DurableFunctionsClient`), `DurableOrchestrationContext`, `DurableEntityContext`,
`EntityId`, `ManagedIdentityTokenSource`, `TokenSource`, `Entity`, and
`OrchestrationRuntimeStatus`.
- v1-compatible return-type wrappers `DurableOrchestrationStatus`,
`PurgeHistoryResult`, and `EntityStateResponse` (exported from
`azure.durable_functions`). The deprecated client methods now return these:
`get_status`/`get_status_all`/`get_status_by` return
`DurableOrchestrationStatus` (wrapping durabletask `OrchestrationState`, with
v1 attributes like `runtime_status`, `output`, `input_`, `custom_status`, and
a falsy value for missing instances); `purge_instance_history`/`_by` return
`PurgeHistoryResult` (with `instances_deleted`); and `read_entity_state`
returns `EntityStateResponse` (with `entity_exists`/`entity_state`).
- `DurableOrchestrationContext.call_http` is present as a stub that raises
`NotImplementedError`, documenting the durable-HTTP gap. `TokenSource` /
`ManagedIdentityTokenSource` remain constructible but only apply to
`call_http`, which is not yet supported.
- `RetryOptions`, a deprecated shim that maps the v1 millisecond-based
constructor onto durabletask `RetryPolicy` (which uses `timedelta`).
`RetryPolicy` is now also exported from `azure.durable_functions`.

### Changed

- `DurableFunctionsClient` is now an async client. Its orchestration and entity
management methods (e.g. `schedule_new_orchestration`, `get_orchestration_state`,
`wait_for_orchestration_completion`) are now coroutines and must be awaited.
This aligns the client with the async API surface of the V1
`DurableOrchestrationClient`.
- `create_http_management_payload` now accepts either the durabletask
`(request, instance_id)` signature or the v1 `(instance_id)` signature for
backwards compatibility.
- `HttpManagementPayload` now subclasses `dict`, so it is directly
JSON-serializable via `json.dumps(payload)` and supports mapping-style access
(`payload["statusQueryGetUri"]`, iteration, `in`, `keys()`/`items()`/`values()`)
so v1 code that treated the payload as a `dict` keeps working.

## v0.1.0

- Initial implementation
49 changes: 49 additions & 0 deletions azure-functions-durable/azure/durable_functions/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

# This module intentionally re-exports deprecated v1 compatibility aliases.
# pyright: reportDeprecated=false

from durabletask.task import RetryPolicy

from .decorators.durable_app import Blueprint, DFApp
from .client import DurableFunctionsClient
from .orchestrator import Orchestrator
from .internal.compat.retry_options import RetryOptions
from .internal.compat.orchestration_runtime_status import OrchestrationRuntimeStatus
from .internal.compat.durable_orchestration_status import DurableOrchestrationStatus
from .internal.compat.purge_history_result import PurgeHistoryResult
from .internal.compat.entity_state_response import EntityStateResponse
from .internal.compat.entity_id import EntityId
from .internal.compat.token_source import ManagedIdentityTokenSource, TokenSource
from .internal.compat.orchestration_context import DurableOrchestrationContext
from .internal.compat.entity_context import DurableEntityContext
from .internal.compat.compat_aliases import (
DurableOrchestrationClient,
Entity,
)

# IMPORTANT: DO NOT REMOVE. `azure-functions` relies on the presence and value of this variable
# for version detection
version = "2.x"

__all__ = [
"Blueprint",
"DFApp",
"DurableEntityContext",
"DurableFunctionsClient",
"DurableOrchestrationClient",
"DurableOrchestrationContext",
"DurableOrchestrationStatus",
"Entity",
"EntityId",
"EntityStateResponse",
"ManagedIdentityTokenSource",
"Orchestrator",
"OrchestrationRuntimeStatus",
"PurgeHistoryResult",
"RetryOptions",
"RetryPolicy",
"TokenSource",
"version",
]
Loading