|
| 1 | +# Changelog |
| 2 | + |
| 3 | +All notable changes to this project will be documented in this file. |
| 4 | + |
| 5 | +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), |
| 6 | +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). |
| 7 | + |
| 8 | +## 2.0.0b1 |
| 9 | + |
| 10 | +First preview (beta) release of `azure-functions-durable` 2.x — a ground-up |
| 11 | +rewrite of the Azure Durable Functions Python SDK built on top of the |
| 12 | +[`durabletask`](https://pypi.org/project/durabletask/) SDK. This is a preview |
| 13 | +release; APIs may change before the stable 2.0.0. |
| 14 | + |
| 15 | +### Why the rewrite |
| 16 | + |
| 17 | +The 1.x SDK implemented the Durable Functions out-of-process programming model |
| 18 | +directly, with its own orchestration action/state model and a JSON protocol |
| 19 | +tailored to the classic Durable Functions host extension. 2.x instead builds on |
| 20 | +the `durabletask` Python SDK — the same gRPC-based runtime that powers the |
| 21 | +Durable Task Scheduler (DTS) and the modern Durable Functions host. Building on |
| 22 | +durabletask means: |
| 23 | + |
| 24 | +- a single orchestration/entity execution core, serialization pipeline, and |
| 25 | + retry/versioning implementation shared with the broader durabletask |
| 26 | + ecosystem, instead of a Functions-specific reimplementation; |
| 27 | +- Functions users can adopt durabletask-native APIs and patterns directly, |
| 28 | + while existing v1 code keeps working through the compatibility layer; and |
| 29 | +- less protocol drift between the Python worker and the durable backend. |
| 30 | + |
| 31 | +### Underlying packages |
| 32 | + |
| 33 | +- [`durabletask`](https://pypi.org/project/durabletask/) — orchestration and |
| 34 | + entity client/worker, executed over gRPC. |
| 35 | +- [`azure-functions`](https://pypi.org/project/azure-functions/) — the |
| 36 | + decorator/binding programming model (`DFApp` / `Blueprint`). |
| 37 | +- [`azure-identity`](https://pypi.org/project/azure-identity/) — Managed |
| 38 | + Identity token acquisition for durable HTTP calls. |
| 39 | + |
| 40 | +### Breaking changes (from `azure-functions-durable` 1.x) |
| 41 | + |
| 42 | +- **Python 3.13+ is now required** (1.x supported 3.10+). On Functions Python |
| 43 | + workers older than 3.13, worker dependencies are not isolated from your app's |
| 44 | + dependencies, which causes a `grpc` version conflict with the durable runtime |
| 45 | + at load time. Python 3.13 enables worker dependency isolation, avoiding the |
| 46 | + collision. |
| 47 | +- **The classic (v1) programming model has been dropped.** Only the |
| 48 | + decorator-based application model (`DFApp` / `Blueprint`, the Python v2 |
| 49 | + programming model) is supported; the `function.json`-based model is not. |
| 50 | +- **The OpenAI Agents integration has been removed.** The |
| 51 | + `azure.durable_functions.openai_agents` package (durable OpenAI Agents SDK |
| 52 | + orchestration) is not part of 2.x. |
| 53 | +- **Runtime target.** 2.x speaks the durabletask gRPC protocol used by the |
| 54 | + Durable Task Scheduler and the modern Durable Functions host, rather than the |
| 55 | + classic Durable Functions extension protocol. |
| 56 | +- **Primary client and context APIs use durabletask names.** The main surface |
| 57 | + is now durabletask's (e.g. `schedule_new_orchestration`, |
| 58 | + `get_orchestration_state`, `wait_for_orchestration_completion`). The v1 |
| 59 | + `DurableOrchestrationClient` method names remain available as deprecated |
| 60 | + aliases that emit `DeprecationWarning` (see [Deprecated](#deprecated)). |
| 61 | + |
| 62 | +### Added |
| 63 | + |
| 64 | +New capabilities beyond the v1 surface, most inherited from `durabletask`: |
| 65 | + |
| 66 | +- **durabletask-native authoring.** Two-argument orchestrator, entity, and |
| 67 | + activity functions (`def orchestrator(ctx, input)`, `def entity(ctx, input)`, |
| 68 | + `def activity(ctx, input)`) and class-based entities (`DurableEntity`) are |
| 69 | +first-class, alongside the supported v1-style single-argument functions. For |
| 70 | +activities, `activity_trigger` adapts a two-argument `(ctx, input)` function |
| 71 | +to the host's single-input calling convention automatically (the context is a |
| 72 | +placeholder object; accessing context attributes raises `NotImplementedError`). |
| 73 | +- **`DurableFunctionsClient.rewind_orchestration(...)`** rewinds a failed |
| 74 | + orchestration to its last known good state (inherited from durabletask). |
| 75 | +- **`DFApp.configure_scheduled_tasks()`** opts an app in to durabletask |
| 76 | + scheduled (recurring) tasks by registering the schedule entity and operation |
| 77 | + orchestrator. Schedules are then managed from a client via |
| 78 | + `durabletask.scheduled.ScheduledTaskClient`. Scheduled tasks are not |
| 79 | + registered unless this method is called. |
| 80 | +- **`DFApp.configure_history_export(writer=...)`** opts an app in to durabletask |
| 81 | + history export by registering the export-job entity, driving orchestrator, and |
| 82 | + activities. Supply the `HistoryWriter` here; the activities resolve their |
| 83 | + durabletask client per invocation from a `durable_client_input` binding, so |
| 84 | + the export activities run correctly across a scaled-out, multi-worker |
| 85 | + deployment (each invocation resolves its own client). This is a correctness |
| 86 | + property, not a large-export throughput guarantee. Export jobs are |
| 87 | + driven from a client via |
| 88 | + `durabletask.extensions.history_export.ExportHistoryClient`. Continuous export |
| 89 | + (`ExportMode.CONTINUOUS`) is not supported on Azure Functions: the |
| 90 | + Functions-registered export entity rejects it at job creation (the job ends |
| 91 | + `FAILED` with an explanatory reason). Continuous tailing needs the host's |
| 92 | + `ListInstanceIds` gRPC call, which the Durable Functions host extension does |
| 93 | + not implement; the instance-enumeration activity uses a Functions-specific |
| 94 | + implementation based on `QueryInstances` for the same reason. This is an |
| 95 | + experimental beta feature intended for bounded, low-volume batch-export |
| 96 | + windows: the `QueryInstances`-based enumeration re-scans and re-sorts the |
| 97 | + terminal-instance population for each batch, so it is not yet suited to |
| 98 | + production-scale history export. Efficient large exports depend on a |
| 99 | + host-side completed-time paging API that the host extension does not yet |
| 100 | + provide. |
| 101 | +- **`DurableOrchestrationContext.call_http(...)`** makes durable HTTP calls from |
| 102 | + orchestrators, restoring the v1 API. The request is executed by a built-in |
| 103 | + activity and, when the endpoint responds with `202 Accepted` and a `Location` |
| 104 | + header, is automatically polled to completion (honoring `Retry-After`). |
| 105 | + `ManagedIdentityTokenSource` can be supplied to attach a Managed Identity |
| 106 | + bearer token to the request. `DurableHttpRequest` and `DurableHttpResponse` |
| 107 | + are exported from `azure.durable_functions`. |
| 108 | +- **`orchestration_trigger(..., input_type=...)`** decodes a v1-style |
| 109 | + `context.get_input()` to the declared type; a call-site `expected_type` on |
| 110 | + `get_input` takes precedence. |
| 111 | + |
| 112 | +### Compatibility with v1 |
| 113 | + |
| 114 | +To ease migration, 2.x ships a compatibility layer over the durabletask |
| 115 | +surface: |
| 116 | + |
| 117 | +- **v1-style single-argument functions** (`def orchestrator(context)`, |
| 118 | + `def entity(context)`) are supported. The worker detects the function shape |
| 119 | + and, for single-argument functions, delivers a functional |
| 120 | + `DurableOrchestrationContext` / `DurableEntityContext` that wraps the |
| 121 | + durabletask context and exposes the v1 API — for orchestrations: |
| 122 | + `get_input`, `call_activity`/`call_activity_with_retry`, |
| 123 | + `call_sub_orchestrator`/`call_sub_orchestrator_with_retry`, `create_timer`, |
| 124 | + `wait_for_external_event`, `continue_as_new`, `set_custom_status`, |
| 125 | + `task_all`/`task_any`, `call_entity`/`signal_entity`, `new_uuid`/`new_guid`, |
| 126 | + `custom_status`, `will_continue_as_new`, `parent_instance_id`, and |
| 127 | + `function_context`; and for entities: `entity_name`, `entity_key`, |
| 128 | + `operation_name`, `get_input`, `get_state` (with `initializer`), `set_state`, |
| 129 | + `set_result`, and `destruct_on_exit`. The operation result is taken from |
| 130 | + `set_result(...)`, falling back to the function's return value. |
| 131 | +- **v1 return-type wrappers** `DurableOrchestrationStatus`, |
| 132 | + `PurgeHistoryResult`, and `EntityStateResponse` are returned by the deprecated |
| 133 | + client methods and exported from `azure.durable_functions`. |
| 134 | +- **`HttpManagementPayload`** subclasses `dict`, so it is directly |
| 135 | + JSON-serializable via `json.dumps(payload)` and supports mapping-style access, |
| 136 | + matching v1 usage. |
| 137 | +- **`create_http_management_payload`** accepts either the durabletask |
| 138 | + `(request, instance_id)` or the v1 `(instance_id)` signature. |
| 139 | + |
| 140 | +### Deprecated |
| 141 | + |
| 142 | +These v1 names are retained as shims that delegate to their durabletask |
| 143 | +equivalents and emit `DeprecationWarning`; prefer the durabletask names in new |
| 144 | +code: |
| 145 | + |
| 146 | +- `DurableOrchestrationClient` (alias for `DurableFunctionsClient`) and its |
| 147 | + method names: `start_new`, `get_status`, `get_status_all`, `get_status_by`, |
| 148 | + `raise_event`, `terminate`, `purge_instance_history`, |
| 149 | + `purge_instance_history_by`, `suspend`, `resume`, `restart`, |
| 150 | + `read_entity_state`, `get_client_response_links`, and |
| 151 | + `wait_for_completion_or_create_check_status_response`. |
| 152 | +- `rewind(...)` — delegates to `rewind_orchestration(...)`. |
| 153 | +- `signal_entity(..., operation_input=...)` — `operation_input` is an alias for |
| 154 | + `input`; `task_hub_name` / `connection_name` are accepted and ignored. |
| 155 | +- `RetryOptions` — maps the v1 millisecond-based constructor onto durabletask |
| 156 | + `RetryPolicy` (which uses `timedelta`). `RetryPolicy` is also exported from |
| 157 | + `azure.durable_functions`. |
| 158 | +- Compatibility aliases exported from `azure.durable_functions`: |
| 159 | + `DurableOrchestrationContext`, `DurableEntityContext`, `EntityId`, |
| 160 | + `ManagedIdentityTokenSource`, `TokenSource`, `Entity`, and |
| 161 | + `OrchestrationRuntimeStatus`. |
| 162 | + |
| 163 | +### Known limitations |
| 164 | + |
| 165 | +- Orchestration history is not exposed on the context; |
| 166 | + `DurableOrchestrationContext.histories` raises `NotImplementedError`. Use the |
| 167 | + client's `get_orchestration_history(...)` instead. |
| 168 | +- The client status methods accept the v1 `show_history` / |
| 169 | + `show_history_output` flags for signature compatibility but ignore them, so |
| 170 | + the returned status has no `historyEvents`. Use |
| 171 | + `get_orchestration_history(...)` to retrieve history. |
| 172 | +- Distributed tracing is not yet wired up. The Durable Functions host delivers |
| 173 | + the parent trace context and emits the orchestration/activity spans itself, |
| 174 | + so orchestrator user-code spans in the Python worker are not yet correlated |
| 175 | + to it, and durabletask's own span emission is intentionally left disabled to |
| 176 | + avoid duplicating the host's spans. |
0 commit comments