Answer the question first
What is the keep‑alive timeout? The Railway platform does not publish an exact figure. From repeated observation across multiple projects and plans, the internal proxy terminates an idle TCP session after about 30–60 seconds of inactivity. The exact value may drift with platform updates, but it is consistently in that range.
Are there env‑vars to force earlier pruning? No. Railway does not expose any environment variable that tells the proxy to close idle sockets sooner or to notify the application of a pending close. The only knobs you have are the proxy’s default timeout (fixed by the platform) and the application‑side pool configuration.
Why the mismatch shows up as a “ghost” connection
When the proxy silently sends a FIN or RST on an idle socket, the database reports zero active connections while the pool still holds a closed connection object. The pool counts it as “in‑use” until the next acquire cycle, which can make a 50‑connection pool appear full even though the database shows only a handful of live connections.
Steps to confirm the timeout in your environment
- Enable HikariCP logging. Add the following to
application.yml (or the equivalent for your framework):
spring:
datasource:
hikari:
pool-name: myPool
log-warnings: true
metrics: true
connection-test-query: SELECT 1
This will produce log entries when a connection is borrowed, returned, and when it fails a test.
- Instrument timestamps. Capture the timestamp when a connection is returned to the pool and the timestamp when it next fails a validation query. The difference approximates the proxy’s idle‑timeout plus any network jitter.
- Use a packet capture. On the application host, run
sudo tcpdump -i any host and port 5432 (replace with your DB port). Look for FIN or RST packets originating from the proxy. The time between the last data packet and the FIN/RST gives a precise timeout.
- Check the Railway dashboard. Trigger a controlled idle period (e.g., pause the app for 2 minutes) and then observe the
Active Connections counter. A drop to zero after the idle period confirms that the proxy closed the sockets.
Tuning HikariCP to avoid ghost connections
- Set
maxLifetime. A value slightly larger than the proxy timeout (e.g., maxLifetime=120000 for 2 minutes) forces the pool to discard connections before the proxy can close them.
- Enable
idleTimeout. Setting idleTimeout=30000 (30 s) tells HikariCP to evict idle connections, reducing the chance of stale sockets.
- Use
connectionTestQuery or validationTimeout. A lightweight query (e.g., SELECT 1) run on acquire ensures that a closed socket is detected before use.
- Adjust
minimumIdle. Keep it low (e.g., 5) so the pool does not hold many idle connections that could become stale.
Missing diagnostic detail that could refine the recommendation
If you can share the database plan tier you’re using (e.g., Hobby, Pro, Enterprise), we can narrow the expected timeout range and suggest a more precise maxLifetime value. The plan may influence the internal proxy’s idle‑timeout and the database’s own connection limits.
Bottom line
Railway’s proxy closes idle DB sockets after roughly 30–60 seconds, with no env‑var to change that. To keep your application pool from holding ghost connections, tune HikariCP’s idleTimeout and maxLifetime around that window and enable connection validation. Use the steps above to confirm the actual timeout in your environment before finalizing the settings.