stack: the HTTP gateway closes idle keep-alive connections after 5 s, so a client whose event loop is blocked gets ECONNRESET (`fetch failed`) on its next request
Maintainer thường phản hồi trong vòng 1 ngày
@7ttp đang làm issue này rồi.
Từ ngày 3/10/2026.
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 84/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- node.js, typescript
Hướng nghiên cứu
Bắt đầu với packages/stack/src/HttpProxy.ts, đặc biệt là createServer(...) và comment hiện có về timeout của upstream Agent. Chạy bản tái hiện keepalive-race.mjs được cung cấp trên native stack và xác nhận rằng việc event loop phía client bị đình trệ lâu hơn năm giây không còn reset request tiếp theo. Keep-alive timeout phía client phải lớn hơn năm giây, đồng thời giữ headersTimeout lớn hơn giá trị đó.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Affected area
Local development
Supabase CLI version
2.119.0
Operating system
macOS 26.7 on Apple silicon, native runtime. First seen on a GitHub Actions ubuntu-latest runner (x64), native runtime.
Installation method
pnpm
Command
supabase start --runtime native # [experimental] stack = true in config.toml
Actual output
The stack's HTTP gateway (the listener behind API_URL) advertises a five-second idle timeout on every response and closes an idle client connection after it:
$ curl -sI "$API_URL/rest/v1/" -H "apikey: $PUBLISHABLE_KEY"
HTTP/1.1 200 OK
server: postgrest/16.4
Connection: keep-alive
Keep-Alive: timeout=5
A Node client whose event loop is free is not affected: fetch's connection pool drops the idle socket in time, and sequential requests seconds apart all succeed. A client whose event loop is blocked for longer than five seconds between two requests on the same connection (a synchronous child process, a long GC pause) cannot do that; the gateway closes the socket first, the client writes its next request to it, and the request fails:
warm: 200
after 4 s with the event loop blocked: 200
warm: 200
after 6 s with the event loop blocked: fetch failed (ECONNRESET)
warm: 200
after 6 s with the event loop free: 200
Through supabase-js this surfaces as TypeError: fetch failed, with nothing about the cause. It first hit us in CI: an end-to-end seed called the Data API, ran two builds with execFileSync, and called the Data API again. It passed on a laptop, where the two builds took less than five seconds, and failed on an ubuntu-latest runner. The same seed had run unchanged against the Docker stack (Kong) for weeks.
Expected behavior
The gateway keeps an idle client connection long enough that a stall of a few seconds in a client does not become a connection reset, as the Docker stack's gateway did: an explicit keepAliveTimeout well above the runtime's five-second default, with headersTimeout kept above it.
Steps to reproduce
supabase start --runtime nativein a project with[experimental] stack = true.- Put
API_URLandPUBLISHABLE_KEYfromsupabase status --envin the environment. - Save the script below as
keepalive-race.mjsand runnode keepalive-race.mjs(Node 24.21.0 here). The request after a six-second block fails withECONNRESET; the same gap with the loop free succeeds.
import { execFileSync } from "node:child_process";
const url = `${process.env.API_URL}/rest/v1/`;
const headers = { apikey: process.env.PUBLISHABLE_KEY };
async function get(label) {
try {
const response = await fetch(url, { headers });
await response.text();
console.log(`${label}: ${response.status}`);
} catch (error) {
console.log(`${label}: ${error.message} (${error.cause?.code})`);
}
}
for (const seconds of [4, 6]) {
await get("warm");
execFileSync("sleep", [String(seconds)]); // blocks the event loop, as any synchronous work does
await get(`after ${seconds} s with the event loop blocked`);
}
await get("warm");
await new Promise((resolve) => setTimeout(resolve, 6000)); // the same gap with the loop free
await get("after 6 s with the event loop free");
Additional context
packages/stack/src/HttpProxy.ts(v2.119.0, unchanged ondevelop) creates the client-facing server withcreateServer(...)and sets nokeepAliveTimeout, so the runtime's default of five seconds applies. The same file already guards the gateway's own upstream connections against this race:new Agent({ keepAlive: true, timeout: 4_000 }), with the comment "Idle sockets close before Node upstreams' default 5 s keep-alive timeout can race a reuse." The client-facing side has no equivalent.- #6922 covered the upstream half of the gateway's connection handling; this is the client-facing half.
- We fixed our side by not blocking the event loop between requests, which is the right shape regardless, so this is a report rather than a blocker.
- Ngôn ngữ chính
- TypeScript
- Star
- 2.4k
- Fork
- 531
- Merge trung bình
- 1 ngày 4 giờ
- Pull request đã merge (30 ngày)
- 346
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của supabase/cli
-
db schema declarative sync: no way to fail (non-zero exit) when the generated migration is destructiveCó thể làm lại được Pull request cho issue này đã bị đóng mà không được merge. Đang mở✨ Feature supabase/cli
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
Maintainer thường phản hồi trong vòng 1 ngày
-
📘 Docs supabase/cli
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 88/100
supabase/cli#6974 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Migration error caret is missing or misplaced when the statement contains multibyte charactersĐang mở🐛 Bug supabase/cli
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
Maintainer thường phản hồi trong vòng 1 ngày
-
config push sends [auth.sms] enable_confirmations un-negated as sms_autoconfirm, so hosted projects get the opposite of localCó thể đã có người làm @7ttp đã nhận 3 ngày trước. Đang mở🐛 Bug supabase/cli
supabase/cli#6997 · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
stack: gateway still opens a new upstream connection per request on 2.119.0 (exhausts ephemeral ports on macOS)Có thể đã có người làm @rbSparky đã nhận 1 ngày trước. Đang mở🐛 Bug open-for-contribution supabase/cli
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 48/100
supabase/cli#6987 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
Issue tương tự
-
bug(sight): the dashboard's text truncations split surrogate pairs and show broken charactersĐang mởcomponent:sight
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
agentic-os-org/ANOLISA#6738 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug Durable Agents Observability (AI Telemetry) status: needs triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
mastra-ai/mastra#26470 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
paperclipai/paperclip#15630 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[good first issue, hacktoberfest] ⛩️ Add new Theme: Sakura Latte (good-first-issue)Có thể đã có người làm @PGrayCS đã nhận hôm nay. Đang mởcommunity first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
Độ khó 1/5 1-3 giờ Mức phù hợp với người mới 78/100
lingdojo/kana-dojo#31937 · 1 bình luận · 5 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày
-
feature/cohorts feature/feature-flags team/feature-flags
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 74/100
Maintainer thường phản hồi trong vòng 1 ngày