Application loads but customer data does not
Can I prove the application can reach its database?
The ticket
CUSTOMER TICKET: customer list is empty and will not load
Account: Beacon Analytics (growth) Impact: all users, core workflow unusable Started: after last night's maintenance window
The app itself seems to come up fine now, but the customer list never loads. We just get an error box that says the service is unavailable. Other pages that do not show customer data seem OK. We had someone in doing maintenance last night, if that helps.
Your job
- Prove which layer is actually failing before you name a cause.
- Restore service with the smallest correct change.
- Verify the customer's own workflow, not just that something responds.
Working notes
The service is expected on http://127.0.0.1:8100. The customer workflow is
GET /customers. Runtime configuration lives in
labs/docker/_stack/compose.override.yaml. After editing it, run tse apply
to recreate the services, then tse check.
- Track
- Docker
- Time
- about 30 minutes
- Difficulty
- Straightforward
- Tier
- Core
Do these first: Service unavailable after a release
Start it
In a Codespace or a local clone:
tse start docker/02-customer-data-not-loadingThat provisions the broken system and prints the ticket above. Investigate with ordinary tools, then run tse check.
Look at the evidence
Real output, captured by running these commands against the broken system and checked against it on every build. It shows you what the evidence looks like. It cannot fix anything, and it will not tell you what is wrong.
Type a command you would reach for, or help.
Enter runs it. Shift and Enter start a new line. The up and down arrows walk back through what you have typed.
Investigation scratchpad
Saved in this browser as you type. Nothing is uploaded. 0 of 7 filled in.
In their words, not yours. Include scope and urgency.
Before running anything: target layer, expected output, two likely causes.
The command or query, and why it is safe to run here.
Three separate lists. This is the step people skip.
One proof sentence, one safe next step, one alternate hypothesis.
Plain language. Impact first. No blame, no speculation.
One gap, one command to repeat tomorrow, one confidence score.
Hints
Each hint gives away a little more. Try to spend a few minutes on your own evidence first, because the recall is what makes it stick.
Hint 1 of 3
Notice what the customer told you that the last ticket did not: the application comes up, and only one workflow is broken.
That is a genuinely different situation from a service that never started, and it rules something out for free. If the process is running and answering requests, the failure is not "the app is down". Something the app depends on is either unreachable, refusing it, or absent.
The smallest question now is not "is it running", because you already know it is. It is:
Can the application reach the thing it needs?
Read what the application itself says when the failing request comes in. It is running, so it is talking.
Hint 2 of 3
The application logs a database_connection_failed event with a detail
message. Read the detail, not just the event name.
"Cannot reach the database" splits into at least four separate causes, and each has different evidence:
| Cause | What would prove it |
|---|---|
| The database is down | The database container's own state and health |
| The name does not resolve | Resolving the name from inside the app container |
| Credentials are rejected | The database's own error text, which says so explicitly |
| Wrong database or schema | A successful connection but missing tables |
Check the database's state first, because it is one command and it eliminates a whole branch. Then work out where the app is actually trying to connect. A hostname is only meaningful relative to where it is evaluated.
Hint 3 of 3
The database is healthy, so the problem is on the path between the two containers. Prove what the app is aiming at:
docker compose -f labs/docker/_stack/compose.yaml \
-f labs/docker/_stack/compose.override.yaml \
exec app printenv DB_HOST
Now prove what that name means from inside the app container, which is the only place it matters:
docker compose -f labs/docker/_stack/compose.yaml \
-f labs/docker/_stack/compose.override.yaml \
exec app getent hosts "$(docker compose \
-f labs/docker/_stack/compose.yaml \
-f labs/docker/_stack/compose.override.yaml \
exec -T app printenv DB_HOST | tr -d '\r')"
Compare that against the name Compose actually publishes for the database service. The value in the config is a perfectly valid hostname. It just does not point where the maintenance work assumed it did.
Solution
Write your customer update before you read this. Comparing your wording against the model answer is worth more than reading it cold.
Reveal the solution
Solution: customer data not loading
What the evidence proved
| Command | What it proved | What it did not prove |
|---|---|---|
docker compose ps |
Both containers are up and the database is healthy | Nothing about whether they can talk |
curl /customers |
The app answers, and answers 503 |
Nothing about which dependency failed |
docker compose logs app |
The failure is database_connection_failed, with a connection-refused detail |
Nothing about why the connection was refused |
exec app printenv DB_HOST |
The app is aiming at localhost |
Nothing on its own, until you know where it is evaluated |
exec app getent hosts localhost |
Inside the container, localhost is the container itself |
The database was never down, and the credentials were never wrong. Both of those are worth ruling out explicitly, because both are the first guess most people reach for.
Root cause
The maintenance change set DB_HOST to localhost. Inside a container,
localhost is that container's own network namespace, so the application spent
every request trying to connect to a database inside itself. Nothing is
listening on port 5432 there, so the connection is refused immediately.
This is why the symptom looked like a database outage while the database was provably healthy: the app never reached it.
On the shared Compose network, the database is reachable by its service
name, postgres, which Compose resolves through its internal DNS.
Scoped fix
In labs/docker/_stack/compose.override.yaml:
services:
app:
environment:
DB_HOST: postgres
Then:
tse apply
tse check
Customer update
The customer list failure was caused by a connection setting changed during last night's maintenance. The application was pointed at the wrong address for the database, so those requests could not complete, which is why only the pages that read customer data were affected. We have corrected the setting and confirmed the customer list is loading. No data was lost or changed. If you notice any other pages still failing, tell me which ones and I will check them against the same setting.
Engineering escalation, if you needed one
Impact:
GET /customersreturning 503 for all users since the maintenance window. Evidence: app healthy and serving;database_connection_failedwith connection refused;DB_HOST=localhostinside the app container;postgrescontainer healthy and accepting connections on the Compose network. Confirmed: database availability, database credentials, app process health. Ruled out: database outage, credential rotation, schema change. Suspected cause: maintenance replaced the Compose service name withlocalhost, which resolves to the app container itself. Request: confirm whether the maintenance template is shared with other services that would have taken the same edit.
That last line matters. One misconfigured service is an incident. A shared template is an outage waiting for the next deploy.
Check your understanding
Three questions on what the evidence here proved, and what it pointedly did not. Wrong answers explain themselves, and so do right ones.
tse quiz
Check your understanding
Three questions on what the evidence proved and what it did not. Every answer explains itself, including the right one.
3 questions, none answered yet.
Why this one exists
Inside a container, localhost means that container, not the host and not another service. Name resolution is a separate provable layer from credentials and from availability.
In an interview
Cross-layer reasoning, which is where most candidates lose the thread. The application is genuinely healthy as a process and genuinely broken as a service. Being able to say "the app is running but cannot reach the database" rather than "the app is broken" is the difference between an escalation engineering can act on and one they have to redo.
Commands introduced
docker compose execdocker inspectgetent hostsprintenv
Evidence layers
- container state
- application logs
- service name resolution
- runtime configuration