Case StudiesCase study / Incident response

One outage, four root causes, each hiding behind the others

DIAREV's backend was failing intermittently. Not consistently enough to look like a config error, not rarely enough to ignore. Here is how we found every layer.

Client
DIAREV
Industry
Healthcare
Services
DevOps, Cloud Infrastructure, Backend
Stack
GCP Cloud Run, Firestore, IAM

What the client saw

  • Admin dashboard calls timing out
  • Enrollment endpoints throwing 500s
  • Frontend losing contact with the backend
01 / Where it broke

The architecture, and the four failure points

Every failure sat on a different link of the same request path, which is why fixing one never made the symptoms fully go away.

FRONTENDWeb appPublic environment variablesCLOUD RUNNode.js backendAdmin dashboard +enrollment APIsScales to zero when idleFIRESTOREDatabaseEnrollment &support-plan dataOld Firebase domainNo longer resolves1IAM bindingsilently reset2CPU throttled under concurrent calls3Cold-start raceDB not ready yet4Env var points here
02 / The debugging path

Fix one, re-test, keep digging

  1. Start

    Symptoms surface

    Intermittent failures, too inconsistent to be a config error.

  2. 1

    IAM binding reset

    Auth failing mid-flow with no clean error.

  3. 2

    CPU throttling

    Concurrent admin calls starved the instance. It looked like a DB problem.

  4. 3

    Cold-start race

    Container was "up" before its Firestore connection was ready.

  5. 4

    Dead env var

    Frontend pointed to a Firebase domain that no longer resolved.

  6. Done

    Stable and guarded

    All four fixed independently, safeguards added.

After each fix we re-tested. The failures were still there. Three more times.

03 / Problems and fixes

Four problems, four fixes

Problem 1

A reset IAM binding

The IAM binding had silently reset, so authorization failed mid-flow with no clean error to point at.

Fix 1

Binding restored, then checklisted

IAM bindings were re-established and added to a standing post-deploy checklist.

Problem 2

CPU throttling under concurrent load

Concurrent admin dashboard calls throttled the CPU. It looked like a database problem. It wasn't.

Fix 2

Cloud Run re-tuned

Configuration moved to gen2 with 1Gi of memory and concurrency set to 80.

Problem 3

Cold starts racing Firestore

The container was "up" before its Firestore connection was ready, so early requests failed.

Fix 3

A warm instance, always

Min-instances set to 1 removed the cold-start race against Firestore connection setup.

Problem 4

A stale frontend env var

A frontend environment variable pointed to a Firebase domain that no longer resolved.

Fix 4

Smoke test before every deploy

An automated smoke test now verifies that every public-facing environment variable resolves.

Outcome

Production incidents rarely have the courtesy of one root cause. Treat "it's fixed" as a hypothesis to test, not a feeling to trust.

  • Full backend reliability restored
  • IAM bindings on the post-deploy checklist
  • Tuned Cloud Run config: gen2, 1Gi, concurrency 80, min-instances 1
  • Env-var smoke test before every deploy
04 / The full write-up

How we found all four

Most outages have one villain: a bad deploy, a maxed-out database, an expired certificate. The hard ones don't. They're four small problems stacked on top of each other, each one wearing a different disguise, all failing at once and pointing you in four different directions at the same time.

That's what we walked into on DIAREV, our camp-based healthcare platform running on Cloud Run. Here's how we found, and fixed, all four.


The symptom

Requests to the backend were failing intermittently. Not consistently enough to look like a config error, not rare enough to ignore. Some admin dashboard calls timed out. Some support-plan enrollments threw 500s. The frontend, meanwhile, was occasionally unable to reach its own backend at all.

The instinct in a moment like this is to chase the loudest error first. We didn't, because in our experience, the loudest error is rarely the real one.

Root cause #1: IAM bindings had quietly reset

The first thread we pulled was permissions. A service account binding had been reset, likely during an earlier infrastructure change, which meant certain backend calls were silently losing their authorization mid-flow. This wasn't throwing a clean "access denied"; it was surfacing as vague, inconsistent failures downstream, which is exactly what made it hard to spot first.

Fix: Re-established the IAM bindings and added them to our standard post-deploy checklist so a reset doesn't go unnoticed again.

Root cause #2: CPU throttling under concurrent load

Separately, we found the Cloud Run service was hitting CPU throttling during bursts of concurrent traffic, particularly when the admin dashboard fired off several parallel API calls at once. Throttling doesn't crash a container; it just makes everything slow and unpredictable, which looks a lot like a database problem until you check the metrics.

Fix: Tuned the Cloud Run configuration: gen2 execution environment, 1Gi memory, and a concurrency setting matched to actual traffic patterns (concurrency=80), so the service had headroom instead of ceiling-hitting under normal load.

Root cause #3: Cold starts racing Firestore connections

Related, but distinct: when the service scaled from zero, a burst of parallel admin dashboard calls would race against Firestore's connection establishment. The container was technically "up" before its database connection was actually ready, so early requests failed even though a retry a second later would have succeeded.

Fix: Set min-instances=1 so the service never fully scales to zero, eliminating the race condition for the traffic patterns that mattered most.

Root cause #4: A frontend env var pointing nowhere

The last piece was the one that looked like it should've been the first thing anyone checked, and yet it hid the longest. A frontend environment variable was pointing to a Firebase App Hosting domain that no longer resolved. Every request built from that variable failed at the DNS level, before it ever reached the backend logic we'd spent hours debugging.

Fix: Corrected the environment variable, then added a smoke test that verifies every public-facing env var actually resolves before a deploy is considered complete.


What made this hard

None of these four issues was individually exotic. IAM resets, throttling, cold starts, and a stale env var are all things any backend engineer has seen before. What made this incident hard was that they were overlapping: each one masking or mimicking the others. A slow request could be throttling or a cold start. A failed request could be a bad IAM binding or an unresolvable domain. You can't fix what you can't isolate, and you can't isolate four causes by treating them as one bug.

The actual fix was going root-cause by root-cause instead of symptom by symptom: reproducing each failure mode in isolation, confirming it independently, and only then trusting that the system was actually healthy, not just quiet.

The takeaway

Production incidents rarely have the courtesy of a single cause. Real infrastructure work means treating "it's fixed" as a hypothesis to test, not a feeling to trust. That discipline, chasing each thread to its actual end instead of stopping at the first plausible explanation, is what we bring to every platform we operate, at Rise Digital India.


Running into intermittent, hard-to-pin-down production issues? Get in touch with Rise Digital India. This is the kind of problem we like.

Dealing with intermittent, hard-to-pin-down issues in production?

Rise Digital India · We like this kind of problem

Get in touch