Skip to content

Commit 199a701

Browse files
committed
Merge remote-tracking branch 'origin/main' into andystaples/add-orchestration-rewind
# Conflicts: # CHANGELOG.md
2 parents f12b808 + 7e95535 commit 199a701

6 files changed

Lines changed: 43 additions & 20 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ ADDED
1111

1212
- Added `TaskHubGrpcClient.rewind_orchestration()` to rewind a failed orchestration instance to its last known good state. Failed activity and sub-orchestration results are removed from the history and the orchestration replays from the last successful checkpoint, retrying only the failed work. The in-memory testing backend supports rewind as well.
1313

14+
## v1.7.2
15+
16+
FIXED
17+
18+
- Fixed history export failing for orchestrations that completed with an error. Events carrying failure information (orchestration completion, activity failure, sub-orchestration failure, and entity operation failure) were not JSON-serializable, causing the `durabletask.extensions.history_export` module to raise `TypeError: Object of type FailureDetails is not JSON serializable`. `FailureDetails` now serializes to a JSON object with `message`, `error_type`, and `stack_trace` fields.
19+
1420
## v1.7.1
1521

1622
ADDED

durabletask-azuremanaged/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88
## Unreleased
99

10+
## v1.7.2
11+
12+
- Updates base dependency to durabletask v1.7.2.
13+
1014
## v1.7.1
1115

1216
- Updates base dependency to durabletask v1.7.1

durabletask-azuremanaged/pyproject.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta"
99

1010
[project]
1111
name = "durabletask.azuremanaged"
12-
version = "1.7.1"
12+
version = "1.7.2"
1313
description = "Durable Task Python SDK provider implementation for the Azure Durable Task Scheduler"
1414
keywords = [
1515
"durable",
@@ -26,13 +26,13 @@ requires-python = ">=3.10"
2626
license = {file = "LICENSE"}
2727
readme = "README.md"
2828
dependencies = [
29-
"durabletask>=1.7.1",
29+
"durabletask>=1.7.2",
3030
"azure-identity>=1.19.0"
3131
]
3232

3333
[project.optional-dependencies]
3434
azure-blob-payloads = [
35-
"durabletask[azure-blob-payloads]>=1.7.1"
35+
"durabletask[azure-blob-payloads]>=1.7.2"
3636
]
3737

3838
[project.urls]

durabletask/task.py

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import math
99
from abc import ABC, abstractmethod
1010
from collections.abc import Callable, Generator, Sequence
11+
from dataclasses import dataclass
1112
from datetime import datetime, timedelta, timezone
1213
from typing import TYPE_CHECKING, Any, Generic, TypeAlias, TypeVar, cast, overload
1314

@@ -449,23 +450,11 @@ def isEnabledFor(self, level: int) -> bool:
449450
return self.logger.isEnabledFor(level)
450451

451452

453+
@dataclass(frozen=True)
452454
class FailureDetails:
453-
def __init__(self, message: str, error_type: str, stack_trace: str | None):
454-
self._message = message
455-
self._error_type = error_type
456-
self._stack_trace = stack_trace
457-
458-
@property
459-
def message(self) -> str:
460-
return self._message
461-
462-
@property
463-
def error_type(self) -> str:
464-
return self._error_type
465-
466-
@property
467-
def stack_trace(self) -> str | None:
468-
return self._stack_trace
455+
message: str
456+
error_type: str
457+
stack_trace: str | None
469458

470459

471460
class TaskFailedError(Exception):

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta"
99

1010
[project]
1111
name = "durabletask"
12-
version = "1.7.1"
12+
version = "1.7.2"
1313
description = "A Durable Task Client SDK for Python"
1414
keywords = [
1515
"durable",

tests/durabletask/extensions/history_export/test_serialization.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,30 @@ def test_includes_type_discriminator(self) -> None:
6666
assert d["event_id"] == 0
6767
assert d["timestamp"].startswith("2025-01-01")
6868

69+
def test_failure_details_is_json_safe(self) -> None:
70+
# Regression: FailureDetails-bearing events must serialize to a
71+
# JSON-safe dict rather than a raw FailureDetails object.
72+
e = history.ExecutionCompletedEvent(
73+
event_id=-1,
74+
timestamp=datetime(2025, 1, 1, tzinfo=timezone.utc),
75+
orchestration_status=3,
76+
result=None,
77+
failure_details=task.FailureDetails(
78+
message="boom", error_type="RuntimeError", stack_trace="trace",
79+
),
80+
)
81+
d = event_to_dict(e)
82+
assert d["failure_details"] == {
83+
"message": "boom",
84+
"error_type": "RuntimeError",
85+
"stack_trace": "trace",
86+
}
87+
# The full document must be JSON-serializable.
88+
fmt = ExportFormat(kind=ExportFormatKind.JSON)
89+
out = serialize_history([e], instance_id="fail-1", fmt=fmt)
90+
doc = json.loads(out)
91+
assert doc["events"][0]["failure_details"]["error_type"] == "RuntimeError"
92+
6993

7094
class TestSerializeJson:
7195
def test_envelope_fields(self) -> None:

0 commit comments

Comments
 (0)