Every held poll on Android was failing at ten seconds

`heldHttp` raised `callTimeout` to the hold plus twenty and left `readTimeout`
at OkHttp's default of TEN SECONDS. A held poll asks the relay to say nothing
for up to twenty. So every one died at ten with a SocketTimeoutException, and
the generous call timeout above it never got the chance to matter.

Nothing said so. The failure was swallowed into a retry, the loop looked busy,
and the only trace was a number on the relay: this device took an average of
112 seconds to collect what was waiting for it, against 5 for an iPhone. A
message written into a connection this end had already abandoned waited for
the next poll instead of arriving.

That is why calling an iPhone took forever, why "connecting..." never
resolved, and why the call then ended: the answer was on the relay the whole
time and the dial guard gave up at forty-five seconds waiting for a fetch that
could not succeed.

Measured on the device, before and after, once the loop was made to say what
it was doing:

    vm cycle 10125ms held=20s call=false failed=SocketTimeoutException
    vm cycle 20304ms held=20s call=false got=0

TWO POLLS, AND I FIXED THE ONE THAT WAS SWITCHED OFF

`MessengerService` and the view model both poll, and the activity stops the
service on the way in -- "exactly one poller at a time". Placing a call is
exactly when the app is on screen, so the service is stopped and the view
model is the poller. The twenty-second hold during a call was fixed in the
service first. The loop that was running kept it.

Both ask for no hold during a call now.

AND THE LOOP CAN SAY WHAT IT COST

One line per cycle: how long it took, how long it was allowed to hold, whether
a call was up, and what came back or what failed. Two rounds were spent
reading an empty trace as "the loop is not running" when it was "the loop has
no voice", and the bug above was invisible for as long as it was because a
failing poll and a quiet one look identical from outside the process.

1619 tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Paul Hitt
2026-09-14 18:19:02 -04:00
co-authored by Claude Opus 5
parent 7d8b721a49
commit 7ccec9e3d1
6 changed files with 192 additions and 6 deletions
+10 -2
View File
@@ -40,8 +40,16 @@ android {
// the paragraph above, so the code keeps climbing and the NAME is what
// closes the 0.10 -> 0.12 gap. They are allowed to differ: the code is
// ordering, the name is what a person reads.
versionCode = 21
versionName = "0.19"
// The NAME is what the website and the app show a person, and it now
// matches the code rather than trailing it: somebody comparing the
// download page against their own app should not have to know that one
// number is ordering and the other is a label.
//
// The code goes to 22 because 21 is published and a code is never
// reused. So they line up as closely as they can from here: name 0.21,
// code 22, and each release from now moves both.
versionCode = 22
versionName = "0.21"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}