🇷🇺 Что нового (RU)
Коротко
v1.7.0 доводит до конца историю с зависанием iOS в «обновлении» после фона. Гипотеза из v1.6.0 (коллапс congestion window) оказалась неверной и опровергнута живой диагностикой; здесь — настоящая причина и точечный воркэраунд. Поведение по умолчанию не меняется (фича выключена), апгрейд безопасен.
Что нашли (настоящая причина)
Это баг клиента iOS, не прокси. После долгого фона у аккаунта протухает server salt. DC отвечает bad_server_salt за ~280мс и сразу кладёт туда новую валидную соль, но MtProtoKit применяет её только если отвергнут специальный time-fix ping; на обычный запрос соль выбрасывается, сессия встаёт в MTProtoStateAwaitingTimeFixAndSalts, и ни один запрос из очереди не уходит. Выйти нечем (у time-fix контекста нет таймаута, 12с/5с таймеры разармятся входящим ответом, sleep-watchdog закомментирован с 2014). Сессия молчит, пока DC сам не закроет сокет (~90–120с) — это и есть бесконечное «обновление». На Android (tgnet) этого нет, он гасит idle-коннекты через ~10с фона.
Апстрим-PR с настоящим фиксом (применять соль из bad_server_salt всегда): TelegramMessenger/Telegram-iOS#2197.
Что добавили (воркэраунд на стороне прокси)
Новая opt-in опция client_silence_close_sec (по умолчанию 0 = выкл). Закрывает релей, если последним по проводу был ответ сервера, а клиент не ответил N секунд — это форсит чистый реконнект (~450мс), который у iOS как раз снимает затык. Срабатывает только когда последним был s2c, поэтому здоровый idle-коннект (чьё последнее слово — свой пинг/ack) не трогается. На проде с порогом 10с «обновление» вместо ~90с проходит за ~10с. Это best-effort, не лечение: прокси слеп к шифрованному MTProto, поэтому значение ниже самого медленного легитимного ответа изредка закроет и здоровый коннект (лишний ~450мс реконнект). Настраивается под себя.
[server]
client_silence_close_sec = 10 # 0 = выкл (дефолт); ~10-15 как отправная точкаУдалено
max_connection_lifetime_sec (из v1.6.0) убран — он бил по неверной гипотезе. Неизвестные ключи конфига игнорируются, так что оставшаяся строка безвредна; замена — client_silence_close_sec.
Проверено
zig build test зелёный + кросс-сборки + install-матрица (debian 11/12, ubuntu 20.04/22.04/24.04) + E2E + bench. Воркэраунд подтверждён на живом проде.
🇬🇧 Release notes (EN)
TL;DR
v1.7.0 closes out the iOS "Updating" hang on resume. The v1.6.0 hypothesis (congestion-window collapse) was wrong and disproven by live diagnostics; this ships the real root cause plus a targeted workaround. Defaults are unchanged (the feature is off), upgrading is safe.
What it actually is
An iOS client bug, not the proxy. After a long background the account's cached server salt is stale. The DC replies bad_server_salt in ~280ms with a fresh valid salt, but MtProtoKit only applies it when the rejected message is the dedicated time-fix ping; for an ordinary request the salt is discarded and the session enters MTProtoStateAwaitingTimeFixAndSalts, which gates every outgoing transaction. Nothing recovers it (the time-fix context has no timeout, the 12s/5s watchdogs disarm on the incoming reply, the sleep watchdog is #if false since 2014), so the session is silent until the DC closes the socket (~90–120s) — the infinite "Updating". Android (tgnet) avoids it by tearing down idle connections ~10s into background.
Upstream PR with the real fix (apply the salt from bad_server_salt unconditionally): TelegramMessenger/Telegram-iOS#2197.
What this adds (proxy-side workaround)
New opt-in option client_silence_close_sec (default 0 = off). Closes a relay when the last relayed payload was server→client and the client hasn't answered for N seconds, forcing the clean reconnect (~450ms) that recovers the iOS client. It fires only when the server spoke last, so a healthy idle connection (whose last word was its own ping/ack) is never touched. On prod at 10s, "Updating" clears in ~10s instead of ~90s. It is best-effort, not a cure: the proxy can't read the encrypted MTProto stream, so a value below your slowest legitimate response will occasionally close a healthy connection too (just a ~450ms reconnect). Tune to taste.
[server]
client_silence_close_sec = 10 # 0 = off (default); ~10-15 as a starting pointRemoved
max_connection_lifetime_sec (from v1.6.0) is gone — it targeted the wrong hypothesis. Unknown config keys are ignored, so a leftover entry is harmless; its replacement is client_silence_close_sec.
Verified
zig build test green + cross-builds + install matrix (debian 11/12, ubuntu 20.04/22.04/24.04) + E2E + bench. The workaround is confirmed on live prod.
Full Changelog: v1.6.0...v1.7.0