Skip to content

Fix hang when closing connections under load - #2575

Open
Nicolae Vartolomei (nvartolomei) wants to merge 1 commit into
Azure:mainfrom
nvartolomei:nv/do-not-hang
Open

Fix hang when closing connections under load#2575
Nicolae Vartolomei (nvartolomei) wants to merge 1 commit into
Azure:mainfrom
nvartolomei:nv/do-not-hang

Conversation

@nvartolomei

@nvartolomei Nicolae Vartolomei (nvartolomei) commented Jul 28, 2025

Copy link
Copy Markdown
fix: Prevent hang when client disconnects under load

In Azurite, all operations are managed through concurrent operation
queues. A bug was identified where operations could hang indefinitely if
the client disconnected before the operation was processed.

This occurred because Azurite would attempt to attach event handlers to
the request's readable stream (body) after it had already been closed by
the client's disconnection. Since a closed stream emits no further
events (like 'data', 'close', or 'error'), the operation would never
complete, causing a permanent hang.

This fix addresses the issue by checking if the request stream is still
readable before attaching any event handlers. This ensures that we only
process requests that are still active, preventing the hang and allowing
the queues to continue processing other operations.

Thanks for contribution! Please go through following checklist before sending PR.

PR Branch Destination

  • For Azurite V3, please send PR to main branch.
  • For legacy Azurite V2, please send PR to legacy-dev branch.

Always Add Test Cases

Make sure test cases are added to cover the code change.

Add Change Log

Add change log for the code change in Upcoming Release section in ChangeLog.md.

Development Guideline

Please go to CONTRIBUTION.md for steps about setting up development environment and recommended Visual Studio Code extensions.

@nvartolomei
Nicolae Vartolomei (nvartolomei) marked this pull request as draft July 28, 2025 16:07
@nvartolomei

This comment was marked as outdated.

@nvartolomei

This comment was marked as resolved.

@blueww

Copy link
Copy Markdown
Contributor

Nicolae Vartolomei (@nvartolomei)
Thanks for the contribution!
It would be better if you could also add changelog.

xiaonlimsft (@XiaoningLiu) , EmmaZhu-MSFT (@EmmaZhu),
Would you please help to review the PR?

…erationQueue processes the request

In Azurite, all operations are managed through concurrent operation
queues. A bug was identified where operations could hang indefinitely if
the client disconnected before the operation was processed.

This occurred because Azurite would attempt to attach event handlers to
the request's readable stream (body) after it had already been closed by
the client's disconnection. Since a closed stream emits no further
events (like 'data', 'close', or 'error'), the operation would never
complete, causing a permanent hang.

This fix addresses the issue by checking if the request stream is still
readable before attaching any event handlers. This ensures that we only
process requests that are still active, preventing the hang and allowing
the queues to continue processing other operations.
@rockwotj

Copy link
Copy Markdown

EmmaZhu-MSFT (@EmmaZhu) would be great to merge this!

@nvartolomei

Copy link
Copy Markdown
Author

Wei Wei (@blueww) mind taking another look at merging this? Anything blocking it?

@blueww

Copy link
Copy Markdown
Contributor

Akanksha Jain (@jainakanksha-msft)

Would you please help to review and approve if no issue found?

@jainakanksha-msft

Copy link
Copy Markdown
Member

Nicolae Vartolomei (@nvartolomei), could you please refresh the PR from main and address copilot comments if any

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.

Pull request overview

Fixes an indefinite hang in Azurite’s blob persistence write path by failing fast when an incoming request/body stream is already non-readable (e.g., client disconnected before the operation queue begins processing), and adds regression coverage plus a changelog entry.

Changes:

  • Add a readability guard in FSExtentStore.streamPipe() to reject immediately when the readable stream is already closed/destroyed.
  • Add a test that simulates an aborted/destroyed input stream to ensure appendExtent() does not hang.
  • Document the fix in the upcoming release changelog.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
tests/blob/fsStore.test.ts Adds a regression test for destroyed/aborted input streams during appendExtent().
src/common/persistence/FSExtentStore.ts Rejects early in streamPipe() when the input stream is not readable to prevent hanging operations.
ChangeLog.md Adds an “Upcoming Release” entry describing the hang fix.

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

Comment on lines +64 to +69
try {
await store.appendExtent(stream1);
assert.fail("Expected an error to be thrown due to destroyed stream");
} catch (err) {
assert.deepStrictEqual(err.message, "FSExtentStore:streamPipe() Readable stream is not readable.");
}
Comment on lines +526 to +529
reject(
new Error(
`FSExtentStore:streamPipe() Readable stream is not readable.`
));
assert.strictEqual(await readIntoString(readable3), "Test");
});

it("should handle garbage collected input stream during appendExtent @loki", async () => {
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.

6 participants