@@ -9,55 +9,6 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
99
1010ADDED
1111
12- - Added overridable activity-dispatch hooks ` _on_activity_execution_started `
13- and ` _on_activity_execution_completed ` on ` TaskHubGrpcWorker ` , invoked
14- immediately before each activity runs and in a ` finally ` after it completes
15- or fails. Subclasses can override these to observe in-flight activity
16- execution (for example, to track the number of activities currently
17- running).
18- - Added ` durabletask.extensions.history_export ` for exporting the event history of
19- terminal orchestrations to an external destination. Includes
20- ` ExportHistoryClient ` , a per-job ` ExportHistoryJobClient ` returned by
21- ` get_job_client(...) ` , and ` list_jobs(...) ` for enumerating jobs by status
22- or last-modified window. Ships with a bundled ` AzureBlobHistoryExportWriter `
23- (installed with ` pip install durabletask[history-export-azure] ` ) and a
24- ` HistoryWriter ` protocol for plugging in custom destinations. Supports both
25- ` ExportMode.BATCH ` (export a window and complete) and ` ExportMode.CONTINUOUS `
26- (tail terminal instances indefinitely until stopped via ` delete_job ` ).
27- Exported blobs are self-describing: each blob carries an explicit
28- ` schema_version ` , the orchestration's ` OrchestrationState ` metadata, and
29- the full ordered event list. Blob names are a lowercase-hex SHA-256 of
30- `` {last_updated_at}|{instance_id} `` with the format extension appended
31- (matches the .NET ` ExportInstanceHistoryActivity ` naming scheme), so
32- re-exporting an instance after a later terminal update lands at a new
33- blob path rather than overwriting the previous one, and instance IDs
34- that differ only by ` / ` no longer collide. Each exported blob also
35- carries ` {"instance_id": <id>} ` as destination-side metadata (the Azure
36- writer persists this as Azure Blob metadata) so consumers can scan a
37- container without parsing each blob body. The export workflow retries each instance up
38- to 3 times with exponential backoff (15s/30s/60s), retries failed batches
39- up to 3 times, caps in-flight exports via ` max_parallel_exports `
40- (default 32), continues-as-new every 5 page cycles to bound orchestrator
41- history while preserving cumulative totals across continue-as-new segments,
42- and re-fetches entity state at the top of every page loop so
43- external delete or mark-failed signals stop the orchestrator cleanly.
44- Empty-page BATCH checkpoints no longer reset the persisted resume cursor,
45- and duplicate ` mark_failed ` signals are now idempotent no-ops when a job
46- is already failed to reduce transition-noise logs.
47- ` delete_job ` actively tears the job down: it clears the entity state,
48- terminates the driving orchestrator, waits briefly for it to settle, and
49- purges its orchestration history so a re-created job with the same ID
50- starts from a clean slate. Per-instance exports refuse to write a blob
51- when the target instance has been purged or has re-entered a non-terminal
52- state, surfacing the skipped instance as a per-batch failure.
53- Job state lives in a durable entity with an explicit state-transition
54- matrix (ACTIVE / COMPLETED / FAILED); invalid transitions raise
55- ` ExportJobInvalidTransitionError ` . Persisted entity state uses a
56- versioned, schema-stable JSON shape (` STATE_SCHEMA_VERSION ` ) with no
57- embedded Python type metadata. Each export job's driving orchestrator
58- uses a deterministic instance ID (` export-job-{job_id} ` , exposed via
59- ` orchestrator_instance_id_for(...) ` ) so callers can correlate a job ID
60- with its orchestrator for logging, monitoring, and restart.
6112- Added a pluggable ` DataConverter ` (` durabletask.serialization ` ) accepted by
6213 ` TaskHubGrpcWorker ` , ` TaskHubGrpcClient ` , and ` AsyncTaskHubGrpcClient ` via a
6314 ` data_converter ` argument. Every payload boundary (inputs, outputs, events,
@@ -124,6 +75,60 @@ subclassing the public abstract types — may need to update their code:
12475 (excluded from equality and ` repr ` ). Code constructing ` OrchestrationState `
12576 positionally should pass it via the new field or rely on its default.
12677
78+ ## v1.6.0
79+
80+ ADDED
81+
82+ - Added overridable activity-dispatch hooks ` _on_activity_execution_started `
83+ and ` _on_activity_execution_completed ` on ` TaskHubGrpcWorker ` , invoked
84+ immediately before each activity runs and in a ` finally ` after it completes
85+ or fails. Subclasses can override these to observe in-flight activity
86+ execution (for example, to track the number of activities currently
87+ running).
88+ - Added ` durabletask.extensions.history_export ` for exporting the event history of
89+ terminal orchestrations to an external destination. Includes
90+ ` ExportHistoryClient ` , a per-job ` ExportHistoryJobClient ` returned by
91+ ` get_job_client(...) ` , and ` list_jobs(...) ` for enumerating jobs by status
92+ or last-modified window. Ships with a bundled ` AzureBlobHistoryExportWriter `
93+ (installed with ` pip install durabletask[history-export-azure] ` ) and a
94+ ` HistoryWriter ` protocol for plugging in custom destinations. Supports both
95+ ` ExportMode.BATCH ` (export a window and complete) and ` ExportMode.CONTINUOUS `
96+ (tail terminal instances indefinitely until stopped via ` delete_job ` ).
97+ Exported blobs are self-describing: each blob carries an explicit
98+ ` schema_version ` , the orchestration's ` OrchestrationState ` metadata, and
99+ the full ordered event list. Blob names are a lowercase-hex SHA-256 of
100+ `` {last_updated_at}|{instance_id} `` with the format extension appended
101+ (matches the .NET ` ExportInstanceHistoryActivity ` naming scheme), so
102+ re-exporting an instance after a later terminal update lands at a new
103+ blob path rather than overwriting the previous one, and instance IDs
104+ that differ only by ` / ` no longer collide. Each exported blob also
105+ carries ` {"instance_id": <id>} ` as destination-side metadata (the Azure
106+ writer persists this as Azure Blob metadata) so consumers can scan a
107+ container without parsing each blob body. The export workflow retries each instance up
108+ to 3 times with exponential backoff (15s/30s/60s), retries failed batches
109+ up to 3 times, caps in-flight exports via ` max_parallel_exports `
110+ (default 32), continues-as-new every 5 page cycles to bound orchestrator
111+ history while preserving cumulative totals across continue-as-new segments,
112+ and re-fetches entity state at the top of every page loop so
113+ external delete or mark-failed signals stop the orchestrator cleanly.
114+ Empty-page BATCH checkpoints no longer reset the persisted resume cursor,
115+ and duplicate ` mark_failed ` signals are now idempotent no-ops when a job
116+ is already failed to reduce transition-noise logs.
117+ ` delete_job ` actively tears the job down: it clears the entity state,
118+ terminates the driving orchestrator, waits briefly for it to settle, and
119+ purges its orchestration history so a re-created job with the same ID
120+ starts from a clean slate. Per-instance exports refuse to write a blob
121+ when the target instance has been purged or has re-entered a non-terminal
122+ state, surfacing the skipped instance as a per-batch failure.
123+ Job state lives in a durable entity with an explicit state-transition
124+ matrix (ACTIVE / COMPLETED / FAILED); invalid transitions raise
125+ ` ExportJobInvalidTransitionError ` . Persisted entity state uses a
126+ versioned, schema-stable JSON shape (` STATE_SCHEMA_VERSION ` ) with no
127+ embedded Python type metadata. Each export job's driving orchestrator
128+ uses a deterministic instance ID (` export-job-{job_id} ` , exposed via
129+ ` orchestrator_instance_id_for(...) ` ) so callers can correlate a job ID
130+ with its orchestrator for logging, monitoring, and restart.
131+
127132## v1.5.0
128133
129134BREAKING CHANGES (type-level only — no runtime impact for typical users)
0 commit comments