Health checks: three different questions called by one name
Liveness asks "are you alive", readiness asks "are you ready to take traffic", startup asks "have you finished booting". They get confused, and the price of the confusion is measurable: a probe tied to a shared database turns one database outage into a simultaneous restart of every replica.
Full technical treatment
TL;DR
A health check is not one question but three. Startup asks whether the application has finished booting; liveness asks whether restarting this process would help; readiness asks whether traffic can be sent here. What separates them is not strictness but consequence: a restart, more waiting, or removal from rotation. And the contents of each probe follow from its consequence — check what that consequence can actually fix.
Hence the central mistake: a probe tied to a shared dependency turns one outage into two. A restart makes nothing outside the process more available — a database, a network, a neighbouring service do not revive because you restarted — while the process itself loses its warm caches and connection pools. Model: a database outage costs 1000 failed requests on its own and 1200 if liveness checks the database. The extra 200 are every replica restarting at once.
Beyond that: the numbers and the boundaries. For a degraded replica, liveness alone gives 520 slow answers and liveness plus readiness 80 — 6.5 times fewer; no probes at all gives 1600, because the balancer keeps sending load to the sick replica. It goes equally blind when readiness always answers "ready". But the opposite extreme exists too: readiness is not the sum of every dependency a service has, it is the answer to whether this replica can serve any traffic at all. The numbers here are model numbers: they follow from declared assumptions, and what carries meaning is the ratios between rows rather than the absolute values.
- a service does not run as a single copy: several identical replicas serve one stream of requests;
- a balancer in front of them decides which replica gets the next request, and can stop giving requests to one of them;
- something watches the replicas themselves and can restart one that has gone wrong.
- how liveness differs from readiness and what startup is for — that is what this lesson is about;
- how an orchestrator configures probes: periods, thresholds, field names;
- restart cascades, removal from rotation, a falsely negative probe.
What is actually being asked
The ladder usually runs like this:
- "Why do you need health checks?" — the warm-up.
- "How does liveness differ from readiness?" — where the substance starts.
- "What do you check inside a probe?" — the central question.
- "Why should liveness not touch the database?" — about cascades.
- "Why a separate startup probe?" — about slow boots.
- "What happens when readiness lies?" — about the opposite mistake.
This lesson rests on a model rather than on a measurement: there is no common standard for how probes behave, only the documentation of particular products. The model answers not "how much exactly" but "what is connected to what", and its assumptions are named.
Base: three questions, not one check
A service has several identical replicas, and from outside nothing about the inside of any of them is visible. There is exactly one way to ask: knock and look at the answer. That is where a health check comes from — a short question somebody puts to a replica at regular intervals, plus an action decided in advance for the case where the answer is no.
The whole topic rests on "are you healthy" not being one question. The observer can take several different actions, and different actions fix different things. So there are three checks, each with a question of its own:
| Probe | The question it answers | What is done on "no" |
|---|---|---|
| startup | has the application finished booting? | nothing: keep waiting, and do not judge the replica strictly |
| liveness | would restarting this process help? | the process is restarted |
| readiness | can traffic be sent here? | traffic stops, the process is left alone |
The middle column for liveness is phrased unusually, and that is the main point of the lesson. The usual phrasing is "is the process alive" — but a probe is not needed for that question: a dead process does not answer at all, and that is visible without any check. The probe exists for the other case: the process is alive, it answers requests, and it has stopped working. What it decides is not "alive or not" but whether the one available cure — a restart — is worth applying.
The right-hand column answers the lesson's main question too: what goes inside each probe? It follows from the consequence — check what that consequence fixes, and nothing else.
That is already enough to answer the basic interview question. Everything below is about the price of getting that choice wrong: what missing readiness costs, why a probe that looks into a shared database adds failures to somebody else's outage, and why an over-diligent readiness is as harmful as a credulous one.
Mechanism 1: the consequence is the definition
There is no normative document for this split: below is a distinction by consequence, which this lesson uses as a definition. The confusion starts wherever all three questions are answered by one handler.
Liveness — "would restarting this process help". A negative answer means: the process is broken badly enough that only a restart can return it to working order. A deadlock, an exhausted thread pool, an infinite loop — internal, cumulative failures, all of them cured by putting the process back into a known state.
Readiness — "can traffic be sent here right now". A negative answer means: do not send me requests, but do not restart me either. A warming cache, a lost connection to a dependency, a temporary overload — states a replica leaves on its own if it is not being loaded.
Startup — "has it finished booting". A separate probe exists so that a slow boot does not look like a death. This lesson assumes liveness does not apply until the startup probe has passed — that is what the separate probe is for.
The difference is in the consequence: liveness restarts, readiness removes from rotation. Hence the rule everything else follows from: check what the consequence can actually fix. For liveness that reads literally: only what a restart of this process can fix belongs inside it.
Mechanism 2: what each probe buys
The model: three replicas, constant traffic, one replica starting to answer slowly — but answering — from the tenth second.
REQUESTS SERVED SLOWLY OR NOT AT ALL
------------------------------------
mode slow failed total
none 1600 1000 6000
liveness 520 1000 6000
liveness+readiness 80 1000 6000
liveness-on-db 640 1200 6000
No probes — 1600 slow answers. The balancer does not know the replica is unwell and keeps sending it a third of the traffic the whole time.
Liveness only — 520. The probe notices the trouble and restarts the replica; the restart takes it out for five seconds, then it comes back — and degrades again. It helps, but badly: the replica shuttles between "unwell" and "restarting".
Liveness plus readiness — 80. The replica is taken out of rotation without a restart, and the load on it stops. 6.5 times fewer slow answers than with liveness alone.
Hence the answer to the second rung: readiness is not "the same thing but gentler". It is a different consequence, and for degradation it is the apt one: a replica that is not being loaded may recover on its own, while a restarted one begins from a cold start.
Mechanism 3: why liveness does not touch the database
The fourth row of the run above is about the mistake that adds failures to somebody else's outage. Its slow answers (640) sit close to the liveness-only mode's 520; the whole difference went into the failed column, and that is what this section is about. Here the probe checks not only itself but a shared dependency: if the database is unavailable, liveness is considered failed.
WHAT THE THREE MODES ACTUALLY CHANGE
------------------------------------
no probes: slow answers 1600
liveness only: slow answers 520
liveness + readiness: slow answers 80
liveness tied to the database: failures 1200
the same failures without that tie 1000
failures added by tying liveness to the database 200
The database is down for ten seconds in both runs, and those ten seconds cost 1000 failed requests regardless of the probes — a probe cannot fix somebody else's outage.
The extra 200, however, belong entirely to the probe. The mechanism: the database goes down → liveness fails on every replica at once → every replica restarts → while they come up the service answers nothing at all, and that continues after the database is already back.
Hence the rule worth answering with: liveness checks only what a restart of this process can fix. A database, a network and a neighbouring service are not fixed by restarts; their place is readiness, where the consequence is milder — the replica stops being loaded but stays alive and comes back on its own.
And the second half of the same rule: a shared dependency makes probes synchronous. If the check is identical on every replica and depends on one external object, they all fail together — and the redundancy that three replicas were meant to provide disappears exactly when it is needed.
Deeper: the boundaries of the rule, and both readiness mistakes
The opposite mistake works the other way round and costs the most slow answers in the model. A readiness handler that always answers "ready" — because it is a static handler returning 200, say — makes the balancer blind: it keeps sending requests where there is nobody to serve them.
The model has no separate mode for such a readiness; the nearest one is the mode with no probes at all: 1600 slow answers. The balancer is equally blind in both cases, so the number is the same. The replica is alive and formally ready, and the traffic keeps arriving.
Hence a practical check worth naming in an interview: readiness must reflect the ability to serve a request, not the fact that a process is running. The minimal honest implementation checks what a request cannot be completed without: a database connection, room in a pool, the state of a task queue.
And the other side of it: the more checks inside readiness, the higher the chance it turns falsely negative and a replica leaves rotation over a trifle. So what gets checked is not "everything there is" but what this service cannot serve its requests without.
This is where the boundary of the rule belongs — the one that mirrors the boundary for liveness. From "dependencies live in readiness" it is tempting to conclude "so list every dependency in it", and that is a mistake too, just a different one. Readiness does not answer "is everything around me fine", it answers whether this replica can serve any traffic at all. A service that still answers some of its requests without the second database has to stay in rotation while that database is down: taking it out turns a partial degradation into a total outage — by your own hand rather than by the outage.
A readiness that lists every dependency also brings back exactly the disease the previous section cured. A shared dependency makes probes synchronous no matter which probe it is written into: every replica leaves rotation at the same moment because they all look at the same external object. The consequence is milder than with liveness — at least the replicas are not restarting — but the redundancy disappears just the same.
How to answer in an interview
Short answer: there are three probes and they differ by consequence — liveness restarts, readiness removes from rotation, startup postpones liveness for the duration of the boot. So the liveness question is not "is the process alive" but "would restarting this process help": only what a restart fixes goes inside it, and dependencies go into readiness.
That is enough to answer correctly. Beyond it is what you add when the interviewer digs.
If the interviewer digs deeper
Three things separate a good answer. First, you give the cost of the mistake as a number: in the model a liveness probe tied to the database added 200 failed requests on top of the 1000 the outage itself cost, because every replica restarted at once. Second, you explain why readiness is needed when liveness exists: a restart returns the replica to service again and again, while removing it from rotation stops the load — 80 slow answers against 520 in the model. Third, you mention the opposite mistake: a readiness that always answers "ready" makes the balancer blind, and that is the worst case the model gives — 1600.
And one thing that is easy to overdo. "Dependencies go into readiness" does not mean readiness should be the sum of every dependency. The precise phrasing is: readiness answers whether the replica can serve any traffic at all — and a replica that serves some of its requests without one of its dependencies should not leave rotation. Otherwise the probe itself turns a partial degradation into a total outage, and the shared dependency makes every replica synchronous again.
Next they ask
Can readiness and liveness be one handler?
Technically yes. But the consequences differ: one restarts, the other stops the load. A shared handler means any reason for "not ready" turns into a restart.
In the model that is precisely the fourth row: a probe that checks the database added 200 failed requests on top of what the outage itself cost. Splitting the handlers is the cheapest measure in this topic.
Why a separate startup probe?
So that a slow boot does not look like a death. If an application takes a minute to come up while liveness is tuned in seconds, it will be restarted before it has started — over and over.
The alternative without a separate probe is stretching the liveness thresholds until they cover the boot. But then the same stretched check applies in steady state too, and a real deadlock is noticed after a minute instead of a second. A separate probe splits the two regimes.
What should readiness check?
What this service cannot serve a request without: a database connection if every request goes to the database; room in a pool; a filled cache if answers are meaningless without it. Not "everything there is": every extra check raises the chance of a false removal from rotation.
A useful test while writing it: if the probe answers "not ready", can the replica come back on its own? If yes, this is readiness. If only a restart can help, this is liveness.
Why does a restart sometimes help after all?
Because some failures are internal and cumulative: leaked descriptors (the lesson on limits), a deadlock, a thread pool whose threads never come back. A restart puts the process back into a known state, and it is the one cure that does not require understanding the cause.
The price is losing everything accumulated: warm caches, established connections, a hot pool. Which is why a restart should not be the reaction to an external outage: it fixes the internal and damages what was fine.
Common misconceptions
liveness and readiness are the same thing under different names
Their consequences differ: liveness restarts the process, readiness stops sending it requests. In the model, for a degraded replica that is 520 slow answers against 80 — 6.5 times — because a restarted replica returns to service and degrades again, while one out of rotation simply is not loaded.
a probe should check everything the service depends on
In liveness, only what a restart of this process can fix. Model: a probe checking the shared database added 200 failed requests on top of the 1000 the outage itself cost, because every replica restarted at once and was still coming up after the database returned. Nor can readiness be assembled mechanically from every dependency: it answers whether the replica can serve any traffic at all, and one extra check inside it turns a partial degradation into a total outage.
if a replica answers slowly it should be restarted
A restart returns the process to a known state at the price of losing warm caches and connections — and a degraded replica will come back and degrade again. The model shows it directly: liveness alone gives 520 slow answers against 80 when the replica is taken out of rotation.
a readiness handler that always answers 'ready' is harmless
It is the worst case the model gives: 1600 slow answers against 80. The balancer goes blind and keeps sending load where nobody can serve it. Readiness must reflect the ability to serve a request, not the fact that the process is running.
a startup probe is an optional nicety
Without it the liveness thresholds have to be stretched to cover the slowest boot — and the same stretched check then applies in steady state, where a real deadlock is noticed after a minute instead of a second. A separate probe splits booting from working.
health checks raise availability by themselves
They change the distribution of failures, not their number. In the model the database outage cost 1000 failed requests under every probe configuration: a probe does not fix somebody else's outage. What it can do is avoid turning one outage into two.
including a shared dependency in a probe makes the picture more accurate
It makes the probes synchronous: every replica fails at the same moment because they all look at the same external object. Three replicas stop being redundancy exactly when redundancy is needed.
Practice
Two exercises. Answer first, then check against the real output: in both, the correct answer comes from a run of the model rather than being written by hand.
Practice · predict the output
none = simulate("none")
liveness = simulate("liveness")
both = simulate("liveness+readiness")
on_db = simulate("liveness-on-db")
print(none["slow"])
print(both["slow"])
print(on_db["failed"] - liveness["failed"])Practice · estimate
Knowledge check
How does liveness differ from readiness?
This is neither a retelling nor a separate text: everything below is taken from the article itself — its own summary, the section headings, the “actually” column and the version table. Which is why these theses cannot drift from the article.
The gist
- A health check is not one question but three. Startup asks whether the application has finished booting; liveness asks whether restarting this process would help; readiness asks whether traffic can be sent here. What separates them is not strictness but consequence: a restart, more waiting, or removal from rotation. And the contents of each probe follow from its consequence — check what that consequence can actually fix.
- Hence the central mistake: a probe tied to a shared dependency turns one outage into two. A restart makes nothing outside the process more available — a database, a network, a neighbouring service do not revive because you restarted — while the process itself loses its warm caches and connection pools. Model: a database outage costs 1000 failed requests on its own and 1200 if liveness checks the database. The extra 200 are every replica restarting at once.
- Beyond that: the numbers and the boundaries. For a degraded replica, liveness alone gives 520 slow answers and liveness plus readiness 80 — 6.5 times fewer; no probes at all gives 1600, because the balancer keeps sending load to the sick replica. It goes equally blind when readiness always answers "ready". But the opposite extreme exists too: readiness is not the sum of every dependency a service has, it is the answer to whether this replica can serve any traffic at all. The numbers here are model numbers: they follow from declared assumptions, and what carries meaning is the ratios between rows rather than the absolute values.
In fact
- Their consequences differ: liveness restarts the process, readiness stops sending it requests. In the model, for a degraded replica that is 520 slow answers against 80 — 6.5 times — because a restarted replica returns to service and degrades again, while one out of rotation simply is not loaded.
- In
liveness, only what a restart of this process can fix. Model: a probe checking the shared database added 200 failed requests on top of the 1000 the outage itself cost, because every replica restarted at once and was still coming up after the database returned. Nor canreadinessbe assembled mechanically from every dependency: it answers whether the replica can serve any traffic at all, and one extra check inside it turns a partial degradation into a total outage. - A restart returns the process to a known state at the price of losing warm caches and connections — and a degraded replica will come back and degrade again. The model shows it directly: liveness alone gives 520 slow answers against 80 when the replica is taken out of rotation.
- It is the worst case the model gives: 1600 slow answers against 80. The balancer goes blind and keeps sending load where nobody can serve it. Readiness must reflect the ability to serve a request, not the fact that the process is running.
- Without it the liveness thresholds have to be stretched to cover the slowest boot — and the same stretched check then applies in steady state, where a real deadlock is noticed after a minute instead of a second. A separate probe splits booting from working.
- They change the distribution of failures, not their number. In the model the database outage cost 1000 failed requests under every probe configuration: a probe does not fix somebody else's outage. What it can do is avoid turning one outage into two.
- It makes the probes synchronous: every replica fails at the same moment because they all look at the same external object. Three replicas stop being redundancy exactly when redundancy is needed.
What is covered
- What is actually being asked
- Base: three questions, not one check
- Mechanism 1: the consequence is the definition
- Mechanism 2: what each probe buys
- Mechanism 3: why liveness does not touch the database
- Deeper: the boundaries of the rule, and both readiness mistakes
- How to answer in an interview
- Next they ask
- Common misconceptions
- Practice
- Knowledge check
Sources & further reading
1 SOURCE
- The model behind this lesson: probes and the restart cascadeSource. This lesson has no external primary source: there is no common standard for how probes behave, only the documentation of particular products. So the lesson rests on a model with declared assumptions: three replicas, constant traffic, one replica degrading from the tenth second, a shared database unavailable from the twentieth to the thirtieth, a probe every second, a threshold of three consecutive failures, a five-second restart. Everything the run prints follows from those rules and can be checked by reading the script./en/bench/probes/model.py