Problem
When the app spots a gap in the server's update IDs it fetches the missing range with GetMissingOnyxMessages. Production traces show a failure mode where the server keeps answering that fetch with a 200 that carries no usable updates. The client never advances, so every incoming Pusher update re-detects the same gap and fires the same fetch again, about once per second (traces show 12 to 47 requests in a row). The earlier fix in #93948 only stopped fetches that overlap in time; it cannot stop this loop because each fetch finishes before the next one starts.
Solution
This PR treats one useless answer as proof instead of retrying. A successful fetch must advance the client past the update ID it was fired from, checked via response.lastUpdateID so it does not race the Onyx write. The first 200 that fails this check escalates to a single incremental ReconnectApp from the client's current update ID (deduplicated by the SequentialQueue). Until the client advances, further fetches from the same client state are skipped while the SequentialQueue still resumes each cycle. Both the gap branch and the pending-updates branch of OnyxUpdateManager share this guard, and a Log.alert captures client and response update IDs for monitoring.
PR
#95477
Issue Owner
Current Issue Owner: @adhorodyski
Problem
When the app spots a gap in the server's update IDs it fetches the missing range with
GetMissingOnyxMessages. Production traces show a failure mode where the server keeps answering that fetch with a 200 that carries no usable updates. The client never advances, so every incoming Pusher update re-detects the same gap and fires the same fetch again, about once per second (traces show 12 to 47 requests in a row). The earlier fix in #93948 only stopped fetches that overlap in time; it cannot stop this loop because each fetch finishes before the next one starts.Solution
This PR treats one useless answer as proof instead of retrying. A successful fetch must advance the client past the update ID it was fired from, checked via
response.lastUpdateIDso it does not race the Onyx write. The first 200 that fails this check escalates to a single incrementalReconnectAppfrom the client's current update ID (deduplicated by the SequentialQueue). Until the client advances, further fetches from the same client state are skipped while the SequentialQueue still resumes each cycle. Both the gap branch and the pending-updates branch ofOnyxUpdateManagershare this guard, and aLog.alertcaptures client and response update IDs for monitoring.PR
#95477
Issue Owner
Current Issue Owner: @adhorodyski