feat(start): take --keepAliveTimeout, as next start does

Merged
K-
13h ago
+156-6

Summary

upwind's native server keeps Node.js's keep-alive default, as next start does. It closes an idle connection about 6 s after its last answer (a keepAliveTimeout of 5 s plus Node.js's 1 s buffer). A client that sends on a pooled connection just as the server closes it gets ECONNRESET. In deploy-tests on node (run 41382774099, shard 48/64), Playwright's API request on a prefetch in vary-params-base-dynamic failed this way.

This PR adds an option and leaves the default alone:

  • upwind start takes --keepAliveTimeout <ms>, spelled like next start --keepAliveTimeout: a whole number of milliseconds from 1 to 2147482647. Node.js arms an idle socket's timer at the timeout plus its 1 s buffer, so a longer value would overflow its timers. At 2147483647, every answer warned (TimeoutOverflowWarning) and the timer was clamped.
  • The CLI hands it to the server as UPWIND_NODE_KEEP_ALIVE_TIMEOUT. server.mjs also reads that variable when it is run directly, as it reads PORT and the other UPWIND_NODE_* variables.
  • When the option is unset, nothing changes.
  • deploy-tests starts the node target's server with 10 minutes. That is longer than any suite leaves a connection idle, and its clients do not resend when a pooled connection is reset.
  • The README describes the option, and when to set it above a proxy's idle timeout.

The same race inside the runtime's native bridge is fixed separately in #432.

Verification

  • A next-form fixture was built for node with this branch and served with upwind start.
    • Without the option, answers carried Keep-Alive: timeout=5, and a request 7 s after the previous one needed a new connection.
    • With --keepAliveTimeout 65000, answers carried Keep-Alive: timeout=65, and the same request reused the connection.
  • Unit tests cover:
    • the flag and its refusals, 2147482648 among them;
    • the environment variable, the process's taking precedence over a file's, and the flag over both;
    • the server's own parser.
  • On Node.js 24.22.1, a server with a keep-alive timeout of 2147483647 warned on its answer, and one with 2147482647 did not.
  • The adapter's native-listening tests, the upwind CLI project (415 tests) and the deploy-tests unit tests (186) pass. Typecheck, lint, format, knip and vocabulary pass.

Summary by cubic

Adds --keepAliveTimeout <ms> to upwind start, spelled and validated like next start's. It sets how long the server keeps an idle connection open after its last answer; unset, Node.js's default stands (about 6 seconds).

A client that sends on a pooled connection just as the server closes it gets ECONNRESET, which happened in a deploy-test on node. The CLI hands the value to the server as UPWIND_NODE_KEEP_ALIVE_TIMEOUT, which server.mjs also reads when run directly. deploy-tests now starts the node target's server with 10 minutes so suites' pooled clients avoid that race.

Details

  • The flag and the variable accept a whole number from 1 to 2147482647 ms; the flag wins over the process's variable, which wins over an env file's.
  • The top is one second below Node's timer limit, because Node adds its 1 s keep-alive buffer to the timeout.
  • --keepAliveTimeout is documented in the README, including setting it above a proxy's idle timeout.

Summary by CodeRabbit

  • New Features
    • Configure the native Node.js server’s idle connection timeout with --keepAliveTimeout <ms> or UPWIND_NODE_KEEP_ALIVE_TIMEOUT.
    • The timeout accepts whole-number values from 1 to 2,147,483,647 milliseconds. A command-line value takes precedence over the environment setting; when neither is set, Node.js uses its default.
  • Documentation
    • Added guidance on setting the timeout and its effect on idle connections.