Skip to content

Fix large-payload recovery and export-history parity with .NET - #304

Open
Varshitha Bachu (bachuv) wants to merge 2 commits into
mainfrom
vabachu/fix-java-payload-export-parity
Open

Varshitha Bachu (bachuv) wants to merge 2 commits into
mainfrom
vabachu/fix-java-payload-export-parity

Conversation

@bachuv

@bachuv Varshitha Bachu (bachuv) commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

Issue describing the changes in this PR

Follow-up to #280 and #293. Addresses three behavioral differences from .NET that existed when the Java large-payload and export-history features were merged.

Pull request checklist

  • My changes do not require documentation changes
    • Otherwise: Documentation issue linked to PR
  • My changes are added to the CHANGELOG.md
  • I have added all required tests (Unit tests, E2E tests)

Additional information

Changes

  • Recreate deleted payload containers and retry new uploads once. Generation-aware cache invalidation prevents stale concurrent failures from invalidating a container another upload has already recreated.
  • Preserve sub-millisecond timestamps in orchestration history and client metadata so exported timestamps and blob filenames do not diverge from .NET due to truncation. Existing orchestration replay timestamp behavior remains unchanged.
  • Align the exported JSON for entity operations and locks with .NET’s history format. This changes only their representation in export files; the Java history API continues returning the same Java event classes

Validation

  • Added regression coverage for container recovery, concurrent failures, timestamp precision, and export formatting.
  • Added test-only golden fixtures generated using .NET history conversion and DurableTask.Core 3.9.0.
  • All 185 scoped tests passed: 43 client, 79 large-payload, and 63 export-history tests.

Compatibility

The preview entity-export format changes from Java-native entity objects to the .NET-compatible representation. Re-exporting instances previously named using millisecond-truncated timestamps may create different blob names; existing blobs are not renamed or removed.

Copilot AI lite review requested due to automatic review settings September 22, 2026 20:43
@bachuv
Varshitha Bachu (bachuv) requested a review from a team as a code owner September 22, 2026 20:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Entity serialization must preserve standard short escapes for five control characters to maintain byte-for-byte parity.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 1 Medium severity

Open (1)
What changed in this PR

This PR fixes large-payload recovery, preserves timestamp precision, and aligns entity-history exports with .NET behavior.

Changes:

  • Adds generation-aware container recreation and upload retry.
  • Preserves sub-millisecond timestamps.
  • Updates entity export serialization and regression coverage.
File Summary
exporthistory/​src/​test/​resources/​golden/​reference-entity-history-events.jsonl Adds golden entity-history fixtures.
exporthistory/​src/​test/​java/​com/​microsoft/​durabletask/​exporthistory/​HistoryEventSerializerTest.java Tests entity serialization behavior.
exporthistory/​src/​test/​java/​com/​microsoft/​durabletask/​exporthistory/​HistoryEventSerializerParityTest.java Tests .NET serialization parity.
exporthistory/​src/​test/​java/​com/​microsoft/​durabletask/​exporthistory/​ExportInstanceHistoryActivityTest.java Tests export activity behavior.
exporthistory/​src/​test/​java/​com/​microsoft/​durabletask/​exporthistory/​ExportBlobNamingTest.java Tests precise blob naming.
exporthistory/​src/​main/​java/​com/​microsoft/​durabletask/​exporthistory/​HistoryEventSerializer.java Implements entity-history serialization.
exporthistory/​src/​main/​java/​com/​microsoft/​durabletask/​exporthistory/​ExportBlobNaming.java Preserves timestamp precision in names.
exporthistory/​README.md Documents export format changes.
client/​src/​test/​java/​com/​microsoft/​durabletask/​OrchestrationMetadataTest.java Tests metadata timestamp precision.
client/​src/​test/​java/​com/​microsoft/​durabletask/​HistoryEventConverterTest.java Tests precise history conversion.
client/​src/​main/​java/​com/​microsoft/​durabletask/​OrchestrationMetadata.java Preserves metadata timestamp precision.
client/​src/​main/​java/​com/​microsoft/​durabletask/​HistoryEventConverter.java Preserves history timestamp precision.
client/​src/​main/​java/​com/​microsoft/​durabletask/​Helpers.java Supports precise protobuf timestamps.
CHANGELOG.md Records the behavioral changes.
azure-blob-payloads/​src/​test/​java/​com/​microsoft/​durabletask/​azureblobpayloads/​BlobPayloadStoreTest.java Tests container recovery and concurrency.
azure-blob-payloads/​src/​main/​java/​com/​microsoft/​durabletask/​azureblobpayloads/​BlobPayloadStore.java Adds container recovery and retry logic.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The real protobuf conversion path turns absent failure stack traces into empty strings, breaking the promised entity-export parity.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 2 Medium severity

Open (2)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The concurrency, timestamp, and serialization changes are internally consistent and covered by focused regression tests.

Review effort: Balanced
Findings: None

Resolved since last review (2)

@YunchuWang wangbill (YunchuWang) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes for one remaining value-level mismatch in the new .NET-compatible entity-failure export. Reviewed commit 5ec000e88240e91f62d19e3769662a800baf4974.

result.put("StackTrace", failure.getStackTrace());
result.put("InnerFailure", entityFailureMap(failure.getInnerFailure()));
result.put("IsNonRetriable", failure.isNonRetriable());
result.put("Properties", failure.getProperties() == null ? Collections.emptyMap() : failure.getProperties());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Decode date-valued failure properties in the export projection

Copying failureDetails.getProperties() directly preserves the dt:/dto: transport prefixes that .NET uses for date-valued properties. Java's protobuf conversion leaves those strings unchanged, whereas the reference .NET conversion recursively decodes them before Newtonsoft serializes the entity response. For example, a streamed EntityOperationFailed property containing dt:2026-06-30T12:00:00.0000000Z exports with that prefix here, but as 2026-06-30T12:00:00Z in .NET. Consumers parsing the reference ISO date value therefore receive a different, non-date string.

Please add an export-local recursive property projection matching the reference date decoding/formatting, preserving ordinary and invalid tagged strings, and extend the streamed-history parity cases to include dt:, dto:, nested maps/lists, and inner failures. This can fix the new export representation without changing the public Java FailureDetails contract.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants