Skip to content

Track outstanding attachment blob work in BlobManager. - #28357

Open
Jatin Garg (jatgarg) wants to merge 2 commits into
microsoft:mainfrom
jatgarg:jatgarg/track-outstanding-blob-work
Open

Jatin Garg (jatgarg) wants to merge 2 commits into
microsoft:mainfrom
jatgarg:jatgarg/track-outstanding-blob-work

Conversation

@jatgarg

Copy link
Copy Markdown
Contributor

Description

Adds a complete BlobManager-owned view of attachment blobs whose sharing has started but has not finished.

This is independently testable preparation for AB#81181. Nothing subscribes to the new event in this PR, so it does not yet change ContainerRuntime.isDirty, "dirty", or "saved". The later activation PR will consume this state only after the separate loader/runtime op-state foundation has landed.

BlobManager now tracks outstanding work in an idempotent Set keyed by local blob ID. A blob enters when BlobManager takes responsibility for sharing it and leaves when:

  • its BlobAttach operation is processed;
  • upload terminates through a non-retriable failure; or
  • sharing is aborted.

It remains continuously tracked across upload completion, TTL-driven re-upload, disconnect, and BlobAttach resubmission. Referenced blobs restored from pending local state are tracked immediately, before sharing resumes. Merely creating and dropping a payload-pending handle does not start tracking.

The acknowledgement boundary matters because storage upload alone does not make the service retain the blob. Processing BlobAttach publishes the local-to-storage ID mapping and establishes temporary retention until a summary sustains the reference.

The Set makes duplicate start/stop paths safe: restored sharing may start after construction, and successful completion is observed both synchronously during BlobAttach processing and later by the upload promise's finally.

This PR also fixes a pre-existing cleanup gap when storage.createBlob() throws synchronously. The synchronous path now performs the same listener, cache, and pending-handle cleanup as an asynchronously rejected upload.

The new accessor and event are internal. No customer-facing API report changes are generated, and no changeset is included because container behavior is not activated here.

WillieHabi and others added 2 commits September 30, 2026 12:06
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 90f3ba4d-f966-4ac8-a85c-168c32014877
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 90f3ba4d-f966-4ac8-a85c-168c32014877
Copilot AI balanced review requested due to automatic review settings September 30, 2026 19:14
@github-actions github-actions Bot added area: tools area: runtime Runtime related issues area: repo Repo related work area: website base: main PRs targeted against main branch labels Sep 30, 2026

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 lifecycle tracking is internally consistent and comprehensively covers success, retry, restoration, failure, and abort paths.

Review effort: Balanced
Findings: None

What changed in this PR

Adds BlobManager-owned tracking for attachment blobs whose sharing is incomplete, including restored pending blobs and terminal cleanup paths.

Changes:

  • Adds outstanding-blob count, state accessor, and change event.
  • Preserves tracking across retries and resubmissions until BlobAttach processing.
  • Adds comprehensive lifecycle tests and synchronous storage-failure cleanup.
File Description
blobManager.ts Implements outstanding-work tracking and synchronous failure cleanup.
index.ts Exports the internal event interface.
blobManager.spec.ts Tests tracking across creation, failure, abort, retry, and resubmission.
pendingBlobs.spec.ts Tests tracking for restored pending blobs.
blobTestUtils.ts Adds storage overrides and transition-recording helpers.

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

@github-actions

Copy link
Copy Markdown
Contributor

Hi! Thank you for opening this PR. Want me to review it?

Based on the diff (646 lines, 5 files), I've queued these reviewers:

  • Correctness — logic errors, race conditions, lifecycle issues
  • Security — vulnerabilities, secret exposure, injection
  • API Compatibility — breaking changes, release tags, type design
  • Performance — algorithmic regressions, memory leaks
  • Testing — coverage gaps, hollow tests
  • Documentation / Developer Experience — missing or misleading docs, examples, and developer-facing guidance

How this works

  • Adjust the reviewer set by ticking/unticking boxes above. Reviewer toggles alone don't trigger anything.

  • Tick Start review below to dispatch the review fleet.

  • After review finishes, tick Start review again to request another run — it auto-resets after each dispatch.

  • This comment updates as new commits land; your reviewer selections are preserved.

  • Start review

@github-actions

Copy link
Copy Markdown
Contributor

Bundle size comparison

Base commit: 071fa2a90080b9e8996a6dbe86c183dea6815aeb
Head commit: bec68a014a70a39a948840e650084d1aa02f0402

Notable changes

  • 🔴 azureClient.js: parsed 639323 → 640027 (+704), gzip 171407 → 171650 (+243)
  • 🔴 odspClient.js: parsed 611282 → 612100 (+818), gzip 164329 → 164616 (+287)
  • 🔴 aqueduct.js: parsed 537762 → 538484 (+722), gzip 144535 → 144740 (+205)
  • 🔴 containerRuntime.js: parsed 319667 → 320359 (+692), gzip 87713 → 87887 (+174)
Per-bundle deltas

@fluid-example/bundle-size-tests

  • fluidFrameworkAllAlpha.js: parsed 808569 → 808625 (+56), gzip 222612 → 222656 (+44)
  • 🔴 azureClient.js: parsed 639323 → 640027 (+704), gzip 171407 → 171650 (+243)
  • 🔴 odspClient.js: parsed 611282 → 612100 (+818), gzip 164329 → 164616 (+287)
  • 🔴 aqueduct.js: parsed 537762 → 538484 (+722), gzip 144535 → 144740 (+205)
  • fluidFramework.js: parsed 416356 → 416389 (+33), gzip 118067 → 118103 (+36)
  • sharedTree.js: parsed 405735 → 405761 (+26), gzip 115513 → 115531 (+18)
  • 🔴 containerRuntime.js: parsed 319667 → 320359 (+692), gzip 87713 → 87887 (+174)
  • sharedString.js: parsed 170105 → 170112 (+7), gzip 48455 → 48462 (+7)
  • experimentalSharedTree.js: parsed 161846 → 161846 (0), gzip 46722 → 46722 (0)
  • matrix.js: parsed 153720 → 153727 (+7), gzip 44381 → 44388 (+7)
  • loader.js: parsed 147328 → 147344 (+16), gzip 40039 → 40047 (+8)
  • odspDriver.js: parsed 106728 → 106786 (+58), gzip 33236 → 33304 (+68)
  • directory.js: parsed 65669 → 65676 (+7), gzip 18493 → 18501 (+8)
  • 578.js: parsed 58686 → 58686 (0), gzip 17657 → 17657 (0)
  • odspPrefetchSnapshot.js: parsed 46463 → 46444 (-19), gzip 15512 → 15522 (+10)
  • map.js: parsed 45820 → 45827 (+7), gzip 14120 → 14126 (+6)
  • 252.js: parsed 44384 → 44384 (0), gzip 13741 → 13741 (0)
  • summarizerDelayLoadedModule.js: parsed 31287 → 31287 (0), gzip 7929 → 7929 (0)
  • socketModule.js: parsed 27108 → 27078 (-30), gzip 8069 → 8103 (+34)
  • createNewModule.js: parsed 12464 → 12464 (0), gzip 4792 → 4805 (+13)
  • summaryModule.js: parsed 3888 → 3888 (0), gzip 1874 → 1874 (0)
  • connectionState.js: parsed 909 → 909 (0), gzip 500 → 500 (0)
  • sharedTreeAttributes.js: parsed 845 → 852 (+7), gzip 496 → 505 (+9)
  • debugAssert.js: parsed 429 → 429 (0), gzip 299 → 299 (0)
  • FluidFramework-HashFallback.js: parsed 419 → 419 (0), gzip 313 → 313 (0)

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

Labels

area: repo Repo related work area: runtime Runtime related issues area: tools area: website base: main PRs targeted against main branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants