Waking Up Databases Without Dead Connections
A published app waking from sleep held its first request 10–12 seconds on database connections that died while it slept. How we got it to 2.3 seconds.
Mythex Team · · 4 min read
Published apps on Mythex, and their databases, go to sleep when nobody is using them. When an app woke up, it could hold its first request for 10–12 seconds, because it tried to reuse database connections that had died while everything slept. We now give Spring Boot apps database settings that are safe across sleep, and tell the agent to build apps of any stack the same way. On the hosting platform, the first request after a wake went from 12.7 seconds to 2.3 seconds.
Why apps and databases sleep
A published Mythex app runs on a machine that suspends after a few idle minutes, and its database is serverless Postgres that sleeps after five idle minutes and wakes on the next request. That's what keeps a quiet app cheap: you're charged for what the database actually used, and a sleeping app spends nothing on compute. We wrote about the billing side in billing databases by what they actually use.
The catch is that the two sleep separately, and they don't agree about what a connection is.
The symptom: a slow first visit
Most server apps keep a connection pool: a handful of open database connections kept ready, so each request doesn't pay the cost of opening a new one. That's the right design for an app that's always on.
Here's what happens with sleep:
- The app is running, with a few idle connections in its pool.
- Nobody visits. The app's machine suspends — frozen, with its pool intact.
- The database goes to sleep and drops its end of every connection.
- A visitor arrives. The app wakes up exactly as it was, still holding connections the database no longer knows about.
- The pool hands out one of those connections. It has to find out it's dead — by trying it and waiting — before giving up on it.
In a Spring Boot app, validating those dead connections blocked the first request for around 10 seconds before it failed with "Connection is not available". To the visitor, the site simply hung, and then maybe showed an error.
Why Spring apps got it worst
Spring Boot is a popular Java framework, and it uses a connection pool called HikariCP by default. Spring can configure that pool from settings, including how many idle connections to keep.
But Mythex gives every app its database as a single DATABASE_URL in the form postgresql://user:pass@host/db. Spring can't read that format directly. So Spring apps built on Mythex were constructing their own pool in code by parsing that URL — and a pool built by hand ignores all of Spring's spring.datasource.* settings. Even if someone knew the right pool settings, there was nowhere they'd take effect.
The fix, part 1: settings Spring can use
When a project has a database, we now also give it environment variables Spring reads natively:
SPRING_DATASOURCE_URL,SPRING_DATASOURCE_USERNAMEandSPRING_DATASOURCE_PASSWORD, converted fromDATABASE_URL(with SSL required unless the URL says otherwise).- Pool settings that survive sleep:
| Setting | Value | Why |
|---|---|---|
| Minimum idle connections | 0 | Keep nothing open between requests, so there's nothing to go stale |
| Idle timeout | 30 seconds | Close unused connections soon |
| Maximum lifetime | 2 minutes | Retire every connection before it can get old |
| Connection timeout | 5 seconds | Don't hang a request for long if the database is slow to answer |
With no idle connections held, a woken app opens one fresh connection instead of wading through dead ones.
With these variables present, Spring configures the pool itself, and the settings apply. Anything the project has set itself always wins; we only fill in what's missing. Apps that aren't Spring ignore these variables.
The detail that almost made it do nothing
Spring maps environment variables onto its settings by a rule that's easy to get wrong. The setting minimum-idle has to be written as SPRING_DATASOURCE_HIKARI_MINIMUMIDLE — dashes dropped, words run together. Writing it as SPRING_DATASOURCE_HIKARI_MINIMUM_IDLE, which looks more natural, maps to a different, non-existent setting (minimum.idle) and is silently ignored.
That's the kind of mistake that passes every review and does nothing in production. So a test checks both that the values are set and that no variable uses the underscore-separated form.
The fix, part 2: every other stack
Spring isn't the only framework with a pool, and we can't pre-configure every library in every language. So the Mythex agent — the AI that writes your app — now gets a standing instruction for any stack: published apps and their databases sleep when idle, so a connection kept open can be dead on the next request. It should:
- keep no idle database connections open, or check each one before use,
- retry once on a connection error, and
- use the database settings the platform provides in the environment, rather than building its own pool by parsing
DATABASE_URL.
That last point closes the loop with part 1: an app built on the provided settings picks up the sleep-safe configuration automatically.
The result
Measured on the hosting platform we run published apps on, the first request after a wake went from 12.7 seconds to 2.3 seconds.
What we took from it
- Every layer that sleeps needs to agree on what survives. A frozen app and a sleeping database each made a reasonable choice. Together, the app woke up holding state that was no longer true.
- Defaults designed for always-on servers don't fit apps that scale to zero. Keeping connections warm is a good idea until everything around them goes cold.
- Give frameworks their data in their own format. One URL was simple for us and forced every Spring app to hand-roll a pool that ignored its own configuration.
- Test that a setting is spelled the way the framework reads it. A correct value under the wrong name does nothing, silently.
If you're new to how databases work on Mythex, see the database docs and our explainer on what Postgres is.