---
title: "Surviving Airport Wi-Fi: Stream Resilience on Bad Networks"
description: "How we keep the AI travel assistant responsive when connectivity is terrible — disconnection detection, reconnection, and partial state recovery."
canonical: https://nowah.xyz/blog/stream-resilience-bad-networks
lastModified: "2026-08-07T03:54:28.438Z"
---

# Surviving Airport Wi-Fi: Stream Resilience on Bad Networks

How we keep the AI travel assistant responsive when connectivity is terrible — disconnection detection, reconnection, and partial state recovery.

I'm going to describe a scenario that every traveler knows. You're at the gate. Your flight boards in 40 minutes. You open the app to check something about your hotel reservation. The airport Wi-Fi connects, sort of. The signal icon shows full bars but nothing loads. You switch to cellular. One bar. You send your message to the AI agent and watch the little status indicator say "Searching..." for what feels like forever.

This is the real world our infrastructure has to work in. Not the developer's laptop on gigabit fiber. Not the demo on a 5G connection in a conference room. The actual conditions where travelers use a travel app: airports, trains, international roaming, hotel lobbies with overloaded networks, and airplane mode transitions.

We spent a lot of time making our streaming pipeline work beautifully on fast connections. Then we spent even more time making it survive on terrible ones.

## The three hostile networks

![Illustration for this section](https://pics.nowah.xyz/website-media/infrastructure-003-img-1.webp)

Through production monitoring, we identified three network conditions that cause the most stream failures.

**Airport Wi-Fi** is the most common. It's congested, high-latency, and drops connections when you walk between terminals. The signal looks strong, but packet loss can be 10% or higher during peak hours. Our streams get interrupted not by losing connectivity entirely, but by packets getting dropped or delayed so badly that the connection times out.

**International roaming** brings a different challenge. Latency spikes to 300-800 milliseconds as packets route through carrier agreements across borders. Bandwidth might be fine, but the round-trip time means our streaming starts need longer buffers before declaring a timeout.

**Airplane mode transitions** are the sharpest edge case. The traveler lands, turns off airplane mode, and immediately starts using the app. The device reconnects to cellular, then maybe switches to airport Wi-Fi, then maybe switches back. Each transition can interrupt an active stream.

## Detecting that the stream died

The trickiest part of stream resilience isn't handling disconnections. It's knowing you're disconnected.

streaming connections sit on top of HTTP. When the server sends events, the client receives them. But when the server stops sending events (because it's waiting for the AI to generate more tokens), silence on the wire looks identical to a dead connection. The client can't tell the difference between "the AI is thinking" and "the network died."

We solve this with heartbeat events. The server sends a lightweight heartbeat every few seconds during active streams. If the client doesn't receive a heartbeat within a configured window, it knows something is wrong. This is different from a TCP-level keepalive. TCP keepalives operate at time scales too long for interactive applications. Our heartbeats fire frequently enough that we detect drops within seconds.

On the client side, we run a watchdog timer. Every time an event arrives (heartbeat, content, tool result, anything), the timer resets. If the timer expires, the client transitions to a "degraded" state and begins reconnection.

## Reconnection with exponential backoff

![Supporting diagram](https://pics.nowah.xyz/website-media/infrastructure-003-img-2.webp)

When the client decides the connection is dead, it doesn't just reconnect immediately. On bad networks, immediate reconnection often fails, which triggers another immediate attempt, which fails, which creates a tight retry loop that wastes battery and bandwidth.

Instead, we use exponential backoff with jitter. The first reconnection attempt fires within one second. If it fails, the next attempt waits two seconds, then four, then eight, with random jitter added to each interval. The jitter prevents thundering herd problems if many clients disconnect simultaneously (which happens when an airport Wi-Fi access point reboots).

We cap the backoff at 30 seconds. For a travel app, waiting more than 30 seconds between reconnection attempts is unacceptable. Beyond that threshold, we fall back to polling.

## Partial state recovery

Reconnecting the transport is only half the problem. The other half is knowing where you left off.

Every server streaming event carries a sequence number and a stream session ID. The client tracks both. When it reconnects, it sends the last received sequence number in the reconnection request. The server can then determine the right course of action.

If the AI is still generating the response, the server resumes the stream from the point after the last received sequence number. The client picks up where it left off with no visible interruption beyond a brief pause.

If the AI finished while the client was disconnected, the server sends the remaining events from a short-lived replay buffer. We keep the last few minutes of events in memory for each active session. Most reconnections happen within seconds, so this buffer is almost always sufficient.

If the replay buffer has expired (the client was disconnected for several minutes), the server sends the complete response as a single event. The client renders it as a complete message rather than streaming it token by token. The traveler misses the streaming animation but gets the full answer.

## Timeout tuning for mobile vs. desktop

We learned early that a single timeout configuration doesn't work across platforms. Our API client uses a 10-second timeout by default, but this needs adjustment for mobile under poor conditions.

On desktop (stable Wi-Fi, wired connections), 10 seconds is generous. If the server hasn't responded in 10 seconds, something is genuinely wrong.

On mobile, 10 seconds can be too aggressive. A cellular handoff might cause a 3-second stall. International roaming adds latency. We adjusted mobile timeouts to be more forgiving for the initial connection while keeping tight timeouts for individual events within an established stream.

The [distinction matters](/blog/ai-agents-vs-chatbots-distinction-matters). A long initial timeout says "I'm patient about connecting." A short event timeout says "Once connected, I expect data to flow." This combination handles slow network negotiation without tolerating silently broken streams.

## What the traveler actually sees

All this machinery should be invisible when it works. Here's what the traveler experiences during a network interruption:

Good case (reconnection within 2 seconds): The streaming text pauses briefly, a subtle reconnection indicator appears, then the text resumes. Most travelers don't even notice unless they're watching closely.

Medium case (reconnection within 10 seconds): The streaming pauses. A clear "Reconnecting..." message appears. The stream resumes and catches up to where the AI has gotten in the meantime. Tokens appear slightly faster as the client renders buffered events.

Bad case (reconnection fails): After several retries, the client shows a "Connection lost" message with a retry button. If the traveler taps retry when network conditions improve, the full response loads at once if the AI has finished processing.

The goal at every level is honest communication. We never show a spinner with no context. We never pretend the connection is fine when it isn't. We never silently fail.

## Measuring resilience in production

We track stream completion rate as our primary resilience metric. This is the percentage of streams that deliver the complete response to the client, including reconnections.

A stream that gets interrupted and reconnects successfully still counts as completed. A stream where the client had to fall back to a REST call after reconnection failed counts as degraded. A stream where the client gave up entirely counts as failed.

Our target is above 95% completion rate even under poor network conditions. We segment this metric by network type (Wi-Fi, cellular, roaming) and by geography (airports, cities, rural) to identify patterns.

The most useful thing we've found is correlating completion rate with specific airports. Some airports have notoriously bad Wi-Fi. Knowing that helps us tune our reconnection parameters for conditions we can predict rather than just react to.

## A resilience checklist for server streaming on mobile

If you're building streaming features for mobile users, here's what we wish someone had told us at the start.

Don't trust the network status API. Browsers and mobile OS report "online" when you have a connection, not when that connection actually works. A device connected to airport Wi-Fi is "online" but might have 40% packet loss.

Implement heartbeats at the application level. TCP keepalives are too slow. Application-level heartbeats every few seconds let you detect broken connections quickly.

Make reconnection invisible when possible. If you can reconnect and resume within two seconds, the traveler shouldn't need to do anything. Only surface the disconnection to the user when it lasts long enough to matter.

Always have a fallback path. Streaming is the preferred delivery mechanism, not the only one. If streaming fails completely, the response should still be retrievable via a standard request once the AI finishes processing.

Test on real bad networks, not simulated ones. Network simulation tools are useful but incomplete. They can simulate high latency or packet loss, but they don't capture the chaotic, bursty nature of real airport Wi-Fi. Test on actual bad networks. Your team travels. Make them test the app at airports.

---

Nowah is an AI travel agent that searches and books real flights and hotels through conversation — no filters, no thirty open tabs. [Plan your next trip](https://app.nowah.xyz).
