Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes several entity-related serialization/deserialization issues (especially in the Azure Functions trigger-binding code path) and adds Jackson JSON support for EntityInstanceId and entity metadata types to improve parity and usability across runtimes.
Changes:
- Fix entity lock-grant handling in the Azure Functions path by special-casing
AutoCloseablelock tasks inhandleEventRaised. - Add Jackson serialization/deserialization support for
EntityInstanceId, and add Jackson-friendly JSON surface forEntityMetadata/TypedEntityMetadatawith new unit tests. - Update samples (standalone + Azure Functions) to use shared builder utilities / Jackson serialization for entity metadata, and update protobuf definitions used by the SDK.
Reviewed changes
Copilot reviewed 32 out of 32 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| samples/src/main/java/io/durabletask/samples/TypedEntityProxySample.java | Switch sample worker/client creation to centralized SampleUtils builders. |
| samples/src/main/java/io/durabletask/samples/SampleUtils.java | New helper for creating client/worker builders based on env-driven connection string. |
| samples/src/main/java/io/durabletask/samples/LowLevelEntitySample.java | Use SampleUtils builders for consistency across samples. |
| samples/src/main/java/io/durabletask/samples/EntityTimeoutSample.java | Use SampleUtils builders for consistency across samples. |
| samples/src/main/java/io/durabletask/samples/EntityReentrantSample.java | Use SampleUtils builders for consistency across samples. |
| samples/src/main/java/io/durabletask/samples/EntityQuerySample.java | Use SampleUtils builders for consistency across samples. |
| samples/src/main/java/io/durabletask/samples/EntityCommunicationSample.java | Use SampleUtils builders for consistency across samples. |
| samples/src/main/java/io/durabletask/samples/CounterEntitySample.java | Use SampleUtils builders for consistency across samples. |
| samples/src/main/java/io/durabletask/samples/BankAccountSample.java | Use SampleUtils builders and avoid swallowing framework control-flow exceptions. |
| samples/build.gradle | Add Gradle run tasks for entity samples + set default ENDPOINT/TASKHUB environment. |
| samples-azure-functions/src/main/java/com/functions/entities/sensors.http | Add HTTP request examples for the new sensor/aggregator Azure Functions sample. |
| samples-azure-functions/src/main/java/com/functions/entities/bankaccounts.http | Add HTTP request examples for the bank account Azure Functions sample. |
| samples-azure-functions/src/main/java/com/functions/entities/SensorState.java | New POJO state types used by sensor/aggregator entities. |
| samples-azure-functions/src/main/java/com/functions/entities/SensorFunctions.java | New Azure Functions endpoints for sensor/aggregator entity communication scenario. |
| samples-azure-functions/src/main/java/com/functions/entities/SensorEntity.java | New sensor entity implementation that forwards readings to an aggregator entity. |
| samples-azure-functions/src/main/java/com/functions/entities/LifetimeFunctions.java | Serialize entity metadata via Jackson converter before returning in HTTP response. |
| samples-azure-functions/src/main/java/com/functions/entities/CounterFunctions.java | Serialize entity metadata via Jackson converter before returning in HTTP response. |
| samples-azure-functions/src/main/java/com/functions/entities/BankAccountFunctions.java | New Azure Functions sample demonstrating entity locking and metadata responses. |
| samples-azure-functions/src/main/java/com/functions/entities/BankAccountEntity.java | New bank account entity implementation for the Azure Functions sample. |
| samples-azure-functions/src/main/java/com/functions/entities/AggregatorEntity.java | New aggregator entity that computes averages and starts an alert orchestration. |
| internal/durabletask-protobuf/protos/orchestrator_service.proto | Update proto contracts (tags, rewind action, deprecations, purge timeout). |
| internal/durabletask-protobuf/PROTO_SOURCE_COMMIT_HASH | Update referenced upstream proto source commit hash. |
| client/src/test/java/com/microsoft/durabletask/TypedEntityMetadataTest.java | Add Jackson serialization tests validating public vs internal fields. |
| client/src/test/java/com/microsoft/durabletask/TaskOrchestrationEntityEventTest.java | Add regression test for lock grants arriving via EventRaised (Azure Functions path). |
| client/src/test/java/com/microsoft/durabletask/EntityInstanceIdTest.java | Add Jackson round-trip tests for compact string EntityInstanceId JSON format. |
| client/src/main/java/com/microsoft/durabletask/TypedEntityMetadata.java | Add Jackson annotations to expose state and hide stateType. |
| client/src/main/java/com/microsoft/durabletask/TaskOrchestrationExecutor.java | Special-case lock grant handling for AutoCloseable tasks in handleEventRaised. |
| client/src/main/java/com/microsoft/durabletask/EntityMetadata.java | Add Jackson annotations to hide internal fields and expose entityId. |
| client/src/main/java/com/microsoft/durabletask/EntityInstanceId.java | Add Jackson serializer/deserializer for compact "@name@key" JSON representation. |
| client/build.gradle | Bump client module version to 1.9.0. |
| azuremanaged/build.gradle | Bump azuremanaged module version to 1.9.0. |
| azurefunctions/build.gradle | Bump azurefunctions module version to 1.9.0. |
sophiatev
previously approved these changes
Apr 22, 2026
sophiatev
approved these changes
Apr 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue describing the changes in this PR
Fixes three serialization/deserialization bugs affecting durable entities in the Azure Functions code path and adds .NET parity for
EntityInstanceIdJSON handling.1. Entity locking fails with deserialization error in Azure Functions
Bug: When an orchestration calls
ctx.lockEntities()in the Azure Functions code path, the lock grant arrives as anEventRaisedhistory event. During replay,handleEventRaised()attempts to deserialize the event payload asAutoCloseable.classvia Jackson. SinceAutoCloseableis an interface, Jackson throws:This caused any orchestration using
lockEntities()to fail on replay in Azure Functions. The DTS/emulator path was unaffected because lock grants arrive as protoEntityLockGrantedevents there, handled by a separate code path.Fix: Added a branch in
handleEventRaised()that checksmatchingTaskRecord.getDataType() == AutoCloseable.class. When detected, it skips Jackson deserialization and instead sets the critical section state (isInCriticalSection,lockedEntityIds) and completes the task withnull— mirroring whathandleEntityLockGranted()does for the proto path. Thenullvalue flows into thethenApplylambda inlockEntities(), which ignores it and returns theAutoCloseableunlock handle.Files changed:
TaskOrchestrationExecutor.javaTests added:
lockEntities_lockGrantedViaEventRaised_succeedsinTaskOrchestrationEntityEventTest.java2.
EntityInstanceIdfails Jackson deserialization when embedded in orchestration payloadsBug:
EntityInstanceIdhad no Jackson annotations, no default constructor, and no setters — only an immutable two-arg constructor. When users embed anEntityInstanceIdin an orchestration input POJO (e.g.,CounterPayload), Jackson cannot deserialize it during orchestration replay. The .NET SDK avoids this by registering a customJsonConverterthat serializesEntityInstanceIdas a compact"@name@key"string.Fix: Added
@JsonSerializeand@JsonDeserializeannotations toEntityInstanceIdwith innerSerializer/Deserializerclasses. These serialize to"@name@key"and deserialize viaEntityInstanceId.fromString(), matching the .NET SDK's compact string representation.Files changed:
EntityInstanceId.javaTests added:
jacksonSerialization_*andjacksonDeserialization_*tests inEntityInstanceIdTest.java3.
TypedEntityMetadatacannot be serialized in Azure Functions HTTP responsesBug: The Azure Functions Java worker uses Gson to serialize HTTP response bodies. When samples pass a
TypedEntityMetadata<T>object directly to.body(entity), Gson hits internal fields it cannot handle:Class<T> stateType→UnsupportedOperationException: Attempted to serialize java.lang.ClassDataConverter dataConverter→ not serializableFix (SDK): Added Jackson annotations to
EntityMetadataandTypedEntityMetadata:@JsonIgnoreonserializedState,dataConverter,stateType, and rawinstanceId@JsonProperty("entityId")ongetEntityInstanceId()(serializes via the newEntityInstanceIdserializer)@JsonProperty("state")ongetState()Fix (Samples): Changed
CounterFunctions,BankAccountFunctions, andLifetimeFunctionsto serialize vianew JacksonDataConverter().serialize(entity)before passing to.body(), ensuring Jackson annotations are respected instead of relying on Gson.Files changed:
EntityMetadata.java,TypedEntityMetadata.java,CounterFunctions.java,BankAccountFunctions.java,LifetimeFunctions.javaTests added:
jacksonSerialization_*tests inTypedEntityMetadataTest.javaTesting
TransferFundssample verified end-to-end — entity locking now works correctlyPull request checklist
CHANGELOG.md