Skip to content

fix(standard-server): settle sendStandardResponse when client disconnects before sending - #1738

Merged
dinwwwh merged 6 commits into
1.xfrom
claude/github-issue-1735-fe1a56
Jul 27, 2026
Merged

fix(standard-server): settle sendStandardResponse when client disconnects before sending#1738
dinwwwh merged 6 commits into
1.xfrom
claude/github-issue-1735-fe1a56

Conversation

@dinwwwh

@dinwwwh dinwwwh commented Jul 27, 2026

Copy link
Copy Markdown
Member

Fixes #1735

handle() hung forever when the client disconnected while the procedure was still running, because the response's 'close' event had already fired before sendStandardResponse() started listening for it.

Now:

  • sendStandardResponse (node, fastify, aws-lambda) settles immediately when the response is already ended and destroys the prepared body so event iterators are cleaned up.
  • toAbortSignal aborts immediately when the response is already closed, including http/2 client cancels.
  • Both detect an ended response via the new isNodeResponseStreamEnded util, which also handles Http2ServerResponse (it hides its stream state at runtime).

Verified with real http/1 and http/2 servers: aborted requests now resolve instead of hanging.

…ready closed

When the client disconnects while the procedure is still running, the
response's 'close' event has already fired before sendStandardResponse
registers its listeners, so the returned promise never settles and
anything awaited after handle() silently never runs.

- Add isNodeResponseStreamEnded util that detects an ended response for
  both http/1 and http/2 (Http2ServerResponse does not expose
  closed/destroyed at runtime, they are read from its underlying
  Http2Stream instead)
- Settle sendStandardResponse immediately when the response is already
  ended (rejecting with the stream error if any) and destroy the
  prepared body so event iterators are cleaned up, in the node, fastify
  and aws-lambda implementations
- Make toAbortSignal abort when the response was already closed at call
  time, using writableEnded && writableFinished so http/2 client cancels
  are detected (Http2Stream force-ends its writable side on abnormal
  close)

Fixes #1735
@vercel

vercel Bot commented Jul 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
orpc Ready Ready Preview, Comment Jul 27, 2026 1:02pm

@pkg-pr-new

pkg-pr-new Bot commented Jul 27, 2026

Copy link
Copy Markdown
More templates

@orpc/ai-sdk

npm i https://pkg.pr.new/@orpc/ai-sdk@1738

@orpc/arktype

npm i https://pkg.pr.new/@orpc/arktype@1738

@orpc/client

npm i https://pkg.pr.new/@orpc/client@1738

@orpc/contract

npm i https://pkg.pr.new/@orpc/contract@1738

@orpc/experimental-durable-iterator

npm i https://pkg.pr.new/@orpc/experimental-durable-iterator@1738

@orpc/hey-api

npm i https://pkg.pr.new/@orpc/hey-api@1738

@orpc/interop

npm i https://pkg.pr.new/@orpc/interop@1738

@orpc/json-schema

npm i https://pkg.pr.new/@orpc/json-schema@1738

@orpc/nest

npm i https://pkg.pr.new/@orpc/nest@1738

@orpc/openapi

npm i https://pkg.pr.new/@orpc/openapi@1738

@orpc/openapi-client

npm i https://pkg.pr.new/@orpc/openapi-client@1738

@orpc/otel

npm i https://pkg.pr.new/@orpc/otel@1738

@orpc/experimental-pino

npm i https://pkg.pr.new/@orpc/experimental-pino@1738

@orpc/experimental-publisher

npm i https://pkg.pr.new/@orpc/experimental-publisher@1738

@orpc/experimental-publisher-durable-object

npm i https://pkg.pr.new/@orpc/experimental-publisher-durable-object@1738

@orpc/experimental-ratelimit

npm i https://pkg.pr.new/@orpc/experimental-ratelimit@1738

@orpc/react

npm i https://pkg.pr.new/@orpc/react@1738

@orpc/react-query

npm i https://pkg.pr.new/@orpc/react-query@1738

@orpc/experimental-react-swr

npm i https://pkg.pr.new/@orpc/experimental-react-swr@1738

@orpc/server

npm i https://pkg.pr.new/@orpc/server@1738

@orpc/shared

npm i https://pkg.pr.new/@orpc/shared@1738

@orpc/solid-query

npm i https://pkg.pr.new/@orpc/solid-query@1738

@orpc/standard-server

npm i https://pkg.pr.new/@orpc/standard-server@1738

@orpc/standard-server-aws-lambda

npm i https://pkg.pr.new/@orpc/standard-server-aws-lambda@1738

@orpc/standard-server-fastify

npm i https://pkg.pr.new/@orpc/standard-server-fastify@1738

@orpc/standard-server-fetch

npm i https://pkg.pr.new/@orpc/standard-server-fetch@1738

@orpc/standard-server-node

npm i https://pkg.pr.new/@orpc/standard-server-node@1738

@orpc/standard-server-peer

npm i https://pkg.pr.new/@orpc/standard-server-peer@1738

@orpc/svelte-query

npm i https://pkg.pr.new/@orpc/svelte-query@1738

@orpc/tanstack-query

npm i https://pkg.pr.new/@orpc/tanstack-query@1738

@orpc/trpc

npm i https://pkg.pr.new/@orpc/trpc@1738

@orpc/valibot

npm i https://pkg.pr.new/@orpc/valibot@1738

@orpc/vue-colada

npm i https://pkg.pr.new/@orpc/vue-colada@1738

@orpc/vue-query

npm i https://pkg.pr.new/@orpc/vue-query@1738

@orpc/zod

npm i https://pkg.pr.new/@orpc/zod@1738

commit: 06a9b09

@codecov

codecov Bot commented Jul 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

dinwwwh added 3 commits July 27, 2026 19:16
Cover the remaining early-exit paths when the response is already ended:
rejecting with the response's error and settling with a non-stream body.

@pullfrog pullfrog Bot 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.

✅ No new issues found.

Reviewed changes — fixes an event-race bug where sendStandardResponse never settles when the client disconnects before sending, blocking cleanup and logging after handle().

  • Add isNodeResponseStreamEnded utility — detects whether a writable response stream can no longer be written to (closed || destroyed || writableFinished). For Http2ServerResponse, reads flags from the underlying Http2Stream because the compat API does not expose them at runtime.
  • Early-return in sendStandardResponse (node, fastify, aws-lambda) — checks end-of-stream at entry and settles immediately, destroying the body stream so generator finally blocks still run. Rejects with errored when set, resolves otherwise.
  • Fix toAbortSignal for already-closed streams — same early-check pattern with writableEnded && writableFinished guard for http2 compat, where writableFinished alone would report as finished even on abnormal close.
  • Export utils from @orpc/standard-server-node

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@pullfrog pullfrog Bot 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.

✅ No new issues found.

Reviewed changes — two incremental improvements since the prior review: added the missing errored-case test for the Fastify adapter, and inlined the isFinishedWriting helper in toAbortSignal.

  • Add rejects when response was destroyed with an error test for Fastify — fills the coverage gap; the node and aws-lambda adapters already had this test.
  • Inline isFinishedWriting in toAbortSignal — replaces the extracted function with inline !stream.writableFinished || !stream.writableEnded, which is De Morgan equivalent. Removes the http2 compat comment since the intent is clear from the condition itself.

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@pullfrog pullfrog Bot 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.

✅ No new issues found.

Reviewed change — one additional test in the Fastify adapter to match existing coverage in the node and aws-lambda adapters.

  • Add resolves when body is not a stream test for Fastify — covers the already-closed path with a plain object body (no stream cleanup needed). Matches the equivalent tests already present for node and aws-lambda.

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@dinwwwh
dinwwwh force-pushed the claude/github-issue-1735-fe1a56 branch from 9979bf4 to bd98a72 Compare July 27, 2026 12:58
@dinwwwh
dinwwwh merged commit a0d7d76 into 1.x Jul 27, 2026
6 checks passed
@dinwwwh
dinwwwh deleted the claude/github-issue-1735-fe1a56 branch July 30, 2026 02:44
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.

1 participant