Sebastiano Druda

← Back to writing

Essay / Software Engineering

Reliability Is What Happens After the Happy Path Ends

Reliability becomes visible when networks fail and work must recover. Explore buffering, bounded retries and requirements that describe useful failure behavior.

A monitoring dashboard can look perfectly healthy while its last useful observation becomes steadily older. The process is running, the page loads, and the displayed number is still plausible. What has disappeared is the relationship between that number and the world it claims to describe.

This is a useful way to approach reliability. Ask what remains true when a dependency becomes unavailable, when an observation arrives late, or when work is repeated during recovery. An application that succeeds only while every assumption holds has a very narrow definition of working.

The happy path tells you what the system does. Failure paths tell you what the system is.

Forest-monitoring concepts offer a concrete setting for this discussion. Here I use them as an academic design scenario, not as a claim about operating a deployed forest sensor network. The scenario makes the trade-offs visible: remote devices, intermittent connectivity, delayed observations and decisions that depend on knowing how current the evidence is.

Separate availability from useful information

Suppose a sensor measures environmental conditions and sends observations to a central service. A simple requirement says the dashboard should remain available. That leaves several important questions unanswered. Can an old observation be displayed as current? How long may the connection be absent? What should happen when a device clock is wrong?

A better requirement identifies the user’s decision. If someone needs to distinguish recent observations from stale ones, the interface must show age and source health. If offline devices may reconnect later, the system needs to distinguish observation time from arrival time.

Those distinctions are small in a data model and substantial in operation. A delayed observation can still be useful for historical analysis while being unsuitable for a current alert. Treating both uses as one generic “latest value” field makes the system harder to trust.

The same issue appears in commerce. A reachable product page does not establish that its stock count is fresh. A working integration process does not establish that every record reached the destination. Reliability requirements should name the useful result rather than only the machine that produces it.

Buffers buy time, with conditions attached

A local buffer can preserve observations while a network is unavailable. In the monitoring scenario, each record might contain a device identifier, an observation timestamp, a sequence number and a value. Reconnection then becomes an opportunity to transfer retained work rather than an assumption that nothing important happened offline.

The buffer needs a capacity policy. When it fills, does the device stop sampling, discard the oldest data, retain selected summaries or overwrite the newest observations? Each choice protects something different. The decision should follow the purpose of the measurements, rather than emerge accidentally from a full disk.

There is also a power-loss question. A buffer held only in memory may help with a short connection failure and do nothing for a reboot. Persistent storage brings its own write, corruption and recovery considerations. Calling both arrangements “offline support” hides their different promises.

For an initial design, I would document a bounded offline interval and the behavior beyond it. That gives the team something testable without pretending that storage or energy is unlimited.

Retries can make a bad situation worse

A failed request does not always mean the remote operation failed. The receiver may have accepted the work before the acknowledgement was lost. Repeating the operation without an identity can produce duplicate effects.

For sensor observations, a stable record identifier can allow the receiver to recognize a replay. For a stock adjustment, the corresponding identity must belong to the business operation, not merely to one network attempt. The correct design depends on what repeating the operation would mean.

Google’s SRE discussion of overload explains why retries need limits: extra attempts can amplify pressure on an already struggling dependency. The practical implication for this scenario is to use a retry budget, delay repeated attempts and avoid having every device reconnect in lockstep.

Do not treat a larger retry count as a universal reliability improvement. It may delay a useful error, consume the remaining battery budget or keep obsolete work ahead of fresh observations. A recovery policy needs a stopping condition as well as another attempt.

Redundancy must protect against the relevant failure

Two sensors mounted together may protect against one broken device while sharing the same power, weather exposure and network path. Two copies of a service may still depend on one catalogue feed. Counting components is not enough to describe resilience.

Start by naming the failure you want the second component to survive. A backup connection helps only if it avoids the dependency that failed. A replicated record helps only if corruption or deletion does not immediately propagate to every copy you would use for recovery.

This is where a modest failure map becomes useful:

observation → local retention → connection → ingestion → interpretation → display

For each arrow, ask what the sender knows after a timeout and what the receiver can identify after a retry. For each box, ask which state survives a restart. The map is deliberately simpler than an infrastructure diagram because its purpose is to expose uncertainty about work.

Degradation should remain honest

A partially functioning system needs a clear account of its limitations. In the monitoring scenario, showing the last observation with an explicit age may be useful. Presenting an interpolated value as a fresh measurement would make a much stronger claim and should not happen silently.

Similarly, a catalogue integration could continue displaying verified descriptions while pausing uncertain price updates. That is a proposed policy, not a universal rule. Some operations may need a stricter stop because proceeding with stale information would be worse than temporary unavailability.

Graceful degradation should reduce capability without disguising uncertainty.

The user interface and backend policy need to agree. A warning hidden in a log does not help someone who is about to act on an outdated value. Conversely, a prominent warning should correspond to a defined condition, not appear whenever a developer feels uncomfortable.

Recovery is a workflow worth designing

After connectivity returns, a large backlog may compete with new observations. Processing everything in arrival order can make the displayed state look fresh only after a long catch-up period. Processing only new data can lose the historical record. The right approach depends on the distinct uses of the data.

One possible design separates current-state updates from historical ingestion. Another prioritizes by observation time while preserving all accepted records for later processing. These are design options to evaluate, not claims that a particular queue product solves the problem automatically.

Recovery also needs a definition of complete. A reconnecting icon tells you the channel is open. It does not tell you whether missing records have been reconciled. Record counts, sequence gaps and explicit checkpoints can help make that distinction observable.

For a human-operated integration, write down who reviews unresolved gaps and what evidence they need. Otherwise the system can leave an error queue technically visible and operationally abandoned.

Measure the promise, not the decorative metric

“Reliable” is too broad to verify. A requirement might instead say that observations older than a defined interval must be visibly marked, or that accepted records must survive a process restart. The thresholds should come from the task and its consequences; invented round numbers are not a substitute for that discussion.

Then build tests around the transitions: disconnect, buffer, reconnect, replay, reconcile. Include a full buffer, a duplicated message and a restart between receiving work and acknowledging it. These cases expose choices that a demonstration on a stable network will never exercise.

The connection to requirements engineering is direct. Reliability starts with a promise precise enough that two people can agree whether it was kept. Observability should then help explain a broken promise, rather than merely count requests.

I would end a reliability review by asking someone to walk through recovery without the original developer’s help. Which information is trustworthy? Which work can be repeated? Where does uncertainty remain? If the system can answer those questions clearly, its behavior after the happy path is becoming a designed capability rather than an improvised repair.

Sources

  1. Google SRE: Handling overload — checked 2026-10-13

Topics