Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

g-cloudflare: large single statement (~124KB) reliably kills the connection on Cloudflare Workers - "Connection terminated unexpectedly"

未关闭
#3,757 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
4/5
预计耗时
3-5 天
新手友好度
48/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
活跃
技术栈
javascript, postgresql

调研方向

首先检查 issue 中描述的 pg-cloudflare 的 CloudflareSocket.write() 和 destroy() 路径。使用约 ~124KB 的 statement 在已部署的 Worker 中重现,然后与成功的约 ~25KB chunk 进行比较,并观察底层写入错误是否会暴露出来。当大块写入能够通过 Workers streams API 成功,或其实际错误能够传递到应用程序时,即表示完成。

由索引模型根据 Issue 内容生成。

描述

Environment

  • pg: 8.16.3 (bundled pg-cloudflare 1.3.0; the socket write path is unchanged in 1.4.0)
  • Runtime: Cloudflare Workers, production (connect() TCP sockets, TLS)
  • Consumer: Prisma @prisma/adapter-pg 6.x → pg.Pool
  • Server: Supabase Postgres behind Supavisor transaction pooler (port 6543)

Summary

A single parameterized statement whose wire message is large (~124KB of bind parameters in our case) deterministically fails from a deployed Worker with:

Error: Connection terminated unexpectedly
    at <bundle>
    at async PgTransaction.performIO
    at async PgTransaction.executeRaw

Small statements on the same connection, milliseconds earlier, succeed. The failure reproduces 100% of the time, including on a freshly opened connection (new pool, single connection, TLS handshake and auth complete, BEGIN and a small SELECT set_config(...) succeed first).

What the server sees

This is the part that localizes the bug to the client side:

  • Postgres logs: nothing at all at the failure timestamps (no error, no crash, no statement logged).

  • Supavisor (pooler) logs:

    ClientHandler: (ECLIENTSOCKETCLOSED) Client socket closed while state was busy (transaction)
    

    i.e. from the server's perspective, the client closed the socket mid-statement. The connection is not being dropped by the pooler or the database — pg (or the Workers socket underneath it) is aborting its own connection while flushing the large message, and then reporting the resulting close as "Connection terminated unexpectedly". The underlying write error, if any, is never surfaced to the application.

Reproduction

Observed shape (via Prisma's pg adapter, but the adapter is a thin passthrough to pg):

// Deployed Worker (not wrangler dev), pg.Pool({ max: 5 }), TLS to Supabase pooler
await client.query('BEGIN')
await client.query("SELECT set_config('request.jwt.claims', $1, TRUE)", [claimsJson]) // ~600B — OK
await client.query(bigInsertSql, bigParams) // ~124KB of array params — connection dies in ~100-200ms

The failing statement is a CTE INSERT ... SELECT FROM unnest($1::uuid[], $2::text[], ...) with ~30 array parameters totaling ~124KB (about 650 rows across 5 tables). Nothing exotic about the SQL itself:

  • The identical statement pattern with smaller arrays succeeds.
  • The identical data split into chunked statements of ~25KB each (200 rows per unnest), inside the same interactive transaction, succeeds 100% of the time. This is our current workaround.
  • Retrying on a brand-new connection fails identically (~100-200ms after the statement is sent), so it is not a stale/idle-socket problem.

I don't have an exact byte threshold; payloads that historically stayed well under ~64KB never failed, ~124KB fails every time.

Suspected cause

pg-cloudflare's CloudflareSocket.write() forwards the entire buffer to a WritableStreamDefaultWriter.write() and returns true immediately — there is no backpressure handling:

write(data, encoding, callback) {
  ...
  this._cfWriter!.write(data).then(
    () => callback(),
    (err) => callback(err)
  )
  return true
}

and destroy() tears down via end() → _cfSocket.close(), which produces exactly the abrupt client-side close the pooler logs. If the runtime's writer rejects or aborts on a large write, the error is only visible to the app as the generic post-close "Connection terminated unexpectedly", which made this quite painful to diagnose.

Expected behavior

Either the large write succeeds (with backpressure/chunking as needed for the Workers streams API), or the actual write error is propagated so the application can see why the connection died.

Notes

  • Reproduced only in production Workers; I have not verified whether local wrangler dev behaves the same.
  • Happy to provide more logs/timings or test patches.
主要语言
JavaScript
星标
13.2k
派生
1.4k
平均合并
6 天 15 小时
30 天内合并 PR
6

贡献指南

这个仓库没有索引到贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

brianc/node-postgres 的其他 Issue

查看 brianc/node-postgres 的全部 Issue

相似的 Issue

更多 JavaScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。