ryer.io

The Requests That Never Reached the Server

TL;DR

  • refreshCohortContent was being called on both platforms, but its body wasn’t executing.
  • Server middleware logging every request.url confirmed the calls never arrived.
  • Calling Axios directly, bypassing our wrapper, made the requests go through.
  • The wrapper deduplicates on a generated key that didn’t include the URL, so different calls collided.
  • Adding the URL to the key fixed it, though getWeeklyCohortContent still had a promise resolution issue by end of day.

A long, circular day chasing requests that appeared to be sent and never arrived.

Establishing the facts

The symptom was user data not caching correctly after an update, on both Android and iOS.

Console logs at the call site confirmed refreshCohortContent was being called on both platforms. But the block inside the function wasn’t logging, which pointed at memoization swallowing the call rather than the call never happening.

I tried changing the Android system date back a day to force a different index fetch and see whether stale cache explained the behaviour. That showed something else: data wasn’t being cached after an update at all, so every render or app load forced a fresh update. The opposite of the problem I thought I had.

Then I checked the server side and the console logs weren’t there either.

Proving it properly

Rather than infer from missing logs, I added simple middleware at the server entry point logging every request’s URL. Unambiguous: no client request for that endpoint reached the server. Other calls were logging fine, so the server and its logging were healthy.

That’s the moment the problem got much smaller. The client thinks it’s sending, the server never receives, and everything in between is ours.

Finding it

I bypassed our intermediate logic and used the Axios instance directly. The request went through immediately.

So the fault is in the wrapper. Our network call utility deduplicates requests based on a generated key — a reasonable optimisation to stop identical calls firing repeatedly. But the key didn’t adequately include the request URL. Two different endpoints could generate the same key, and the second call would be treated as a duplicate of the first and served a cached response instead of being sent.

The fix is to include the URL in the key construction so distinct calls are treated as distinct.

Worth noting what this wasn’t: there were no HTTP 304s anywhere, which rules out network-level caching. This was entirely our own deduplication logic, which is why nothing in the browser or platform tooling showed it.

Not finished

Later in the day the symptom hadn’t fully cleared. Tests were failing because mocks weren’t applied, and I isolated remaining trouble in getWeeklyCohortContent, where promise resolution is the suspect.

Plan for tomorrow: clear caches, rebuild, and look again at the deterministic key for overlaps I haven’t spotted. The dedup key was a real bug and fixing it was right, but it evidently wasn’t the only thing here.

A good reminder how much time a small undetected glitch can eat — helped along by real-world interruptions, and by my having to tell our product owner a task would be late.