The connection follows the app lifecycle
In Whistler, the Socket.IO connection is tied to the app’s state. It disconnects when the app goes to the background and reconnects when it returns. Holding a socket open in the background wastes battery, and the operating system will close it anyway — better to make that transition explicit than to discover it in a bug report.
All of this lives in one socket context rather than in individual screens, so there is exactly one place that decides when the app is connected.
Reconnection is bounded
Automatic reconnection uses backoff: five attempts, starting at one second and growing to ten. Unbounded, aggressive retries turn a server incident into a self-inflicted load spike.
Decide what survives a disconnect
Some events matter enough to keep. View events are written to an on-device queue before they are sent, so they survive the app being killed while backgrounded. The queue is capped at 50 entries, flushes only when the socket reports connected, and only one flush runs at a time.
Just as important is what doesn’t get queued. Every buffered event is a decision about consistency and storage, and that decision belongs in code review, not in an accident.
Treat inbound data as untrusted
Socket payloads are checked for required fields before they enter state; malformed messages are logged and dropped rather than rendered. The same principle applies to REST: validate at the boundary and keep the server as the source of truth.
Centralise auth at the API client
Auth headers and 401 handling live in the Axios client’s interceptors, not in screens. The interceptor only signals session expiry when a token was actually set, so an unauthenticated request can’t log someone out. At SeamHealth I designed and consumed REST APIs with JWT authentication and role-based access, and the rule there was the same: the client can hide what a user can’t do, but only the server can enforce it.
Make a service’s limits explicit
The Device Intelligence service I built in FastAPI runs its background jobs — similarity recalculation, duplicate merging, risk updates, session expiry — inside the API process. That keeps local setup to a pip install, but it means every replica would run every job. So the worker count is pinned to one and the README says, in bold, not to scale it out until the scheduler moves out of process.
The same service fails closed: it refuses to start in production with the development secret key, and it trusts X-Forwarded-For only from configured proxy addresses. In a security service, defaults are decisions.
- A written limit is safer than a clever workaround nobody understands.
- A failed deploy is cheaper than a running service with forgeable tokens.