Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

## v1.7.2

FIXED

- 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.

## v1.7.1

ADDED
Expand Down
4 changes: 4 additions & 0 deletions durabletask-azuremanaged/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

## v1.7.2

- Updates base dependency to durabletask v1.7.2.

## v1.7.1

- Updates base dependency to durabletask v1.7.1
Expand Down
6 changes: 3 additions & 3 deletions durabletask-azuremanaged/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "durabletask.azuremanaged"
version = "1.7.1"
version = "1.7.2"
description = "Durable Task Python SDK provider implementation for the Azure Durable Task Scheduler"
keywords = [
"durable",
Expand All @@ -26,13 +26,13 @@ requires-python = ">=3.10"
license = {file = "LICENSE"}
readme = "README.md"
dependencies = [
"durabletask>=1.7.1",
"durabletask>=1.7.2",
"azure-identity>=1.19.0"
]

[project.optional-dependencies]
azure-blob-payloads = [
"durabletask[azure-blob-payloads]>=1.7.1"
"durabletask[azure-blob-payloads]>=1.7.2"
]

[project.urls]
Expand Down
21 changes: 5 additions & 16 deletions durabletask/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import math
from abc import ABC, abstractmethod
from collections.abc import Callable, Generator, Sequence
from dataclasses import dataclass
from datetime import datetime, timedelta, timezone
from typing import TYPE_CHECKING, Any, Generic, TypeAlias, TypeVar, cast, overload

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


@dataclass(frozen=True)
class FailureDetails:
def __init__(self, message: str, error_type: str, stack_trace: str | None):
self._message = message
self._error_type = error_type
self._stack_trace = stack_trace

@property
def message(self) -> str:
return self._message

@property
def error_type(self) -> str:
return self._error_type

@property
def stack_trace(self) -> str | None:
return self._stack_trace
message: str
error_type: str
stack_trace: str | None


class TaskFailedError(Exception):
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "durabletask"
version = "1.7.1"
version = "1.7.2"
description = "A Durable Task Client SDK for Python"
keywords = [
"durable",
Expand Down
24 changes: 24 additions & 0 deletions tests/durabletask/extensions/history_export/test_serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,30 @@ def test_includes_type_discriminator(self) -> None:
assert d["event_id"] == 0
assert d["timestamp"].startswith("2025-01-01")

def test_failure_details_is_json_safe(self) -> None:
# Regression: FailureDetails-bearing events must serialize to a
# JSON-safe dict rather than a raw FailureDetails object.
e = history.ExecutionCompletedEvent(
event_id=-1,
timestamp=datetime(2025, 1, 1, tzinfo=timezone.utc),
orchestration_status=3,
result=None,
failure_details=task.FailureDetails(
message="boom", error_type="RuntimeError", stack_trace="trace",
),
)
d = event_to_dict(e)
assert d["failure_details"] == {
"message": "boom",
"error_type": "RuntimeError",
"stack_trace": "trace",
}
# The full document must be JSON-serializable.
fmt = ExportFormat(kind=ExportFormatKind.JSON)
out = serialize_history([e], instance_id="fail-1", fmt=fmt)
doc = json.loads(out)
assert doc["events"][0]["failure_details"]["error_type"] == "RuntimeError"


class TestSerializeJson:
def test_envelope_fields(self) -> None:
Expand Down
Loading