Tags: microsoft/durabletask-python
Tags
Add azure-functions-durable v2: a durabletask-based rewrite of Durabl… …e Functions for Python (#155) * Storing changes commit * Working orchestrators + activities * Nitpicks and cleanup * Save-all nits * Add entity support (needs extension change) * Refine entity support - Still needs eventSent and eventRecieved implementations * Finish entity support * Fixes and improvements - Add new_uuid method to OrchestrationContext for deterministic replay-safe UUIDs - Fix entity locking behavior for Functions - Align _RuntimeOrchestrationContext param names with OrchestrationContext - Remap __init__.py files for new module - Update version to 0.0.1dev0 - Add docstrings to missing methods - Move code for executing orchestrators/entities to DurableFunctionsWorker - Add function metadata to triggers for detection by extension * Bump durabletask version, fix metadata * Use Protocol for stubs * Update to new workflow pattern * Rename stub file * Fix import * Experimental dependency revision * Update to match changes in functions SDK * Merge issue fix * Various * Add Functions to requirements * Rename to azure-functions-durable v2 * Re-add Orchestrator object/model * Modernize pipelines for functions package * Cleanup pyright errors * Remove non-existent extension call * Serialization compat, fix typing, working again * Use the async client (match old behavior) * Compat layer V1 * Reorganize compat files * Add shims for old orchestration and entity call arg patterns * Add remaining orchestration surface * Add missing type coersion, rich client, tests * Fix gaps found via integration tests * Fix old-name interceptor lookup * More compat layer stuff * Return an emtpy function context instead of raising * Asyncio in test matrix * CI Tweaks * Add Durable HTTP feature * CHANGELOG for now * Add unit testing coverage * Add E2E harness * Expand E2E coverage * More E2E test edge cases, fixes, add scheduled tasks * Add history export to afd * Add afd rewind * lint fix * Pyright fixes * Review feedback * Review Feedback 2 * 2.0.0b1 CHANGELOG rewrite * Review Feedback 3 * Fix CI * Review Feedback 4 * History export pagination fix * Allow both activity signatures * Record DT limitation * Comment tweak * Address YunchuWang review items * afd: address PR #155 review feedback Fixes from berndverst's review of the Azure Functions Durable v2 provider: - durable_app: preserve the configured entity name (mirror orchestrator wiring) - client: accept the v1 'entityId' keyword on entity APIs - client: return the full status JSON for TERMINATED/FAILED and surface failure details via DurableOrchestrationStatus.to_json() - entity_id: fix get_entity_id - http/builtin: resolve a relative Location header against the request URI - serialization: decode plainly and let coerce() reconstruct typed values (loose-mode portion of the strict-typing fix) - replace typing_extensions.deprecated with stdlib warnings.deprecated and drop the typing_extensions dependency * afd: forward destination type through payload deserialization - FunctionsDataConverter.deserialize now passes the target type to df_loads as expected_type so payloads are deserialized with type validation instead of decoding untyped and coercing afterward. - Depend directly on azure-functions' df_dumps/df_loads; remove the legacy custom-object serialization fallback path and its tests. - DurableEntityContext.get_input coerces the operation input to expected_type when one is supplied (previously ignored). - wrap_orchestrator stamps the decorator-declared input_type onto the wrapper's input annotation so type discovery deserializes the orchestration input to that type. - builtin_http_poll_orchestrator returns a DurableHttpResponse object so the call_http sub-orchestration result round-trips as its declared type. * Make scheduled payloads and the Functions converter strict-typing compatible - ScheduleOperationRequest.to_json emits its options input as a plain mapping and from_json rebuilds the concrete options type from the operation name, so the payload is JSON-native (no nested custom-object envelope a strict-typing serializer cannot encode). - ScheduleState.to_json emits its schedule configuration as a plain mapping instead of the raw object; from_json already rebuilds it. - FunctionsDataConverter.coerce validates through serialize/deserialize so a coercion applies the same codec type rules as a wire payload, and can_reconstruct returns True so type discovery always hands the declared type to the codec. - Run the azure-functions-durable end-to-end suite in both the default and strict payload-typing modes via a CI matrix. Verified: unit suites, plus the e2e suite in both loose and strict modes. * Resolve the history-export client per invocation via a durable client binding The export activities previously resolved their durabletask client from a process-global context bound in the request handler, which is not visible to an activity running in another worker process. They now declare a durable_client_input binding and build the client per invocation from it, so the host supplies it wherever the activity runs. The HistoryWriter, which the host cannot inject, is registered via configure_history_export(writer=...) at app startup and reused. Supporting SDK fixes for functions that carry a durable client binding alongside their trigger: - wrap_activity leaves a native activity whose first parameter is the trigger input untouched (so additional bindings such as a durable client bind by name) instead of adapting it as a (context, input) activity. - the durable client middleware invokes synchronous user functions and returns their result instead of awaiting it. Verified: unit suites, plus the e2e suite (history export and full) in loose and strict modes. * Reject continuous history export on Azure Functions Add azure.durable_functions.extensions.history_export.ExportHistoryClient, a Functions-aware subclass that rejects ExportMode.CONTINUOUS at job creation and otherwise passes through to the durabletask client. Continuous export tails terminal instances indefinitely, which needs the host's ListInstanceIds (a server-side completed-time cursor); the Durable Functions host extension does not implement it, so the Functions enumeration path can only page a bounded completed-time window safely. Batch export is unaffected. Also refresh the changelog entry for configure_history_export to reflect the writer argument and per-invocation client binding. Verified: unit suites, plus the history-export e2e (batch) in loose mode. * Enforce the continuous-export rejection at the Functions export entity Rejecting ExportMode.CONTINUOUS only in an optional ExportHistoryClient subclass was bypassable: callers can use the core durabletask ExportHistoryClient (which the docs point to) to signal the same shared ExportJobEntity, whose create operation had no mode guard. Move the guard to a Functions-registered ExportJobEntity subclass that marks the job FAILED with an explanatory reason when created in continuous mode, so the unsupported mode cannot start regardless of which client is used. Remove the now-redundant azure.durable_functions extensions.history_export module (callers use the core client directly). Also narrowly suppress reportDeprecated on the internal EntityId self-references in EntityId.get_entity_id so the package's strict Pyright check passes while the public EntityId deprecation is preserved. Verified: unit suites, strict Pyright on the changed files, and the history-export e2e including a new continuous-rejection test. * Address review nits: cast target and unused logger - orchestrator.py: pass the Any type object to cast (was a forward-ref string). - serialization.py: remove the now-unused logger and logging import (dead after the fallback removal). * Adopt azure-functions register_converter API for durable bindings Define and register the durable binding converters in this package via azure-functions' new register_converter API, replacing the SDK's prior version-detection auto-registration. The durableClient converter now constructs the rich DurableFunctionsClient during decode, so the per-function _add_rich_client middleware (and its forced-str annotation hack) is removed. - Add internal/converters.py defining the four durable converters and register_durable_converters(); call it at package import. - Remove _add_rich_client and now-unused imports from durable_app.py. - Add test_converters.py; update decorator and smoke tests. * Back-compat unit testing for orchestrators/clients * Address PR feedback * Update azure-functions minimums * Address PR #155 review: schedule serialization, HTTP/export docs, client channel lifecycle - ScheduleState.to_json: add regression test pinning the DTS wire shape (plain PascalCase ScheduleConfiguration mapping, no __class__ envelope); confirmed no wire change under the default converter. - orchestrator_generator_wrapper: handle orchestrators that return without yielding (no StopIteration leak). - builtin http: cache DefaultAzureCredential process-wide to avoid re-running the credential chain on every managed-identity poll. - history export: mark batch export experimental/low-volume in changelog + docstring; clarify scaled-out wording is a correctness property, not a throughput guarantee. - Durable client channel lifecycle: close per-invocation async DurableFunctionsClient channels via an app-level post_invocation extension (schedule_close on the owning loop); close the per-process sync export client at interpreter exit (atexit) with a first-bind lock. Ref #181 for the future native sync binding. - Tests: new test_client_lifecycle.py + sync-client lifecycle, credential-reuse, immediate-return orchestrator, and wire-shape guard tests. Verified via unit suite and functions_e2e (durable client + history export slices). * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Run functions e2e unconditionally; install azure-functions from PyPI azure-functions 2.3.0b2 is now on PyPI, so remove the RUN_FUNCTIONS_E2E gate on the e2e job and drop the local azure-functions build fallback (AZURE_FUNCTIONS_PYTHON_LIBRARY / sibling repo) from nox. The provider's declared azure-functions>=2.3.0b2 dependency now resolves from PyPI. Verified with a clean-venv functions_e2e run (resolved azure-functions 2.3.0b2). * Min azfunc version in requirements.txt * Unpin azure-functions in shared requirements; install 2.3.0b2 explicitly in functions CI azure-functions>=2.3.0b2 requires Python 3.13+, but requirements.txt is shared with the core durabletask / azuremanaged / typecheck CI that runs a 3.10-3.14 matrix, so the pin produced 'No matching distribution' on 3.10-3.12. Unpin it back to bare azure-functions so those jobs resolve a 3.10-compatible build. The azure-functions-durable run-tests job installs the provider with --no-deps and runs only on 3.13/3.14, so add an explicit 'pip install azure-functions>=2.3.0b2' there to pull the build that provides register_converter. * CI: upload Functions host logs as an artifact on e2e failure The e2e harness writes each sample app's 'func start' output to <app>/_func_host.log, but only folds it into an exception on startup failures -- runtime 500s (e.g. durable operations failing after the host is up) leave the real host/worker error invisible in the CI log. Upload the host logs on failure so the durable-extension/worker error is retrievable for diagnosis. * Fix durable client 500 when host sends config fields as null The Durable Functions host client-config JSON can send fields explicitly as null (observed with maxGrpcMessageSizeInBytes on newer extension bundles) rather than omitting them. dict.get(key, default) only substitutes the default for absent keys, so a present-but-null value returned None -- crashing the 'maxGrpcMessageSizeInBytes > 0' guard in __init__ (TypeError: '>' not supported between NoneType and int) and failing every durable-client binding decode with a 500. Parse every field with 'client.get(key) or default' so an explicit null (like a missing key) collapses to its falsy default. Diagnosed from the e2e func host log; add regression tests for a single null field and for all fields sent as null. * Use preview bundles for compatible Durable extension version * Skip API version check azurite --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Bernd Verst <github@bernd.dev>
Release v1.8.0: bump SDK versions and update changelogs (#183) Bump durabletask and durabletask.azuremanaged to 1.8.0, update the azuremanaged dependency floors, and move Unreleased changelog entries into a v1.8.0 section for both packages. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: ebc438fa-ef0b-4c2e-96fd-646d8ed0b6b7
Release v1.8.0: bump SDK versions and update changelogs (#183) Bump durabletask and durabletask.azuremanaged to 1.8.0, update the azuremanaged dependency floors, and move Unreleased changelog entries into a v1.8.0 section for both packages. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: ebc438fa-ef0b-4c2e-96fd-646d8ed0b6b7
Fix FailureDetails JSON serialization and cut v1.7.2 (#172) Convert task.FailureDetails to a frozen dataclass so failed orchestrations serialize cleanly through the history_export module. Previously FailureDetails was a plain class, so HistoryEvent.to_dict() left it as a raw object and json.dumps raised TypeError for ExecutionCompleted, TaskFailed, SubOrchestrationInstanceFailed, and EntityOperationFailed events. Bump both packages to v1.7.2 and update changelogs.
Fix FailureDetails JSON serialization and cut v1.7.2 (#172) Convert task.FailureDetails to a frozen dataclass so failed orchestrations serialize cleanly through the history_export module. Previously FailureDetails was a plain class, so HistoryEvent.to_dict() left it as a raw object and json.dumps raised TypeError for ExecutionCompleted, TaskFailed, SubOrchestrationInstanceFailed, and EntityOperationFailed events. Bump both packages to v1.7.2 and update changelogs.
PreviousNext