Debugging PoolTimedOut with YugabyteDB, Docker, Rust, and GitHub Actions
Setting up an ephemeral database for integration tests sounds simple — until Docker, CI containers, and database drivers all collide.
Debugging PoolTimedOut with YugabyteDB, Docker, Rust, and GitHub Actions
Setting up an ephemeral database for integration tests sounds simple — until Docker, CI containers, and database drivers all collide.
This post walks through a real debugging journey of running Rust unit tests against YugabyteDB in GitHub Actions, where everything worked locally but consistently failed in CI with:
Unable to Create Connection With Postgres: PoolTimedOut
If you’ve ever dealt with Postgres-compatible databases, Docker Compose, and GitHub Actions job containers, this story will probably feel familiar.
The Goal
- Run Rust unit tests (
cargo test) - Use YugabyteDB as a PostgreSQL-compatible test database
- Start YugabyteDB using Docker Compose
- Run tests inside a GitHub Actions job container
- No volumes, fully ephemeral DB
- Tests pass locally and in CI
Locally, everything worked perfectly.
CI was a different story.
The Initial Symptom
In GitHub Actions, tests consistently failed with:
Unable to Create Connection With Postgres: PoolTimedOut
Important observations:
- YugabyteDB container was running
- Healthcheck passed
ysqlshworked from inside the Yugabyte containercargo teststill timed out
This ruled out:
- Yugabyte not starting
- Wrong credentials
- Port not exposed
- SSL misconfiguration (explicitly disabled)
So what was going on?
Understanding the CI Network Topology
The key realization came from understanding where the Rust tests were running.
In GitHub Actions, the setup looked like this:
┌──────────────────────────────┐
│ GitHub Actions Job Container │
│ │
│ cargo test │
│ │
└───────────────┬──────────────┘
│
│ Docker network
│
┌───────────────▼──────────────┐
│ YugabyteDB Container │
│ (started via docker-compose) │
└──────────────────────────────┘
This is very different from local development.
The Critical Mistake: localhost
The Rust application was configured like this:
database:
host: "localhost"
port: 5433
name: "yugabyte"
user: "yugabyte"
password: "yugabyte"
ssl_mode: "disable"
Why this works locally
- YugabyteDB is exposed on the host
localhost:5433correctly routes to the database
Why this fails in CI
Inside a job container:
localhost = the job container itself
But YugabyteDB is running in a different container.
So the Rust app was trying to connect to:
job-container → localhost:5433 ❌
Nothing was listening there.
Why the Error Was PoolTimedOut
This made the issue harder to spot.
Most Rust Postgres pools:
- Retry connection acquisition
- Wait until timeout
- Do not fail immediately on
ECONNREFUSED
So instead of a clear “connection refused,” the error surfaced as: “PoolTimedOut”
Which misleadingly suggests a pool configuration issue.
The Fix: Stop Using localhost
In Docker-based CI:
Containers must talk to each other using container names, not
localhost.
The correct host was the Docker service name:
yugabytedb
Correct connection string for CI
postgres://yugabyte:yugabyte@yugabytedb:5433/yugabyte?sslmode=disable
In the GitHub Actions workflow:
- name: Run unit tests
env:
DATABASE_URL: postgres://yugabyte:yugabyte@yugabytedb:5433/yugabyte?sslmode=disable
run: |
make test
Once this change was applied:
- ✅ Database connections succeeded
- ✅ Pools initialized correctly
- ✅
cargo testpassed reliably
Key Takeaways
1. localhost is context-dependent
- Local machine → host OS
- Docker container → that container only
- GitHub Actions job container → never the host
2. Prefer DATABASE_URL in CI
It removes ambiguity and avoids env parsing mistakes.
3. PoolTimedOut often means “can’t reach the DB”
Not authentication. Not SSL. Not max connections. Just networking.
4. Healthchecks aren’t enough
A healthy DB container doesn’t mean your test container can reach it.
Final Checklist for DB-backed CI Tests
- ❌ Don’t use
localhostbetween containers - ✅ Use Docker service names
- ✅ Disable SSL explicitly for YugabyteDB
- ✅ Connect containers to the same Docker network
- ✅ Use
DATABASE_URLwhen possible
Conclusion
The bug wasn’t YugabyteDB. It wasn’t Rust. It wasn’t Docker Compose.
It was a single word:
**localhost**
Once that was fixed, everything else fell into place.
If you’re debugging database timeouts in CI, always ask yourself:
“Where is this code actually running?”
It might save you days.
메타데이터
- post_id
- fcda0db2013f
- slug
- debugging-pooltimedout-with-yugabytedb-docker-rust-and-github-actions-fcda0db2013f
- url
- https://medium.com/@shahnilay/debugging-pooltimedout-with-yugabytedb-docker-rust-and-github-actions-fcda0db2013f
- canonical_url
- https://medium.com/@shahnilay/debugging-pooltimedout-with-yugabytedb-docker-rust-and-github-actions-fcda0db2013f
- author_url
- https://medium.com/@shahnilay
- status
- ok
- fetched_at
- 2026-08-29 00:48:47