|
21 | 21 | - Added an optional `signal_time` parameter to `OrchestrationContext.signal_entity` |
22 | 22 | and to the client `signal_entity` methods (sync and async), allowing entity |
23 | 23 | signals to be scheduled for future delivery from orchestrations and clients. |
| 24 | +- Added a pluggable `DataConverter` (`durabletask.serialization`) accepted by |
| 25 | + `TaskHubGrpcWorker`, `TaskHubGrpcClient`, and `AsyncTaskHubGrpcClient` via a |
| 26 | + `data_converter` argument. Every payload boundary (inputs, outputs, events, |
| 27 | + custom status, entity state) routes through it. The default |
| 28 | + `JsonDataConverter` preserves existing behavior, so a custom converter (for |
| 29 | + example one backed by pydantic) is opt-in. Custom objects can opt in via a |
| 30 | + `to_json()` hook and a `from_json(value)` classmethod. |
| 31 | +- `OrchestrationContext.call_activity`, `call_sub_orchestrator`, and |
| 32 | + `call_entity` accept an optional `return_type`, and `wait_for_external_event` |
| 33 | + accepts an optional `data_type`. When provided, the result/event payload is |
| 34 | + reconstructed as that type (dataclasses — including nested dataclass, |
| 35 | + `Optional`, and `list` fields — and `from_json()`-capable types) and the |
| 36 | + returned task is typed accordingly (e.g. `call_activity(..., return_type=Foo)` |
| 37 | + yields `CompletableTask[Foo]`). When omitted, the raw deserialized JSON is |
| 38 | + returned as before. |
| 39 | +- Inbound payloads are reconstructed from function type annotations. When an |
| 40 | + orchestrator, activity, or entity operation annotates its input parameter (or |
| 41 | + an activity its return value) with a dataclass or `from_json()`-capable type, |
| 42 | + the payload is reconstructed as that type. Builtins and unannotated/unknown |
| 43 | + types are passed through unchanged. An explicit `return_type` takes precedence |
| 44 | + over a discovered annotation. |
| 45 | +- Added typed accessors to `client.OrchestrationState`: `get_input()`, |
| 46 | + `get_output()`, and `get_custom_status()` each accept an optional |
| 47 | + `expected_type` and deserialize the corresponding payload, reconstructing |
| 48 | + dataclasses and `from_json()`-capable types. The raw `serialized_*` fields are |
| 49 | + retained. |
| 50 | +- Objects exposing a `to_json()` method are now JSON-serializable when passed as |
| 51 | + activity/orchestrator inputs or outputs. |
| 52 | +- Added `EntityMetadata.get_typed_state(intended_type=...)`, which deserializes |
| 53 | + the entity's persisted state and reconstructs dataclasses and |
| 54 | + `from_json()`-capable types. The existing `get_state()` is unchanged: with no |
| 55 | + argument it returns the raw serialized JSON payload, and `get_state(some_type)` |
| 56 | + applies constructor-based coercion (`some_type(raw)`). |
| 57 | +- Entity runtime state retrieval (`EntityContext.get_state(intended_type=...)` / |
| 58 | + `DurableEntity.get_state(...)`) now also reconstructs dataclasses and |
| 59 | + `from_json()`-capable types, in addition to the existing constructor-based |
| 60 | + coercion. |
| 61 | + |
| 62 | +CHANGED |
| 63 | + |
| 64 | +- Custom objects (dataclasses, `SimpleNamespace`, namedtuples) are now |
| 65 | + serialized as plain JSON. Decoding such a payload *without* a type hint now |
| 66 | + yields a plain `dict` (previously a `SimpleNamespace`; a namedtuple now |
| 67 | + round-trips as a JSON array). To get the original type back, pass the new |
| 68 | + `return_type` / `data_type` arguments, annotate the consuming function's |
| 69 | + parameter or return type, or use the typed client accessors. Payloads produced |
| 70 | + by older SDK versions still deserialize — including into a `SimpleNamespace` |
| 71 | + when no type is supplied — so in-flight orchestrations continue to replay |
| 72 | + across an upgrade. |
| 73 | +- JSON serialization failures now raise a `TypeError` that chains the original |
| 74 | + error (`__cause__`) and names the offending type. |
| 75 | + |
| 76 | +FIXED |
| 77 | + |
| 78 | +- Falsy entity states (`0`, `""`, `[]`, `{}`) are no longer dropped when an |
| 79 | + entity batch is persisted. Previously a falsy current state was treated as |
| 80 | + "no state" and written as `None`, effectively deleting it; only an actual |
| 81 | + `None` state now clears the persisted entity state. |
| 82 | + |
| 83 | +BREAKING CHANGES (type-level only — no runtime impact for typical users) |
| 84 | + |
| 85 | +These changes do not alter runtime behavior, but because the package ships |
| 86 | +`py.typed`, consumers running strict type checkers (pyright/mypy) — or |
| 87 | +subclassing the public abstract types — may need to update their code: |
| 88 | + |
| 89 | +- `OrchestrationContext.call_activity`, `call_sub_orchestrator`, `call_entity`, |
| 90 | + and `wait_for_external_event` gained new keyword-only parameters |
| 91 | + (`return_type` / `data_type`). Subclasses overriding these methods should add |
| 92 | + the parameter to match the base signature. |
| 93 | +- `client.OrchestrationState` gained a non-public `_data_converter` field |
| 94 | + (excluded from equality and `repr`). Code constructing `OrchestrationState` |
| 95 | + positionally should pass it via the new field or rely on its default. |
24 | 96 |
|
25 | 97 | ## v1.6.0 |
26 | 98 |
|
|
0 commit comments