A single customer’s invalid, expired, or revoked credential should not make a Node.js API unhealthy. Liveness should answer “is this process stuck?”, readiness should answer “can this instance serve the traffic it is meant to receive right now?”, and a degraded state should describe an instance that is still serving a defined subset of its work. Where a credential or tier condition falls among those three depends on your API contract. Kubernetes and framework probe documentation explain how probes behave, but they do not decide which credential or tier states count as degraded for your service.
Liveness and readiness trigger different consequences
Kubernetes uses a liveness probe to decide when to restart a container, and a readiness probe to decide whether a Pod should receive traffic from a Service. The two outcomes have very different costs. A restart drops in-flight requests and resets in-memory caches and connection pools. Removing a Pod from rotation only moves its load to its neighbours, and the Pod can rejoin as soon as it passes again.
As an Amazon Associate I earn from qualifying purchases.
| Probe | Question it answers | Failure consequence in Kubernetes | Belongs here |
|---|---|---|---|
| Startup | Has initialization finished? | When configured, liveness and readiness checks do not run until startup succeeds | Slow configuration load, cache warm-up |
| Liveness | Is the process stuck or unable to make progress? | The container is restarted | Deadlocked event loop, unrecoverable internal state |
| Readiness | Can this instance serve the traffic it is meant to receive now? | The Pod is removed from Service endpoints until it passes again | Required database, required credential store, graceful shutdown |
The Express documentation, in its “Health Checks and Graceful Shutdown” guidance, states the load-balancer view directly: “A load balancer uses health checks to determine if an application instance is healthy and can accept requests.” That is a readiness question. Most credential and tier problems are readiness-shaped at most, and many are not health problems at all.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Define the states before writing the endpoint
Write the state model in terms of your API’s promises first. The HTTP representation can come later, and it should stay small.
#1 Best Overall
- List each request class the API serves, and the tier or credential type allowed to call it.
- Mark each dependency as required (no useful work is possible without it) or optional (only one request class needs it).
- Map required dependencies to readiness. Keep liveness free of dependency checks.
- For each optional failure, decide whether the instance should report degraded while still returning success to probes, or whether only the affected routes should return an error.
- Decide that caller-level credential results never change probe status.
In practice this produces three operator-facing states:
- Live: the process can make progress. A failure means a restart is a plausible recovery.
- Ready: every required dependency is available, so the instance can accept its intended traffic.
- Degraded: the instance is ready, but at least one optional capability is impaired. Affected requests fail with a precise status, and everything else continues.
Should an invalid API credential make a service unhealthy?
Usually not. An invalid, expired, revoked, or quota-exhausted key describes one caller’s request. The correct response is a 401, 403, or 429 for that request, and the instance keeps serving everyone else. If a bad key changed probe results, one client could remove capacity from all clients, and a restart would not fix anything.
Rank #2
The exception is when the credential machinery is required for every request. If each call must verify a key against a credential store, and that store is unreachable with no usable cached verification, the instance cannot do its intended work. Readiness should then fail. That is a dependency outage, not a bad key, and the probe reason should say so.
Separate caller outcomes from dependency outcomes
- Caller outcome (key invalid, revoked, expired, or over quota): return the request-level status, log a redacted reason, and leave probes unchanged.
- Dependency outcome (credential store or issuer unreachable): readiness depends on whether cached or fresh verification can still satisfy required requests. Liveness is unaffected.
How readiness should handle service tiers
Tier entitlements are a per-request decision. Readiness should reflect whether the instance can serve the requests it is meant to receive, not whether every tier’s features are working. If a premium-only capability depends on a failing service, baseline callers should still be served. Marking the whole instance unready removes capacity from requests that never touch the failed feature.
Rank #3
The table below shows one way to classify common states. It is an example starting point for a hypothetical API, not a standard, and each row should be replaced with your own contract.
| Condition | Liveness | Readiness | Response to affected requests | Reported state |
|---|---|---|---|---|
| A caller’s key is expired or revoked | Pass | Pass | 401 or 403 for that key | ok |
| A caller’s tier lacks entitlement for an endpoint | Pass | Pass | 403 for that call | ok |
| A caller has exhausted its quota | Pass | Pass | 429 for that caller | ok |
| A premium-only dependency is down, baseline traffic still works | Pass | Pass | 503 on premium routes only | degraded |
| A required database is down | Pass | Fail | Pod removed from Service endpoints | unavailable |
| Credential store unreachable, no usable cache, every call needs verification | Pass | Fail | 503 on all authenticated calls | unavailable |
| Event loop stalled or internal state unrecoverable | Fail | Fail | Container restarted; no response is possible | not reported |
Keep tier logic out of the probe itself where possible. A readiness check that asks “is the premium analytics client healthy?” couples every tier to one optional capability. A check that asks “are the required dependencies for baseline requests available?” keeps probe results aligned with capacity.
Rank #4
Implement the endpoints in Node.js
The Node.js Reference Architecture’s health-check guidance recommends a minimal implementation for most services, with Express examples that expose /livez and /readyz routes. The sketch below follows that approach and adds the degraded state. It is illustrative and has not been run or load-tested. Replace the placeholder dependency checks with your own.
Recommended Free Tools
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
// Dependency state is refreshed in the background so probe requests stay cheap.
const health = {
required: { database: false, credentialStore: false },
optional: { premiumAnalytics: false },
draining: false,
};
async function refreshHealth() {
health.required.database = await checkDatabase().then(() => true, () => false);
health.required.credentialStore = await checkCredentialStore().then(() => true, () => false);
health.optional.premiumAnalytics = await checkAnalytics().then(() => true, () => false);
}
refreshHealth();
setInterval(refreshHealth, 10000).unref();
process.on('SIGTERM', () => {
health.draining = true;
});
app.get('/livez', (req, res) => {
res.status(200).type('text/plain').send('ok');
});
app.get('/readyz', (req, res) => {
const requiredOk = Object.values(health.required).every(Boolean);
if (health.draining || !requiredOk) {
return res.status(503).json({ status: 'unavailable' });
}
const optionalOk = Object.values(health.optional).every(Boolean);
res.status(200).json({ status: optionalOk ? 'ok' : 'degraded' });
});
app.listen(PORT);
What this sketch does
- Liveness never calls a dependency, so a database or credential outage cannot restart the process.
- Readiness is false until the first refresh completes, which prevents traffic from reaching an instance that has not checked its dependencies.
- Draining on
SIGTERMremoves the instance from rotation before shutdown. - Optional failures return 200 with
degraded, so the Pod stays in rotation. Routes that need the optional capability must still return their own error.
Wire each route that depends on an optional capability to check that capability directly. The probe status does not protect those routes on its own.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Configure Kubernetes probes to match the routes
Probe paths must match routes your application actually exposes. The values below are starting points to tune against your own startup time and failure tolerance, not tested recommendations.
startupProbe:
httpGet:
path: /livez
port: 3000
periodSeconds: 5
failureThreshold: 12
livenessProbe:
httpGet:
path: /livez
port: 3000
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /readyz
port: 3000
periodSeconds: 5
failureThreshold: 2
Kubernetes evaluates the HTTP status code, not the response body. Under this configuration, a degraded response is invisible to the Service and visible only to anything that reads the body.
Report degradation without leaking secrets
NestJS Terminus, in its documentation on health checks, shows one framework pattern: a degraded indicator does not fail the check. It is listed under info, the overall status becomes degraded, and the HTTP status stays 200. That pattern works only if your probe consumer ignores bodies. Verify how your load balancer or orchestrator interprets status codes before adopting it on a probe endpoint.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsKeep the probe response to a status word. If operators need dependency names or timings, expose them on a separate authenticated route with its own access controls. Never include raw credential values, authorization headers, key identifiers that let someone impersonate a caller, or stack traces in a health response or its logs. Log the reason for a failed verification as a redacted category, such as “key expired” or “store timeout.”
Lightship is one documented Node.js library that provides readiness, liveness, startup checks, and graceful shutdown. Using a library makes sense when its state model matches yours. If it does not, a few routes are usually easier to reason about than a framework’s default categories.
Quick Recap
Troubleshoot common failure patterns
- Pods restart during a database outage: a dependency check has leaked into liveness. Move it to readiness.
- Pods flap in and out of the Service: an optional or slow dependency is driving readiness, or the timeout is shorter than the dependency’s normal latency. Raise
failureThresholdor refresh in the background as shown above. - All Pods become unready after one customer’s key is revoked: a caller-level result is reaching the probe state. Return the status from the request handler instead.
- Degraded state never shows up in the load balancer: expected when the probe ignores response bodies. Scrape the body with monitoring or use a separate route.
- Probes pass but customers receive 503 responses: the route that uses the failing capability does not check that capability. Add a route-level check or error path.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




