Skip to content

feat: [2/6] integrate payloads with clients workers and history - #389

Open
wangbill (YunchuWang) wants to merge 8 commits into
yunchuwang-payload-phase-1-corefrom
yunchuwang-payload-phase-2-sdk
Open

wangbill (YunchuWang) wants to merge 8 commits into
yunchuwang-payload-phase-1-corefrom
yunchuwang-payload-phase-2-sdk

Conversation

@YunchuWang

@YunchuWang wangbill (YunchuWang) commented Oct 16, 2026 •

Copy link
Copy Markdown
Member

Summary

What changed?

  • Add opt-in payload-aware client and worker options, unary request externalization and response hydration without changing the disabled transport path.
  • Hydrate work items and history chunks before user execution/conversion, apply streamed backpressure, propagate storage failures as retryable work, and handle large histories without variadic argument limits.
  • Await bounded, cancellation-aware abandonment of acquired work when payload processing fails without a converted business completion; tokenless host entrypoints preserve original errors.
  • Scope completion-wait deadline retries to scheduler RPC failures, not successful-response payload hydration or custom-store deadlines.
  • Centralize unary payload/metadata/RPC/hydration in _call. Scheduling, completion waits, rewind and restart supply only their RPC error-mapping/retry callbacks; storage/metadata/hydration errors retain their original identity.
  • Expose Azure-managed builder opt-in with core >=0.4.1 and configuration-preservation tests.
  • Use a custom in-memory PayloadStore in loopback gRPC tests. No Azure Blob provider, cleanup API, reserved task registration, or future purge import exists in this snapshot.

Why is this change needed?

  • Phase 2/6 of the requested large-payload implementation split. This PR's base is phase 1's branch, so its diff excludes previously reviewed phases.
  • Behavioral reference: durabletask-dotnet 91739687. The stack also inherits the reviewed JavaScript carryover and whole-message size-preflight repairs described below; it does not claim unchanged .NET failure-priority semantics.

Issues / work items

  • Resolves: N/A (user-requested phased feature review).
  • Related: original oversized PR #387. It is closed without merging; its original branch/history remain preserved.

Project checklist

  • Release notes are not required for the next release
    • Otherwise: Notes added to CHANGELOG.md
  • Backport is not required
    • Otherwise: Backport tracked by issue/PR #issue_or_pr
  • All required tests have been added/updated (unit tests, E2E tests)
  • Breaking change?
    • If yes:
      • Impact: The Azure-managed package now requires core >=0.4.1 for its public payload option types; core 0.4.0 is not a valid type/API provider.
      • Migration guidance: Publish the completed core 0.4.1 before the dependent package; do not release this partial phase.

AI-assisted code disclosure (required)

Was an AI tool used? (select one)

  • No
  • Yes, AI helped write parts of this PR (e.g., GitHub Copilot)
  • Yes, an AI agent generated most of this PR

If AI was used:

  • Tool(s): GitHub Copilot.
  • AI-assisted areas/files: This phase's source, regression tests, and directly related metadata/documentation.
  • What you changed after AI output: Split the implementation along independently buildable boundaries; retained focused regression evidence and removed unrelated formatting-only changes. Human review is still required.

AI verification (required if AI was used):

  • I understand the code and can explain it
  • I verified referenced APIs/types exist and are correct
  • I reviewed edge cases/failure paths (timeouts, retries, cancellation, exceptions)
  • I reviewed concurrency/async behavior
  • I checked for unintended breaking or behavior changes

These human attestations are intentionally left unchecked.


Testing

Automated tests

  • Current review head: f3ea69fc79eb594961ab4d57651f5e1360fb9127.
  • npm run test:unit -w @microsoft/durabletask-js -- --runTestsByPath test\client-error-cause.spec.ts test\client-wait.spec.ts test\client-wait-grpc.spec.ts test\payload-transport.spec.ts test\orchestration-id-reuse-policy.spec.ts test\client-options.spec.ts test\client-suspend-resume.spec.ts test\client-purge.spec.ts — 233 tests / 8 suites passed on this exact approved commit.
  • npm run build:core and npm run lint — passed. Scoped TypeScript/changelog formatting, commit-hook ESLint and git diff --check b4ddad9afa9f28d1ca9ebc510e5921074855cd56..HEAD passed.
  • TDD reproduced 18 remaining rewind/restart upload/metadata identity failures before production edits. The final suite adds 56 unique controls, including frozen/reused errors, actual scheduler causes, cancellation/backoff stages and metadata failure on a later retry.
  • The direct eligible-input control verifies one real in-memory upload across three RPC attempts, identical request/token, fresh metadata three times, two policy invocations and hydration only after success. Existing real-loopback scheduling/wait fixtures and old purge tests are unchanged; no sleep was added to hide default-dispatch changes.
  • Owning receipts: central-call-red.log, central-call-owning-final-green.log, central-call-final-build-lint.log, central-call-final-format-diff.log; failed intermediate fixture/timing logs are not presented as passing final evidence.
  • git diff --check origin/yunchuwang-payload-phase-1-core...HEAD — passed. Prior heads remain ancestors; predecessor bases, phase-local review scopes, release/cleanup/version notes and ready-for-review state are preserved.
  • Combined final on exact ae63cab8ecb6ec6b2b3e0e15067091a5b8a6b24e: npm run test:unit — 3,180 tests / 133 suites passed (core 2,028; Functions 226; Blob 39; Azure-managed 821; export-history 66). Ten opt-in service tests are skipped by this unit command.
  • On the same final head, npm run build passed all five workspaces and npm run lint passed. This is the true final aggregate containing both approved commits; the earlier stopped pre-lifecycle run is not a final pass.
  • Final structural/blob audit passed: one unary transport site and one upload/resolve site in _call; all five semantic callers delegate; phase4–6 client/lifecycle fixtures match the approved runner fix, and PR1 processor plus existing public-loopback fixtures are unchanged.
  • Final DTS live run: 39837123528 on exact ae63cab8ecb6ec6b2b3e0e15067091a5b8a6b24e — PENDING (in_progress) at 2026-10-22T19:07:38.5343134Z. The link is authoritative for later completion; no early pass is claimed.
  • PR388 source/body remain unchanged at 137bb547e8781fd84c2738c3e13ae0f65cd66174; its separately verified hosted evidence is 30 SUCCESS / 1 SKIPPED. Review approval is still required. Main-base-only PR filters are unchanged; absent stacked-PR jobs are not passes.
  • Scope limits remain: no live storage-outage or mixed .NET/JavaScript execution, no transactional rollback or generic orphan collector. Tombstone cleanup cannot discover blobs without a backend-recorded reference.

Manual validation (only if runtime/behavior changed)

  • Environment (OS, Node.js version, components): Windows, Node.js v24.14.0; loopback gRPC transport tests and provider-independent in-memory payload storage.
  • Steps + observed results:
    1. Materialized this phase on its declared predecessor, with no future-phase imports.
    2. Ran the exact owning checks above and inspected the incremental patch.
    3. Kept the original feature branch/history and primary user checkout unchanged.
  • Evidence (optional): Full local logs are session artifacts, not repository changes.

Notes for reviewers

Shared unary boundary correction

  • f3ea69fc79eb594961ab4d57651f5e1360fb9127 restores one private _call pipeline: combine cancellation once; externalize once; generate fresh metadata outside each RPC catch; invoke only the operation's RPC policy; hydrate once after success. true retries the RPC, false rethrows unchanged, and throwing maps a genuine RPC error with its cause. The no-metadata path preserves its original dispatch timing.
  • Scheduling and completion waits no longer inline separate pipelines; rewind/restart mappings use the same RPC-only boundary. Errors are not mutated or tagged and no public API, helper signature, dependency or middleware framework was added.
  • The separate auto-purge runner dedupe follow-up belongs to #391, not this phase.
  • All earlier reviewed carryover, UTF-8 preflight, token/cancellation, rewind mapping and worker-release repairs remain ancestors. No PR merge, package publication or history rewrite was performed.
Merge order Phase PR Base branch
1 Core contracts #388 main
2 SDK integration #389 yunchuwang-payload-phase-1-core
3 Azure Blob provider #390 yunchuwang-payload-phase-2-sdk
4 Purge protocol/client #391 yunchuwang-payload-phase-3-blob
5 Purge worker #392 yunchuwang-payload-phase-4-client
6 Release/usage/consumers #393 yunchuwang-payload-phase-5-worker

Merge 1 → 2 → 3 → 4 → 5 → 6. Each PR targets its predecessor; retarget the next PR only after its prerequisite merges. Do not publish packages or describe a partial phase as the complete feature.

  • This phase enables transparent transport using a supplied PayloadStore, but does not provide Azure Blob storage or cleanup.
  • Payload-aware work-item capability is advertised only when enabled. Cleanup filters and business-version exemptions are deliberately deferred to phase 5.
  • Full live DTS/mixed-.NET execution has not been run locally (Docker daemon unavailable). The final phase records aggregate local Blob/Azurite, source/wire interoperability and packed-consumer evidence without claiming absent hosted checks.

Phase 2 of 6: externalize outgoing payloads and await query, work-item and streamed history hydration before conversion or dispatch. Add Azure-managed builder opt-in and its core API peer floor, without importing the later Azure Blob provider or cleanup runner.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 81e20512-d3a2-4f8e-a574-f396140ec9c7
wangbill (YunchuWang) and others added 4 commits October 19, 2026 12:47
Inherit d5c9df7 carryover traversal and 55dfcf3 whole-message size preflight without rewriting phase history. Preserve the SDK phase boundary and all release notes.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 81e20512-d3a2-4f8e-a574-f396140ec9c7
Release acquired work through the captured task-specific abandon RPC after unconverted payload failures, preserving host errors and cancellation-aware bounded delivery.

Co-authored-by: Copilot App <[email protected]>

Copilot-Session: 2e5a9c41-aa30-4a1e-b176-22049e28af91
Hydrate successful wait responses outside scheduler deadline recovery so custom payload-store errors retain their original identity and cancellation.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 2e5a9c41-aa30-4a1e-b176-22049e28af91
Preserve the existing phase head and all approved SDK repairs while inheriting aeb598f recognized-token skipping and bee1313 aborted-signal precedence. No unrelated behavior or release metadata changes.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 81e20512-d3a2-4f8e-a574-f396140ec9c7
Comment thread packages/durabletask-js/src/client/client.ts
wangbill (YunchuWang) and others added 3 commits October 22, 2026 13:12
Keep payload externalization and metadata generation outside the startInstance error translation catch. Preserve original non-scheduler errors, real scheduler causes, scheduling options and stop cancellation, with real loopback regression coverage.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 2e5a9c41-aa30-4a1e-b176-22049e28af91
Combine approved scheduling RPC error-domain isolation with the exact approved rewind input mapping and regression tests. Preserve both source commits and the prior phase history.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 81e20512-d3a2-4f8e-a574-f396140ec9c7
Keep a single payload/metadata/RPC/hydration pipeline in _call. Invoke operation mapping or retry callbacks only for actual RPC failures; preserve original non-RPC errors and cancellation, per-attempt fresh metadata, one externalization/hydration, and no-generator dispatch timing. Route start, completion waits, rewind and restart through that shared boundary.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 2e5a9c41-aa30-4a1e-b176-22049e28af91
: signal;
effectiveSignal?.throwIfAborted();
if (this._payloads) await this._payloads.externalize(request, effectiveSignal);
while (true) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

what no max retries?

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants