mirror of
https://github.com/telemt/telemt.git
synced 2026-11-01 13:21:58 +03:00
Retry Jitter in Docs
This commit is contained in:
@@ -311,6 +311,20 @@ Example — replace `[[server.listeners]]` (other `[server]` fields including `[
|
|||||||
{"server": {"listeners": [{"ip": "0.0.0.0", "port": 443, "client_mss": "92"}]}}
|
{"server": {"listeners": [{"ip": "0.0.0.0", "port": 443, "client_mss": "92"}]}}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### WEB retry jitter configuration
|
||||||
|
|
||||||
|
The managed `web.retry_jitter` object supports `enabled`, `min_ms`, `max_ms`,
|
||||||
|
`distribution` (`uniform` or `triangular`) and optional triangular `peak_ms`.
|
||||||
|
Validation is identical to file configuration, including when disabled. Reload
|
||||||
|
updates newly rendered bridge pages without a process restart. Existing pages
|
||||||
|
retain their policy through recovery; the recovery representation is unchanged.
|
||||||
|
Require `0 <= min_ms <= max_ms <= 30000`; an explicit `peak_ms` is valid only
|
||||||
|
with `triangular` and must lie within that interval. Unknown keys and
|
||||||
|
distributions are rejected. The range is an additive delay, not the total pause.
|
||||||
|
See [retry jitter parameters](../../Config_params/CONFIG_PARAMS.en.md#webretry_jitter)
|
||||||
|
and the [WEB guide](../../WEB/WEB_PROXY.en.md#configurable-http-retry-jitter)
|
||||||
|
for defaults, budgets and compatibility semantics.
|
||||||
|
|
||||||
### `RotateSecretRequest`
|
### `RotateSecretRequest`
|
||||||
| Field | Type | Required | Description |
|
| Field | Type | Required | Description |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
@@ -417,7 +431,7 @@ for `POST /v1/runtime/web/lifecycle/pause` and `/resume`, and:
|
|||||||
|
|
||||||
for `POST /v1/runtime/web/lifecycle/drain`, where `timeout_secs` is bounded to `1..=3600`. Pause and resume return `200`; drain freezes one monotonic absolute deadline and returns `202` without waiting for completion. A second drain while one is `draining` or `force_closing` returns `409 web_lifecycle_in_progress` and cannot alter the first deadline. Repeated pause/resume requests already satisfied by the current state are idempotent and do not advance the lifecycle epoch. Pause during an active drain leaves that drain running. Resume cancels an active drain and opens admission; if the deadline already committed its forced-close snapshot, those old session close signals remain effective.
|
for `POST /v1/runtime/web/lifecycle/drain`, where `timeout_secs` is bounded to `1..=3600`. Pause and resume return `200`; drain freezes one monotonic absolute deadline and returns `202` without waiting for completion. A second drain while one is `draining` or `force_closing` returns `409 web_lifecycle_in_progress` and cannot alter the first deadline. Repeated pause/resume requests already satisfied by the current state are idempotent and do not advance the lifecycle epoch. Pause during an active drain leaves that drain running. Resume cancels an active drain and opens admission; if the deadline already committed its forced-close snapshot, those old session close signals remain effective.
|
||||||
|
|
||||||
Pause and drain block bootstrap issuance, initial/replacement session creation, and logical-stream admission. Exact session-creation replay, existing DATA/WINDOW/CLOSE, carrier polling/WebSocket exchanges, and explicit session DELETE remain available. Rejection does not consume bootstrap/session/stream rate or quota state: authenticated session creation returns retryable `503` with `Retry-After: 1`, while bridge issuance preserves the decoy route and a rejected logical `OPEN` receives a stream-local close.
|
Pause and drain block bootstrap issuance, initial/replacement session creation, and logical-stream admission. Exact session-creation replay, existing DATA/WINDOW/CLOSE, carrier polling/WebSocket exchanges, and explicit session DELETE remain available. Rejection does not consume bootstrap/session/stream rate or quota state: authenticated session creation returns retryable `503` with `Retry-After: 1` and `X-Telemt-Retry-After-Ms: 250`, while bridge issuance preserves the decoy route and a rejected logical `OPEN` receives a stream-local close.
|
||||||
|
|
||||||
Drain remains graceful until either all live sessions, logical-stream ownership, and session-owned WebSockets reach zero or its deadline fires. The deadline is the latest time to commit close signals, not a claim that cooperative task teardown is already complete. At the deadline every remaining live session receives an idempotent close signal outside manager locks, status becomes `force_closing`, and only confirmed zero publishes `drained` with outcome `forced`. Natural zero publishes outcome `graceful`. Both outcomes keep operator admission closed until explicit resume.
|
Drain remains graceful until either all live sessions, logical-stream ownership, and session-owned WebSockets reach zero or its deadline fires. The deadline is the latest time to commit close signals, not a claim that cooperative task teardown is already complete. At the deadline every remaining live session receives an idempotent close signal outside manager locks, status becomes `force_closing`, and only confirmed zero publishes `drained` with outcome `forced`. Natural zero publishes outcome `graceful`. Both outcomes keep operator admission closed until explicit resume.
|
||||||
|
|
||||||
|
|||||||
@@ -2616,11 +2616,11 @@ Der WEB-Modus transportiert MTProxy-Datenverkehr von Telegram Desktop über HTTP
|
|||||||
| `timeouts` | Tabelle | begrenzte Defaults | `✔` |
|
| `timeouts` | Tabelle | begrenzte Defaults | `✔` |
|
||||||
| `vhosts` | Tabellen-Array | `[]` | `✔` |
|
| `vhosts` | Tabellen-Array | `[]` | `✔` |
|
||||||
|
|
||||||
`enabled = true` erfordert mindestens einen durch die Netzwerkrichtlinie zugelassenen WEB-Listener, einen vhost und mindestens ein Profil in jedem vhost. `https` behält den serialisierten HTTPS-Transport bei und erfordert `max_http_handlers >= 2`. Mit `https-lanes` erhalten Stream null und jeder logische Stream eigene Uplink-Sequenzen, Downlink-Cursor, Wiederholungen und Long Polls; dieser Carrier erfordert `max_http_handlers >= 4` und öffentliches HTTP/2 am TLS-Terminator. `websocket` transportiert alle logischen Streams über eine geordnete RFC-6455-Verbindung, während `websocket-lanes` jedem Stream ungleich null eine eigene Verbindung zuweist und Lane-Fehler isoliert. Beide WebSocket-Carrier verwenden nach der HTTPS-Sitzungserstellung `GET /api/v1/ws` und erfordern, dass der TLS-Terminator die HTTP/1.1-Upgrade-Header unverändert weiterleitet.
|
`enabled = true` erfordert mindestens einen durch die Netzwerkrichtlinie zugelassenen WEB-Listener, einen vhost und mindestens ein Profil in jedem vhost. `https` verwendet eine gemeinsame HTTPS-Uplink-Sequenz mit einem ausgehandelten Upload-Fenster von 1–4 und erfordert `max_http_handlers >= 2`. Mit `https-lanes` erhalten Stream null und jeder logische Stream eigene Uplink-Sequenzen, Downlink-Cursor, Wiederholungen und Long Polls; dieser Carrier erfordert `max_http_handlers >= 4` und öffentliches HTTP/2 am TLS-Terminator. `websocket` transportiert alle logischen Streams über eine geordnete RFC-6455-Verbindung, während `websocket-lanes` jedem Stream ungleich null eine eigene Verbindung zuweist und Lane-Fehler isoliert. Beide WebSocket-Carrier verwenden nach der HTTPS-Sitzungserstellung `GET /api/v1/ws` und erfordern, dass der TLS-Terminator die HTTP/1.1-Upgrade-Header unverändert weiterleitet.
|
||||||
|
|
||||||
Fehlt `carriers` oder ist es `false`, sind Auto-Negotiation und Lernen deaktiviert und `carrier` ist der einzige Modus. Ein nicht leeres `carriers`-Array aktiviert die Start-Negotiation in der konfigurierten Reihenfolge; `carrier` wird genau einmal als letzter Fallback angehängt. Leere Arrays, Duplikate und `true` werden abgelehnt. Der Client darf nur vor dem Carrier-Commit zum nächsten Kandidaten wechseln; nach dem Commit erfordert ein Carrier-Wechsel eine neue Sitzung. Ein nativer Client ohne Metadaten, einschließlich Telegram iOS, verwendet immer den konfigurierten festen `carrier`, auch bei aktivierter Negotiation. Das aktuelle iOS unterstützt nur `https`; solche Bereitstellungen müssen daher `carrier = "https"` setzen. Die CFNetwork- und Darwin-User-Agent-Klassifizierung leitet keine Carrier-Unterstützung ab. Explizite native iOS-Capabilities werden mit `{https}` geschnitten; andere explizite Client-Capabilities gelten wie gemeldet.
|
Fehlt `carriers` oder ist es `false`, sind Auto-Negotiation und Lernen deaktiviert und `carrier` ist der einzige Modus. Ein nicht leeres `carriers`-Array aktiviert die Start-Negotiation in der konfigurierten Reihenfolge; `carrier` wird genau einmal als letzter Fallback angehängt. Leere Arrays, Duplikate und `true` werden abgelehnt. Der Client darf nur vor dem Carrier-Commit zum nächsten Kandidaten wechseln; nach dem Commit erfordert ein Carrier-Wechsel eine neue Sitzung. Ein nativer Client ohne Metadaten, einschließlich Telegram iOS, verwendet immer den konfigurierten festen `carrier`, auch bei aktivierter Negotiation. Das aktuelle iOS unterstützt nur `https`; solche Bereitstellungen müssen daher `carrier = "https"` setzen. Die CFNetwork- und Darwin-User-Agent-Klassifizierung leitet keine Carrier-Unterstützung ab. Explizite native iOS-Capabilities werden mit `{https}` geschnitten; andere explizite Client-Capabilities gelten wie gemeldet.
|
||||||
|
|
||||||
`http_connection_capacity_action` gilt erst, nachdem Telemt eine private WEB-TCP-Verbindung akzeptiert hat und `max_http_connections` ausgeschöpft ist. `drop` schließt wie bisher sofort. `respond` sendet eine leere wiederholbare `503 Service Unavailable` mit `Retry-After: 1`, `Cache-Control: no-store` und `Connection: close`. `wait` wartet höchstens `http_overload_timeout_ms` auf normale Kapazität und beginnt danach die übliche HTTP-Verarbeitung; bei Timeout wird dieselbe begrenzte `503` gesendet. Höchstens `max_http_overload_connections` akzeptierte Sockets dürfen außerhalb der normalen Kapazität warten oder antworten.
|
`http_connection_capacity_action` gilt erst, nachdem Telemt eine private WEB-TCP-Verbindung akzeptiert hat und `max_http_connections` ausgeschöpft ist. `drop` schließt wie bisher sofort. `respond` sendet eine leere wiederholbare `503 Service Unavailable` mit `Retry-After: 1`, `X-Telemt-Retry-After-Ms: 250`, `Cache-Control: no-store` und `Connection: close`. `wait` wartet höchstens `http_overload_timeout_ms` auf normale Kapazität und beginnt danach die übliche HTTP-Verarbeitung; bei Timeout wird dieselbe begrenzte `503` gesendet. Höchstens `max_http_overload_connections` akzeptierte Sockets dürfen außerhalb der normalen Kapazität warten oder antworten.
|
||||||
|
|
||||||
`decoy_fasttrack_mode` ist restart-only und betrifft nur Capability-Arbeit für `GET/HEAD` am konfigurierten Basis-Root. `off` behält den vollständigen Scan bei, `shadow` zählt geeignete Requests ohne den Scan zu überspringen, und `enforce` überspringt ihn nur für `HEAD` oder eine fehlende/nicht kanonische `bridge`-Query. Ein kanonisch geformtes Bridge-`GET` scannt immer alle Profile des ausgewählten vhost. Die Optimierung begrenzt keine feindlichen kanonischen Probes; `enforce` muss hinter dem produktiven TLS-Terminator auf Timing-Unterscheidbarkeit geprüft werden.
|
`decoy_fasttrack_mode` ist restart-only und betrifft nur Capability-Arbeit für `GET/HEAD` am konfigurierten Basis-Root. `off` behält den vollständigen Scan bei, `shadow` zählt geeignete Requests ohne den Scan zu überspringen, und `enforce` überspringt ihn nur für `HEAD` oder eine fehlende/nicht kanonische `bridge`-Query. Ein kanonisch geformtes Bridge-`GET` scannt immer alle Profile des ausgewählten vhost. Die Optimierung begrenzt keine feindlichen kanonischen Probes; `enforce` muss hinter dem produktiven TLS-Terminator auf Timing-Unterscheidbarkeit geprüft werden.
|
||||||
|
|
||||||
@@ -2704,6 +2704,38 @@ Diese prozessweiten Obergrenzen begrenzen alle WEB-Register, Warteschlangen, Req
|
|||||||
| `new_streams_per_minute` | `u32` | `6000` | Nachhaltige Erstellungsrate für logische Streams. |
|
| `new_streams_per_minute` | `u32` | `6000` | Nachhaltige Erstellungsrate für logische Streams. |
|
||||||
| `new_streams_burst` | `u32` | `512` | Prozessweiter Burst für die Stream-Erstellung. |
|
| `new_streams_burst` | `u32` | `512` | Prozessweiter Burst für die Stream-Erstellung. |
|
||||||
|
|
||||||
|
# [web.retry_jitter]
|
||||||
|
|
||||||
|
| Schlüssel | Typ | Standard | Beschreibung |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `enabled` | `bool` | `false` | Aktiviert additiven Retry-Jitter. |
|
||||||
|
| `min_ms` | `u32` | `0` | Inklusiver minimaler Zuschlag in Millisekunden. |
|
||||||
|
| `max_ms` | `u32` | `250` | Inklusiver maximaler Zuschlag in Millisekunden; höchstens `30000`. |
|
||||||
|
| `distribution` | `string` | `"uniform"` | `uniform` oder `triangular`. |
|
||||||
|
| `peak_ms` | `Option<u32>` | `—` | Spitze der Dreiecksverteilung; ohne Angabe die Intervallmitte. |
|
||||||
|
|
||||||
|
`[web.retry_jitter]` ergänzt jeden bestehenden HTTP-Retry der Bridge um eine unabhängig gewählte Verzögerung: Netzwerkfehler und Antworten mit 408/429/502/503/504. Telegram-Anwendungen müssen nicht geändert werden. Ohne diesen Abschnitt oder mit `enabled = false` bleiben der 250-ms-Hinweis von Telemt und das bisherige Backoff/Jitter-Verhalten erhalten.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[web.retry_jitter]
|
||||||
|
enabled = true
|
||||||
|
min_ms = 0
|
||||||
|
max_ms = 250
|
||||||
|
distribution = "uniform"
|
||||||
|
# Only for distribution = "triangular":
|
||||||
|
# peak_ms = 125
|
||||||
|
```
|
||||||
|
|
||||||
|
Der Bereich beschreibt einen **Zuschlag**, nicht die gesamte Pause: Zusammen mit dem Telemt-Hinweis von 250 ms ergibt dieses Beispiel 250–500 ms. Ohne positiven Serverhinweis bleibt die Basis bei 250, 500, 1000, dann 2000 ms. Aktivierter Jitter ersetzt den bisherigen Jitter von bis zu 25%. Ein gültiger standardmäßiger `Retry-After` wird im aktivierten Modus nicht auf die bisherige Grenze von 30 Sekunden verkürzt. Übersteigt die Pause das verbleibende Operationsbudget, läuft das Budget ohne vorzeitigen Retry ab.
|
||||||
|
|
||||||
|
Standardwerte: `enabled = false`, `min_ms = 0`, `max_ms = 250`, `distribution = "uniform"`, ohne `peak_ms`. Es gilt `0 <= min_ms <= max_ms <= 30000`. `uniform` verteilt ganze Millisekunden gleichmäßig; `triangular` verwendet eine Dreiecksverteilung mit Rundung auf Millisekunden. Der optionale Gipfel liegt standardmäßig in der Mitte und muss innerhalb des Intervalls liegen. Ein expliziter Gipfel bei `uniform`, unbekannte Schlüssel/Verteilungen und ungültige Grenzen werden auch im deaktivierten Zustand abgelehnt. Gleiche Grenzen ergeben einen konstanten Zuschlag.
|
||||||
|
|
||||||
|
Die Richtlinie wird pro Bridge-Seite festgeschrieben. Konfigurations-/API-Reload wirkt auf neu geladene Seiten; bestehende Seiten behalten ihre Einstellungen bei Recovery. Recovery-JSON und HTTP-Kompatibilitätsheader bleiben unverändert. Die Auswahl bevorzugt `crypto.getRandomValues`, mit `Math.random` als Kompatibilitätsfallback. Erfolgreicher Datenverkehr wird nicht verzögert. Versuchslimits, absolute Budgets, Abbruch und unveränderte Payload-/Sequence-Wiederholung bleiben erhalten; längere Pausen können die Anzahl der Versuche innerhalb eines Startup-/Recovery-Budgets reduzieren.
|
||||||
|
|
||||||
|
Dies streut feste Retry-Intervalle, garantiert aber keinen Schutz vor DPI. Browser-Scheduling, Netzwerkwarteschlangen und andere Protokollzeiten bleiben beobachtbar. Bestehende Zeitleisten zeigen den deaktivierten Standardmodus. Bei aktiviertem Modus wird zu jeder Retry-Pause eine gezogene Verzögerung addiert, nicht zum ersten Verbindungsaufbau oder zu jedem Datenframe.
|
||||||
|
|
||||||
|
Die Richtlinie ändert nur bereits vorhandene Retry-Pausen. Strengere Limits einzelner Aufrufe bleiben erhalten: Reguläre `/down`-Polls und `/up`-Aufrufe nach dem Commit führen einen Versuch aus; ihr Recovery-Replay erlaubt zwei. Die Option erzeugt keine neuen Retry-Schleifen. Sie verlängert weder `web.timeouts.bridge_retry_secs` noch Start- oder Recovery-Deadlines.
|
||||||
|
|
||||||
# [web.timeouts]
|
# [web.timeouts]
|
||||||
|
|
||||||
Sofern eine Zeile nichts anderes angibt, werden Timeouts in Sekunden angegeben und müssen im Bereich `1..=3600` liegen. Konfigurierte serverseitige Deadlines einzelner HTTP-Phasen müssen kleiner als `http_idle_secs` sein; geschützte Phasen behalten ihre eigenen Deadlines, sodass der Idle-Timer keine Gesamtdeadline für einen Request ist. Das clientseitige Bridge-Retry-Fenster hat eigene Grenzen.
|
Sofern eine Zeile nichts anderes angibt, werden Timeouts in Sekunden angegeben und müssen im Bereich `1..=3600` liegen. Konfigurierte serverseitige Deadlines einzelner HTTP-Phasen müssen kleiner als `http_idle_secs` sein; geschützte Phasen behalten ihre eigenen Deadlines, sodass der Idle-Timer keine Gesamtdeadline für einen Request ist. Das clientseitige Bridge-Retry-Fenster hat eigene Grenzen.
|
||||||
|
|||||||
@@ -2616,11 +2616,11 @@ WEB mode carries Telegram Desktop MTProxy traffic through HTTPS terminated by an
|
|||||||
| `timeouts` | table | bounded defaults | `✔` |
|
| `timeouts` | table | bounded defaults | `✔` |
|
||||||
| `vhosts` | array of tables | `[]` | `✔` |
|
| `vhosts` | array of tables | `[]` | `✔` |
|
||||||
|
|
||||||
`enabled = true` requires at least one network-eligible WEB listener, at least one vhost, and at least one profile in every vhost. `https` preserves the serialized HTTPS transport and requires `max_http_handlers >= 2`. `https-lanes` gives stream zero and every logical stream independent uplink sequencing, downlink cursors, retries, and long polls; it requires `max_http_handlers >= 4` and public HTTP/2 on the TLS terminator. `websocket` carries all logical streams over one ordered RFC 6455 connection, while `websocket-lanes` owns one connection per non-zero logical stream and isolates lane failures. Both WebSocket carriers use `GET /api/v1/ws` after HTTPS session creation and require the TLS terminator to preserve HTTP/1.1 Upgrade headers.
|
`enabled = true` requires at least one network-eligible WEB listener, at least one vhost, and at least one profile in every vhost. `https` uses a shared HTTPS uplink sequence with a negotiated upload window of 1–4 and requires `max_http_handlers >= 2`. `https-lanes` gives stream zero and every logical stream independent uplink sequencing, downlink cursors, retries, and long polls; it requires `max_http_handlers >= 4` and public HTTP/2 on the TLS terminator. `websocket` carries all logical streams over one ordered RFC 6455 connection, while `websocket-lanes` owns one connection per non-zero logical stream and isolates lane failures. Both WebSocket carriers use `GET /api/v1/ws` after HTTPS session creation and require the TLS terminator to preserve HTTP/1.1 Upgrade headers.
|
||||||
|
|
||||||
When `carriers` is missing or `false`, auto-negotiation and learning are disabled and `carrier` is the only mode. A non-empty `carriers` array enables startup-only negotiation in its configured order; `carrier` is appended exactly once as the final fallback. Empty arrays, duplicates, and `true` are rejected. The client advances candidates only before carrier commit and must create a new session to change carrier after commit. A metadata-free native client, including Telegram iOS, always uses the configured fixed `carrier`, even when negotiation is enabled. Current iOS supports only `https`, so such deployments must configure `carrier = "https"`. CFNetwork and Darwin User-Agent classification does not infer carrier support. Explicit native iOS capabilities are intersected with `{https}`; other explicit client capabilities participate as reported.
|
When `carriers` is missing or `false`, auto-negotiation and learning are disabled and `carrier` is the only mode. A non-empty `carriers` array enables startup-only negotiation in its configured order; `carrier` is appended exactly once as the final fallback. Empty arrays, duplicates, and `true` are rejected. The client advances candidates only before carrier commit and must create a new session to change carrier after commit. A metadata-free native client, including Telegram iOS, always uses the configured fixed `carrier`, even when negotiation is enabled. Current iOS supports only `https`, so such deployments must configure `carrier = "https"`. CFNetwork and Darwin User-Agent classification does not infer carrier support. Explicit native iOS capabilities are intersected with `{https}`; other explicit client capabilities participate as reported.
|
||||||
|
|
||||||
`http_connection_capacity_action` applies only after Telemt has accepted a private WEB TCP connection and `max_http_connections` is exhausted. `drop` preserves the legacy immediate close. `respond` emits an empty `503 Service Unavailable` with `Retry-After: 1`, `Cache-Control: no-store`, and `Connection: close`. `wait` waits for ordinary connection capacity for at most `http_overload_timeout_ms`, then enters normal HTTP handling; timeout emits the same bounded `503`. At most `max_http_overload_connections` accepted sockets may wait or respond outside ordinary connection capacity. This policy cannot observe or cause a TCP connect refusal before Telemt accepts the socket.
|
`http_connection_capacity_action` applies only after Telemt has accepted a private WEB TCP connection and `max_http_connections` is exhausted. `drop` preserves the legacy immediate close. `respond` emits an empty `503 Service Unavailable` with `Retry-After: 1`, `X-Telemt-Retry-After-Ms: 250`, `Cache-Control: no-store`, and `Connection: close`. `wait` waits for ordinary connection capacity for at most `http_overload_timeout_ms`, then enters normal HTTP handling; timeout emits the same bounded `503`. At most `max_http_overload_connections` accepted sockets may wait or respond outside ordinary connection capacity. This policy cannot observe or cause a TCP connect refusal before Telemt accepts the socket.
|
||||||
|
|
||||||
`decoy_fasttrack_mode` is restart-only. `off` preserves legacy root-request scanning and collects no fast-track decisions. `shadow` records eligible requests while preserving the full scan. `enforce` skips scans only for `HEAD` or absent/noncanonical bridge queries. A canonical bridge-shaped `GET`, including an unknown capability, always scans every profile in the selected vhost. The optimization does not bound hostile canonical probes and enforce mode must be validated for request-shape timing distinguishability behind the production TLS terminator.
|
`decoy_fasttrack_mode` is restart-only. `off` preserves legacy root-request scanning and collects no fast-track decisions. `shadow` records eligible requests while preserving the full scan. `enforce` skips scans only for `HEAD` or absent/noncanonical bridge queries. A canonical bridge-shaped `GET`, including an unknown capability, always scans every profile in the selected vhost. The optimization does not bound hostile canonical probes and enforce mode must be validated for request-shape timing distinguishability behind the production TLS terminator.
|
||||||
|
|
||||||
@@ -2704,6 +2704,38 @@ These process-wide ceilings make every WEB registry, queue, request body, capabi
|
|||||||
| `new_streams_per_minute` | `u32` | `6000` | Sustained logical-stream creation rate. |
|
| `new_streams_per_minute` | `u32` | `6000` | Sustained logical-stream creation rate. |
|
||||||
| `new_streams_burst` | `u32` | `512` | Process-wide logical-stream creation burst. |
|
| `new_streams_burst` | `u32` | `512` | Process-wide logical-stream creation burst. |
|
||||||
|
|
||||||
|
# [web.retry_jitter]
|
||||||
|
|
||||||
|
| Key | Type | Default | Description |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `enabled` | `bool` | `false` | Enable additive retry jitter. |
|
||||||
|
| `min_ms` | `u32` | `0` | Inclusive minimum addition in milliseconds. |
|
||||||
|
| `max_ms` | `u32` | `250` | Inclusive maximum addition in milliseconds; at most `30000`. |
|
||||||
|
| `distribution` | `string` | `"uniform"` | `uniform` or `triangular`. |
|
||||||
|
| `peak_ms` | `Option<u32>` | `—` | Triangular peak; omitted means the interval midpoint. |
|
||||||
|
|
||||||
|
`[web.retry_jitter]` adds an independently sampled delay to every existing bridge HTTP retry (network errors and 408/429/502/503/504). It requires no Telegram application changes. Without this section, or with `enabled = false`, the existing 250 ms Telemt hint and legacy backoff/jitter remain unchanged.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[web.retry_jitter]
|
||||||
|
enabled = true
|
||||||
|
min_ms = 0
|
||||||
|
max_ms = 250
|
||||||
|
distribution = "uniform"
|
||||||
|
# Only for distribution = "triangular":
|
||||||
|
# peak_ms = 125
|
||||||
|
```
|
||||||
|
|
||||||
|
The range describes an **addition**, not the total pause: the Telemt 250 ms hint plus this example gives 250–500 ms. Without a positive server hint, the base remains 250, 500, 1000, then 2000 ms. Enabled jitter replaces the legacy 25% jitter. A valid standard `Retry-After` is not shortened to the legacy 30-second cap in enabled mode. If the pause exceeds the remaining operation budget, the budget expires without an early retry.
|
||||||
|
|
||||||
|
Defaults are `enabled = false`, `min_ms = 0`, `max_ms = 250`, `distribution = "uniform"`, and no `peak_ms`. Require `0 <= min_ms <= max_ms <= 30000`. `uniform` samples integer milliseconds; `triangular` samples a triangular density and rounds to milliseconds. Its optional peak defaults to the midpoint and must be within the interval. An explicit peak with `uniform`, unknown keys/distributions and invalid ranges are rejected even when disabled. Equal bounds produce a constant addition.
|
||||||
|
|
||||||
|
The policy is frozen into each bridge page. Config/API reload affects newly loaded pages; existing pages retain it through recovery. Recovery JSON and HTTP compatibility headers remain unchanged. Sampling prefers `crypto.getRandomValues`, with `Math.random` as a compatibility fallback. Successful traffic is not delayed. Attempt limits, absolute budgets, cancellation and payload/sequence replay remain intact; longer pauses can exhaust a startup/recovery budget sooner in terms of completed attempts.
|
||||||
|
|
||||||
|
This reduces fixed retry timing, without guaranteeing resistance to DPI. Browser scheduling, network queues and other protocol timing remain observable. Existing timeline examples describe the default disabled mode. To evaluate enabled mode, add a sampled delay to each retry pause, not to the initial connection or every data frame.
|
||||||
|
|
||||||
|
The policy changes existing retry waits only. Stricter per-call limits still apply: ordinary `/down` polls and committed `/up` calls use one attempt; their recovery replay permits two. This option does not create new retry loops. It neither extends `web.timeouts.bridge_retry_secs` nor any startup/recovery deadline.
|
||||||
|
|
||||||
# [web.timeouts]
|
# [web.timeouts]
|
||||||
|
|
||||||
Unless a row states otherwise, timeouts are measured in seconds and must be within `1..=3600`. Configured server-side HTTP phase deadlines must be lower than `http_idle_secs`; protected phases retain their own deadlines, so the idle timer is not an aggregate request deadline. The bridge retry window is client-side and follows its own bound.
|
Unless a row states otherwise, timeouts are measured in seconds and must be within `1..=3600`. Configured server-side HTTP phase deadlines must be lower than `http_idle_secs`; protected phases retain their own deadlines, so the idle timer is not an aggregate request deadline. The bridge retry window is client-side and follows its own bound.
|
||||||
|
|||||||
@@ -2622,11 +2622,11 @@ WEB-режим переносит MTProxy-трафик Telegram Desktop внут
|
|||||||
| `timeouts` | таблица | ограниченные defaults | `✔` |
|
| `timeouts` | таблица | ограниченные defaults | `✔` |
|
||||||
| `vhosts` | массив таблиц | `[]` | `✔` |
|
| `vhosts` | массив таблиц | `[]` | `✔` |
|
||||||
|
|
||||||
Для `enabled = true` нужен как минимум один доступный по сетевой политике WEB-listener, один vhost и один профиль в каждом vhost. `https` сохраняет сериализованный HTTPS transport и требует `max_http_handlers >= 2`. В `https-lanes` stream zero и каждый logical stream получают независимые uplink sequence, downlink cursor, retry и long poll; carrier требует `max_http_handlers >= 4` и публичного HTTP/2 на TLS-терминаторе. `websocket` переносит все logical streams через одно упорядоченное RFC 6455 connection, а `websocket-lanes` выделяет отдельное connection каждому ненулевому stream и изолирует сбои lane. Оба WebSocket carrier используют `GET /api/v1/ws` после создания HTTPS-сессии и требуют от TLS-терминатора сохранять HTTP/1.1 Upgrade headers.
|
Для `enabled = true` нужен как минимум один доступный по сетевой политике WEB-listener, один vhost и один профиль в каждом vhost. `https` использует общую последовательность HTTPS uplink с согласуемым окном upload 1–4 и требует `max_http_handlers >= 2`. В `https-lanes` stream zero и каждый logical stream получают независимые uplink sequence, downlink cursor, retry и long poll; carrier требует `max_http_handlers >= 4` и публичного HTTP/2 на TLS-терминаторе. `websocket` переносит все logical streams через одно упорядоченное RFC 6455 connection, а `websocket-lanes` выделяет отдельное connection каждому ненулевому stream и изолирует сбои lane. Оба WebSocket carrier используют `GET /api/v1/ws` после создания HTTPS-сессии и требуют от TLS-терминатора сохранять HTTP/1.1 Upgrade headers.
|
||||||
|
|
||||||
Если `carriers` отсутствует или равен `false`, auto-negotiation и обучение выключены, а `carrier` задаёт единственный режим. Непустой массив `carriers` включает стартовый перебор в заданном порядке; `carrier` ровно один раз добавляется последним fallback-вариантом. Пустой массив, дубликаты и `true` запрещены. Клиент может перейти к следующему кандидату только до commit carrier; для смены carrier после commit нужна новая сессия. Native-клиент без метаданных, включая Telegram iOS, всегда использует настроенный фиксированный `carrier`, даже при включённом auto-negotiation. Текущий iOS поддерживает только `https`, поэтому такой deployment должен задавать `carrier = "https"`. Классификация User-Agent CFNetwork и Darwin не определяет поддержку carrier. Явные capabilities нативного iOS пересекаются с `{https}`; capabilities остальных явных клиентов применяются как переданы.
|
Если `carriers` отсутствует или равен `false`, auto-negotiation и обучение выключены, а `carrier` задаёт единственный режим. Непустой массив `carriers` включает стартовый перебор в заданном порядке; `carrier` ровно один раз добавляется последним fallback-вариантом. Пустой массив, дубликаты и `true` запрещены. Клиент может перейти к следующему кандидату только до commit carrier; для смены carrier после commit нужна новая сессия. Native-клиент без метаданных, включая Telegram iOS, всегда использует настроенный фиксированный `carrier`, даже при включённом auto-negotiation. Текущий iOS поддерживает только `https`, поэтому такой deployment должен задавать `carrier = "https"`. Классификация User-Agent CFNetwork и Darwin не определяет поддержку carrier. Явные capabilities нативного iOS пересекаются с `{https}`; capabilities остальных явных клиентов применяются как переданы.
|
||||||
|
|
||||||
`http_connection_capacity_action` применяется только после того, как Telemt принял приватное WEB TCP connection и исчерпал `max_http_connections`. `drop` сохраняет немедленное закрытие. `respond` отправляет пустой повторяемый `503 Service Unavailable` с `Retry-After: 1`, `Cache-Control: no-store` и `Connection: close`. `wait` ожидает обычную capacity не более `http_overload_timeout_ms`, затем переходит к нормальной HTTP-обработке; по timeout отправляется тот же ограниченный `503`. Вне обычной capacity могут ожидать или отвечать не более `max_http_overload_connections` принятых sockets.
|
`http_connection_capacity_action` применяется только после того, как Telemt принял приватное WEB TCP connection и исчерпал `max_http_connections`. `drop` сохраняет немедленное закрытие. `respond` отправляет пустой повторяемый `503 Service Unavailable` с `Retry-After: 1`, `X-Telemt-Retry-After-Ms: 250`, `Cache-Control: no-store` и `Connection: close`. `wait` ожидает обычную capacity не более `http_overload_timeout_ms`, затем переходит к нормальной HTTP-обработке; по timeout отправляется тот же ограниченный `503`. Вне обычной capacity могут ожидать или отвечать не более `max_http_overload_connections` принятых sockets.
|
||||||
|
|
||||||
`decoy_fasttrack_mode` требует перезапуска и управляет только capability work для `GET/HEAD` на настроенном base root. `off` сохраняет полный scan, `shadow` считает подходящие requests, но не пропускает scan, а `enforce` пропускает его только для `HEAD` или отсутствующего/неканонического параметра `bridge`. Канонический bridge-shaped `GET` всегда сканирует все профили выбранного vhost. Оптимизация не ограничивает враждебные канонические probes; `enforce` необходимо проверять на различимость timing за production TLS-терминатором.
|
`decoy_fasttrack_mode` требует перезапуска и управляет только capability work для `GET/HEAD` на настроенном base root. `off` сохраняет полный scan, `shadow` считает подходящие requests, но не пропускает scan, а `enforce` пропускает его только для `HEAD` или отсутствующего/неканонического параметра `bridge`. Канонический bridge-shaped `GET` всегда сканирует все профили выбранного vhost. Оптимизация не ограничивает враждебные канонические probes; `enforce` необходимо проверять на различимость timing за production TLS-терминатором.
|
||||||
|
|
||||||
@@ -2710,6 +2710,38 @@ WEB-режим переносит MTProxy-трафик Telegram Desktop внут
|
|||||||
| `new_streams_per_minute` | `u32` | `6000` | Устойчивая скорость создания logical streams. |
|
| `new_streams_per_minute` | `u32` | `6000` | Устойчивая скорость создания logical streams. |
|
||||||
| `new_streams_burst` | `u32` | `512` | Process-wide burst создания logical streams. |
|
| `new_streams_burst` | `u32` | `512` | Process-wide burst создания logical streams. |
|
||||||
|
|
||||||
|
# [web.retry_jitter]
|
||||||
|
|
||||||
|
| Ключ | Тип | По умолчанию | Описание |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `enabled` | `bool` | `false` | Включает добавочный jitter повторов. |
|
||||||
|
| `min_ms` | `u32` | `0` | Минимальная добавка в миллисекундах включительно. |
|
||||||
|
| `max_ms` | `u32` | `250` | Максимальная добавка в миллисекундах включительно; не более `30000`. |
|
||||||
|
| `distribution` | `string` | `"uniform"` | `uniform` или `triangular`. |
|
||||||
|
| `peak_ms` | `Option<u32>` | `—` | Пик треугольного распределения; при отсутствии — середина диапазона. |
|
||||||
|
|
||||||
|
`[web.retry_jitter]` добавляет независимо выбранную задержку к каждому существующему HTTP-повтору бриджа: сетевым ошибкам и ответам 408/429/502/503/504. Менять приложения Telegram не требуется. Без секции или при `enabled = false` сохраняются подсказка Telemt на 250 мс и прежний backoff/jitter.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[web.retry_jitter]
|
||||||
|
enabled = true
|
||||||
|
min_ms = 0
|
||||||
|
max_ms = 250
|
||||||
|
distribution = "uniform"
|
||||||
|
# Only for distribution = "triangular":
|
||||||
|
# peak_ms = 125
|
||||||
|
```
|
||||||
|
|
||||||
|
Диапазон задаёт **добавку**, а не полную паузу: подсказка Telemt 250 мс с этим примером даёт 250–500 мс. Без положительной серверной подсказки база остаётся 250, 500, 1000, затем 2000 мс. Включённый jitter заменяет прежний jitter до 25%. Корректный стандартный `Retry-After` во включённом режиме не сокращается прежним пределом в 30 секунд. Если пауза не помещается в оставшийся бюджет операции, бюджет истекает без раннего повтора.
|
||||||
|
|
||||||
|
Значения по умолчанию: `enabled = false`, `min_ms = 0`, `max_ms = 250`, `distribution = "uniform"`, `peak_ms` отсутствует. Требуется `0 <= min_ms <= max_ms <= 30000`. `uniform` выбирает целые миллисекунды равномерно; `triangular` использует треугольную плотность с округлением до миллисекунд. Необязательный пик по умолчанию находится посередине и должен входить в диапазон. Явный пик для `uniform`, неизвестные ключи/распределения и неверные границы отклоняются даже при выключенной опции. Одинаковые границы дают постоянную добавку.
|
||||||
|
|
||||||
|
Политика фиксируется в каждой странице бриджа. Reload через конфиг/API влияет на новые страницы; активные сохраняют настройки при recovery. Recovery JSON и HTTP-заголовки совместимости не меняются. Используется `crypto.getRandomValues`, при недоступности — `Math.random` для совместимости. Успешный трафик не задерживается. Лимиты попыток, общий бюджет, отмена и повтор неизменных payload/sequence сохраняются; более длинные паузы могут уменьшить число попыток, помещающихся в startup/recovery-бюджет.
|
||||||
|
|
||||||
|
Это размывает фиксированные интервалы повторов, но не гарантирует защиту от DPI. Планирование браузера, сетевые очереди и другие временные характеристики протокола остаются наблюдаемыми. Существующие примеры временной шкалы описывают выключенную опцию. Для включённого режима добавляйте выбранную задержку к каждой паузе повтора, а не к первому соединению или каждому кадру данных.
|
||||||
|
|
||||||
|
Политика меняет только уже предусмотренные паузы перед повтором. Более строгие ограничения отдельных вызовов сохраняются: обычный poll `/down` и вызов `/up` после commit выполняют одну попытку; их replay при восстановлении допускает две. Опция не создаёт новых циклов повторов. Она не продлевает `web.timeouts.bridge_retry_secs` и сроки запуска или восстановления.
|
||||||
|
|
||||||
# [web.timeouts]
|
# [web.timeouts]
|
||||||
|
|
||||||
Если в строке не указано иное, таймауты задаются в секундах и должны входить в диапазон `1..=3600`. Настроенные серверные deadlines отдельных HTTP-фаз должны быть меньше `http_idle_secs`; защищённые фазы сохраняют собственные deadlines, поэтому idle-таймер не является общим deadline запроса. Client-side окно повторов bridge имеет отдельные границы.
|
Если в строке не указано иное, таймауты задаются в секундах и должны входить в диапазон `1..=3600`. Настроенные серверные deadlines отдельных HTTP-фаз должны быть меньше `http_idle_secs`; защищённые фазы сохраняют собственные deadlines, поэтому idle-таймер не является общим deadline запроса. Client-side окно повторов bridge имеет отдельные границы.
|
||||||
|
|||||||
+39
-12
@@ -94,7 +94,7 @@ flowchart LR
|
|||||||
W5 --> W6["TL_pong empfangen<br/>Angezeigte Messung beendet"]
|
W5 --> W6["TL_pong empfangen<br/>Angezeigte Messung beendet"]
|
||||||
X["Nur wenn eine weitere Verbindung nötig ist<br/>TCP + TLS, eventuell WebSocket-Upgrade<br/>Kein Handshake pro Ping bei Wiederverwendung"] -.-> W3
|
X["Nur wenn eine weitere Verbindung nötig ist<br/>TCP + TLS, eventuell WebSocket-Upgrade<br/>Kein Handshake pro Ping bei Wiederverwendung"] -.-> W3
|
||||||
X -.-> W5
|
X -.-> W5
|
||||||
R["Nur bei Fehlern oder Überlastung<br/>Retries und Backoff<br/>Retry-After: 1 kann etwa eine Sekunde hinzufügen"] -.-> W3
|
R["Nur bei Fehlern oder Überlastung<br/>Retries und Backoff<br/>Telemt-Basis 250 ms<br/>Plus optionaler Jitter"] -.-> W3
|
||||||
R -.-> W5
|
R -.-> W5
|
||||||
end
|
end
|
||||||
classDef preparation fill:#eeeeee,stroke:#666666,color:#111111
|
classDef preparation fill:#eeeeee,stroke:#666666,color:#111111
|
||||||
@@ -113,6 +113,30 @@ Bei Wiederverwendung des Carriers entfällt der bedingte TCP/TLS/Upgrade-Aufwand
|
|||||||
|
|
||||||
Die sichtbare Differenz kann somit verbleibenden WEB-Streamaufbau, zusätzliche Verbindungen, Transportverarbeitung und Scheduling sowie belegte Retries enthalten. Sie ist weder ein fester TLS-Zuschlag noch die arithmetische Summe aller Kästen. Der erste echte TLS-Handshake steht bewusst vor dem Android-Timer: Er beeinflusst die Gesamtdauer der Prüfung, normalerweise aber nicht den angezeigten Messwert. Da die Prüfung einen separaten Transport verwendet, garantiert eine aktive App-Verbindung auch keine warme Prüfung in der Proxyliste.
|
Die sichtbare Differenz kann somit verbleibenden WEB-Streamaufbau, zusätzliche Verbindungen, Transportverarbeitung und Scheduling sowie belegte Retries enthalten. Sie ist weder ein fester TLS-Zuschlag noch die arithmetische Summe aller Kästen. Der erste echte TLS-Handshake steht bewusst vor dem Android-Timer: Er beeinflusst die Gesamtdauer der Prüfung, normalerweise aber nicht den angezeigten Messwert. Da die Prüfung einen separaten Transport verwendet, garantiert eine aktive App-Verbindung auch keine warme Prüfung in der Proxyliste.
|
||||||
|
|
||||||
|
### Konfigurierbarer Jitter für HTTP-Wiederholungen
|
||||||
|
|
||||||
|
`[web.retry_jitter]` ergänzt jeden bestehenden HTTP-Retry der Bridge um eine unabhängig gewählte Verzögerung: Netzwerkfehler und Antworten mit 408/429/502/503/504. Telegram-Anwendungen müssen nicht geändert werden. Ohne diesen Abschnitt oder mit `enabled = false` bleiben der 250-ms-Hinweis von Telemt und das bisherige Backoff/Jitter-Verhalten erhalten.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[web.retry_jitter]
|
||||||
|
enabled = true
|
||||||
|
min_ms = 0
|
||||||
|
max_ms = 250
|
||||||
|
distribution = "uniform"
|
||||||
|
# Only for distribution = "triangular":
|
||||||
|
# peak_ms = 125
|
||||||
|
```
|
||||||
|
|
||||||
|
Der Bereich beschreibt einen **Zuschlag**, nicht die gesamte Pause: Zusammen mit dem Telemt-Hinweis von 250 ms ergibt dieses Beispiel 250–500 ms. Ohne positiven Serverhinweis bleibt die Basis bei 250, 500, 1000, dann 2000 ms. Aktivierter Jitter ersetzt den bisherigen Jitter von bis zu 25%. Ein gültiger standardmäßiger `Retry-After` wird im aktivierten Modus nicht auf die bisherige Grenze von 30 Sekunden verkürzt. Übersteigt die Pause das verbleibende Operationsbudget, läuft das Budget ohne vorzeitigen Retry ab.
|
||||||
|
|
||||||
|
Standardwerte: `enabled = false`, `min_ms = 0`, `max_ms = 250`, `distribution = "uniform"`, ohne `peak_ms`. Es gilt `0 <= min_ms <= max_ms <= 30000`. `uniform` verteilt ganze Millisekunden gleichmäßig; `triangular` verwendet eine Dreiecksverteilung mit Rundung auf Millisekunden. Der optionale Gipfel liegt standardmäßig in der Mitte und muss innerhalb des Intervalls liegen. Ein expliziter Gipfel bei `uniform`, unbekannte Schlüssel/Verteilungen und ungültige Grenzen werden auch im deaktivierten Zustand abgelehnt. Gleiche Grenzen ergeben einen konstanten Zuschlag.
|
||||||
|
|
||||||
|
Die Richtlinie wird pro Bridge-Seite festgeschrieben. Konfigurations-/API-Reload wirkt auf neu geladene Seiten; bestehende Seiten behalten ihre Einstellungen bei Recovery. Recovery-JSON und HTTP-Kompatibilitätsheader bleiben unverändert. Die Auswahl bevorzugt `crypto.getRandomValues`, mit `Math.random` als Kompatibilitätsfallback. Erfolgreicher Datenverkehr wird nicht verzögert. Versuchslimits, absolute Budgets, Abbruch und unveränderte Payload-/Sequence-Wiederholung bleiben erhalten; längere Pausen können die Anzahl der Versuche innerhalb eines Startup-/Recovery-Budgets reduzieren.
|
||||||
|
|
||||||
|
Dies streut feste Retry-Intervalle, garantiert aber keinen Schutz vor DPI. Browser-Scheduling, Netzwerkwarteschlangen und andere Protokollzeiten bleiben beobachtbar. Bestehende Zeitleisten zeigen den deaktivierten Standardmodus. Bei aktiviertem Modus wird zu jeder Retry-Pause eine gezogene Verzögerung addiert, nicht zum ersten Verbindungsaufbau oder zu jedem Datenframe.
|
||||||
|
|
||||||
|
Die Richtlinie ändert nur bereits vorhandene Retry-Pausen. Strengere Limits einzelner Aufrufe bleiben erhalten: Reguläre `/down`-Polls und `/up`-Aufrufe nach dem Commit führen einen Versuch aus; ihr Recovery-Replay erlaubt zwei. Die Option erzeugt keine neuen Retry-Schleifen. Sie verlängert weder `web.timeouts.bridge_retry_secs` noch Start- oder Recovery-Deadlines.
|
||||||
|
|
||||||
## Beispielhafte Zeitleiste mit ungefähren Dauern
|
## Beispielhafte Zeitleiste mit ungefähren Dauern
|
||||||
|
|
||||||
**Ein Erklärungsmodell, kein Benchmark und kein erwarteter Latenzbereich.** Die Zahlen sollen das Zusammenspiel der Phasen zeigen. Sie rekonstruieren nicht die beobachteten 1000–1500 ms. Annahmen: DNS ist bereits zwischengespeichert, der RTT zwischen Client und Frontend beträgt 40 ms, die TCP-Verbindung ist neu, bei Bedarf erfolgt ein vollständiger TLS-1.3-Handshake, ein DC-Autorisierungsschlüssel ist vorhanden, und es gibt weder Paketverlust noch ein Zurücksetzen des nativen Anfragezeitstempels. Als Basis dient Classic/DD. Bei EE kommt der eigene FakeTLS-Aufbau vor dem nativen Timer hinzu.
|
**Ein Erklärungsmodell, kein Benchmark und kein erwarteter Latenzbereich.** Die Zahlen sollen das Zusammenspiel der Phasen zeigen. Sie rekonstruieren nicht die beobachteten 1000–1500 ms. Annahmen: DNS ist bereits zwischengespeichert, der RTT zwischen Client und Frontend beträgt 40 ms, die TCP-Verbindung ist neu, bei Bedarf erfolgt ein vollständiger TLS-1.3-Handshake, ein DC-Autorisierungsschlüssel ist vorhanden, und es gibt weder Paketverlust noch ein Zurücksetzen des nativen Anfragezeitstempels. Als Basis dient Classic/DD. Bei EE kommt der eigene FakeTLS-Aufbau vor dem nativen Timer hinzu.
|
||||||
@@ -126,10 +150,10 @@ Die Darstellung beginnt beim **letzten Anfragezeitstempel** der jeweiligen Prüf
|
|||||||
gantt
|
gantt
|
||||||
dateFormat x
|
dateFormat x
|
||||||
axisFormat %S.%L
|
axisFormat %S.%L
|
||||||
tickInterval 200millisecond
|
tickInterval 100millisecond
|
||||||
todayMarker off
|
todayMarker off
|
||||||
title Angezeigter Ping - Beispielmodell
|
title Angezeigter Ping - Jitter aus
|
||||||
accTitle: Angezeigter Ping - Beispielmodell
|
accTitle: Angezeigter Ping - Jitter aus
|
||||||
accDescr: Sekunden seit Anfragezeitstempel, Beschriftungen in Millisekunden
|
accDescr: Sekunden seit Anfragezeitstempel, Beschriftungen in Millisekunden
|
||||||
section Classic/DD - 100 ms
|
section Classic/DD - 100 ms
|
||||||
R 100 ms :n_r, 0, 100ms
|
R 100 ms :n_r, 0, 100ms
|
||||||
@@ -137,28 +161,31 @@ gantt
|
|||||||
U 40 ms :w_u, 0, 40ms
|
U 40 ms :w_u, 0, 40ms
|
||||||
R 100 ms :w_r, after w_u, 100ms
|
R 100 ms :w_r, after w_u, 100ms
|
||||||
D 60 ms :w_d, after w_r, 60ms
|
D 60 ms :w_d, after w_r, 60ms
|
||||||
section WEB mit Retry - 1240 ms
|
section WEB mit Retry - 490 ms
|
||||||
F 40 ms :crit, f_u, 0, 40ms
|
F 40 ms :crit, f_u, 0, 40ms
|
||||||
Warten 1000 ms :crit, retry_wait, after f_u, 1000ms
|
Warten 250 ms :crit, retry_wait, after f_u, 250ms
|
||||||
U 40 ms :retry_u, after retry_wait, 40ms
|
U 40 ms :retry_u, after retry_wait, 40ms
|
||||||
R 100 ms :retry_r, after retry_u, 100ms
|
R 100 ms :retry_r, after retry_u, 100ms
|
||||||
D 60 ms :retry_d, after retry_r, 60ms
|
D 60 ms :retry_d, after retry_r, 60ms
|
||||||
```
|
```
|
||||||
|
|
||||||
Dauer der einzelnen Phasen: `R` = 100 ms grundlegende MTProxy-Relay-/Netzwerk-/DC-Arbeit für Anfrage und Antwort. `U` = 40 ms zusätzliche WEB-Uplink-/OPEN-/Client-Arbeit. `D` = 60 ms zusätzliche WEB-Downlink-/Zustellarbeit. `F` = 40 ms für einen fehlgeschlagenen Upload-Versuch. `Warten` = 1000 ms Wartezeit gemäß `Retry-After: 1`. `U` und `D` sind beispielhafte Zusatzkosten gegenüber `R`, keine erneute Anrechnung des gesamten Netzwerk-RTT. Die ACK/Commit-Freigabe wird nur berücksichtigt, soweit sie die Zustellung tatsächlich verzögert.
|
Dauer der einzelnen Phasen: `R` = 100 ms grundlegende MTProxy-Relay-/Netzwerk-/DC-Arbeit für Anfrage und Antwort. `U` = 40 ms zusätzliche WEB-Uplink-/OPEN-/Client-Arbeit. `D` = 60 ms zusätzliche WEB-Downlink-/Zustellarbeit. `F` = 40 ms für einen fehlgeschlagenen Upload-Versuch. `Warten` = 250 ms Wartezeit gemäß `X-Telemt-Retry-After-Ms: 250`. `U` und `D` sind beispielhafte Zusatzkosten gegenüber `R`, keine erneute Anrechnung des gesamten Netzwerk-RTT. Die ACK/Commit-Freigabe wird nur berücksichtigt, soweit sie die Zustellung tatsächlich verzögert.
|
||||||
|
|
||||||
| Szenario | Vor dem Ping-Timer | Angezeigter Ping | Gesamtdauer der Prüfung im Modell |
|
| Szenario | Vor dem Ping-Timer | Angezeigter Ping | Gesamtdauer der Prüfung im Modell |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| Classic/DD | 40 ms | 100 ms | 140 ms |
|
| Classic/DD | 40 ms | 100 ms | 140 ms |
|
||||||
| WEB ohne Fehler | 750 ms | 40 + 100 + 60 = 200 ms | 950 ms |
|
| WEB ohne Fehler | 750 ms | 40 + 100 + 60 = 200 ms | 950 ms |
|
||||||
| WEB mit einem fehlgeschlagenen Upload und einer Retry-Pause | 750 ms | 40 + 1000 + 40 + 100 + 60 = 1240 ms | 1990 ms |
|
| WEB mit einem fehlgeschlagenen Upload und einer Retry-Pause | 750 ms | 40 + 250 + 40 + 100 + 60 = 490 ms | 1240 ms |
|
||||||
|
| WEB, gleicher Retry mit uniformem Jitter 0–250 ms | 750 ms | 490–740 ms | 1240–1490 ms |
|
||||||
|
|
||||||
Eine weitere TCP- und TLS-1.3-Verbindung **innerhalb** der Messung könnte hier bei vollständig sequenziellem Ablauf ungefähr 80 ms hinzufügen: Aus 200 ms würden 280 ms. Bei Verbindungswiederverwendung entfällt dieser zusätzliche Handshake-Aufwand. Ein anfänglicher vollständiger TLS-1.2- statt TLS-1.3-Handshake verlängert unter diesen Annahmen die Vorbereitung um etwa 40 ms, nicht den angezeigten Ping. Die Beispiele lassen TLS-Verarbeitung, Sitzungswiederaufnahme und Paketverlust unberücksichtigt.
|
Eine weitere TCP- und TLS-1.3-Verbindung **innerhalb** der Messung könnte hier bei vollständig sequenziellem Ablauf ungefähr 80 ms hinzufügen: Aus 200 ms würden 280 ms. Bei Verbindungswiederverwendung entfällt dieser zusätzliche Handshake-Aufwand. Ein anfänglicher vollständiger TLS-1.2- statt TLS-1.3-Handshake verlängert unter diesen Annahmen die Vorbereitung um etwa 40 ms, nicht den angezeigten Ping. Die Beispiele lassen TLS-Verarbeitung, Sitzungswiederaufnahme und Paketverlust unberücksichtigt.
|
||||||
|
|
||||||
Die Zeile mit 1240 ms zeigt einen möglichen Mechanismus für einen Sekundenwert: einen durch HTTP-Traces belegten Retry. Sie beweist nicht, dass Retries die ursprüngliche Beobachtung verursacht haben. Ohne einen solchen Retry müssen andere tatsächlich gemessene Verzögerungen lokalisiert werden, etwa Warteschlangen, Frontend-Pufferung, Verbindungsaufbau oder Upstream-Arbeit. Timeouts dürfen nicht als Wartepausen eingesetzt und überlappende Phasen nicht ungeprüft in dieses sequenzielle Modell übertragen werden.
|
Die Zeile mit 490 ms und das Diagramm zeigen einen Retry bei deaktiviertem Jitter. Die zusätzliche Tabellenzeile wendet `enabled = true`, `min_ms = 0`, `max_ms = 250`, `distribution = "uniform"` auf denselben Retry an; ihr Bereich stammt aus dem Modell, nicht aus Messungen. Eine frühere JavaScript-Bridge ohne Millisekundenerweiterung oder ein Vermittler, der diesen Hinweis bei deaktiviertem Jitter entfernt, behält die standardmäßige Sekundenpause bei: Der angezeigte Ping beträgt im selben Modell dann 1240 ms. Keines der Szenarien bestimmt die Ursache der ursprünglichen Beobachtung. Ohne belegte Retries andere Verzögerungen wie Warteschlangen, Frontend-Pufferung, Verbindungsaufbau oder Upstream-Arbeit untersuchen. Timeouts dürfen nicht als Wartepausen eingesetzt und überlappende Phasen nicht ungeprüft in dieses sequenzielle Modell übertragen werden.
|
||||||
|
|
||||||
## HTTP, WebSocket und weitere Verzögerungen
|
## HTTP, WebSocket und weitere Verzögerungen
|
||||||
|
|
||||||
|
Überlastungsantworten von Telemt enthalten `Retry-After: 1` und `X-Telemt-Retry-After-Ms: 250`. Nur Status `503` mit diesem exakten Header-Paar legt in der generierten Bridge eine **Basispause von 250 ms** fest. Bei `web.retry_jitter.enabled = false` beträgt die Pause 250 ms; bei aktiviertem Jitter kommt der konfigurierte zufällige Zuschlag hinzu. Andere Antworten verwenden die unten beschriebene Standardbehandlung von `Retry-After` oder den Backoff ohne Serverhinweis. Frühere JavaScript-Bridge-Seiten ohne Unterstützung des Millisekundenhinweises verwenden bis zum Laden einer neuen Seite die Sekundenpause; ein Update der Telegram-App ist dafür nicht erforderlich. Versuchslimits, absolute Budgets, Abbruchverhalten und Zulassungsgrenzen bleiben unverändert.
|
||||||
|
|
||||||
| Faktor | Auswirkung und Beleg |
|
| Faktor | Auswirkung und Beleg |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| HTTP-Uplink | Die generierte Bridge bietet `X-Telemt-Up-Window: 4` an; der Server akzeptiert 1–4, ohne Aushandlung gilt 1. Fenster 1 wartet vor dem nächsten Upload auf ein ACK; Fenster 4 erlaubt begrenzte Parallelität. Nicht jeder HTTP-Pfad arbeitet nach Stop-and-Wait. Siehe [Aushandlung][runtime] und [Sitzungshandler][session]. |
|
| HTTP-Uplink | Die generierte Bridge bietet `X-Telemt-Up-Window: 4` an; der Server akzeptiert 1–4, ohne Aushandlung gilt 1. Fenster 1 wartet vor dem nächsten Upload auf ein ACK; Fenster 4 erlaubt begrenzte Parallelität. Nicht jeder HTTP-Pfad arbeitet nach Stop-and-Wait. Siehe [Aushandlung][runtime] und [Sitzungshandler][session]. |
|
||||||
@@ -168,7 +195,7 @@ Die Zeile mit 1240 ms zeigt einen möglichen Mechanismus für einen Sekundenwert
|
|||||||
| Frontend-Pufferung | Pufferung von Anfragen/Antworten oder fehlende Streaming-/Upgrade-Unterstützung kann kleine Nachrichten verzögern. Mit dem bestehenden NGINX-Beispiel vergleichen; Routing, Authentifizierung und Limits beibehalten. |
|
| Frontend-Pufferung | Pufferung von Anfragen/Antworten oder fehlende Streaming-/Upgrade-Unterstützung kann kleine Nachrichten verzögern. Mit dem bestehenden NGINX-Beispiel vergleichen; Routing, Authentifizierung und Limits beibehalten. |
|
||||||
| Client-Scheduling | Java-Accept/Read-Threads, UI-Dispatch, WebView/JavaScript und die Rückgabe an nativen Code erzeugen Warteschlangen. CPU-Last, mobiles Energiesparen und Netzwechsel können dies verstärken. |
|
| Client-Scheduling | Java-Accept/Read-Threads, UI-Dispatch, WebView/JavaScript und die Rückgabe an nativen Code erzeugen Warteschlangen. CPU-Last, mobiles Energiesparen und Netzwechsel können dies verstärken. |
|
||||||
| Weiterleitung und Netzwerk | Verbleibende Stream-Zulassung, innerer MTProxy-Handshake, Direct-Verbindungsaufbau oder ME-Registrierung, Telegram-Antwort, Paketverluste/Wiederholungen und Warteschlangen können beitragen. Eine bereite WEB-Sitzung belegt keinen bereiten Upstream. |
|
| Weiterleitung und Netzwerk | Verbleibende Stream-Zulassung, innerer MTProxy-Handshake, Direct-Verbindungsaufbau oder ME-Registrierung, Telegram-Antwort, Paketverluste/Wiederholungen und Warteschlangen können beitragen. Eine bereite WEB-Sitzung belegt keinen bereiten Upstream. |
|
||||||
| Fehler und Wiederholungen | Telemt kann `503` mit `Retry-After: 1` zurückgeben. Die Bridge berücksichtigt dies; sonstiges Retry-Backoff beginnt bei 250 ms und verdoppelt sich bis 2000 ms zuzüglich bis zu ungefähr 25% Jitter, innerhalb des Retry-Budgets. Wiederholbare HTTP-Statuscodes umfassen 408/429/502/503/504. Ein Trace muss solche Ereignisse zeigen, bevor eine Sekundenstufe darauf zurückgeführt wird. Siehe [Antworten][response] und [Retry-Logik][request]. |
|
| Fehler und Wiederholungen | Wiederholbare Statuscodes sind 408/429/502/503/504. Bei deaktiviertem Jitter ergibt der exakte Telemt-Hinweis eine Pause von 250 ms; ohne positiven Serverhinweis beginnt der Backoff bei 250 ms und verdoppelt sich bis zu einer Basis von 2000 ms zuzüglich des bisherigen Jitters unter 25%. Bei aktiviertem Jitter ist die Pause der positive Serverhinweis oder diese Basis **plus** der konfigurierte Zufallswert, der den bisherigen Jitter ersetzt. Budgets und aufrufspezifische Versuchslimits gelten weiterhin. Die Richtlinie der geladenen Bridge und tatsächliche Retry-Zeitpunkte festhalten. Siehe [Antworten][response] und [Retry-Logik][request]. |
|
||||||
|
|
||||||
Fristen sind keine obligatorischen Pausen. Die Standardwerte von 10 s für Bridge-Anfragen, 90 s Retry-Budget, 30 s bis zum ersten Stream-Byte und 10 s für den Stream-Handshake dürfen nicht zum normalen Ping addiert werden. `carrier_probe_coalesce_ms=0` deaktiviert diese optionale Verzögerung zur Zusammenfassung von Probes. Carrier-Fallback-Fristen betreffen fehlgeschlagene Versuche, nicht jeden erfolgreichen Austausch. Siehe [Standardwerte](../../src/config/types/web/defaults.rs).
|
Fristen sind keine obligatorischen Pausen. Die Standardwerte von 10 s für Bridge-Anfragen, 90 s Retry-Budget, 30 s bis zum ersten Stream-Byte und 10 s für den Stream-Handshake dürfen nicht zum normalen Ping addiert werden. `carrier_probe_coalesce_ms=0` deaktiviert diese optionale Verzögerung zur Zusammenfassung von Probes. Carrier-Fallback-Fristen betreffen fehlgeschlagene Versuche, nicht jeden erfolgreichen Austausch. Siehe [Standardwerte](../../src/config/types/web/defaults.rs).
|
||||||
|
|
||||||
@@ -176,7 +203,7 @@ Vereinfacht umfasst eine WEB-Messung **verbleibenden Aufbau + Transport-/Netzwer
|
|||||||
|
|
||||||
## Diagnose unter Beibehaltung der Schutzmechanismen
|
## Diagnose unter Beibehaltung der Schutzmechanismen
|
||||||
|
|
||||||
1. Client/Build, Android-WebView-Version, Carrier, öffentlichen Endpunkt, IP-Familie, Netzwerk, Direct/ME-Route, DC und Last erfassen. Unter gleichen Bedingungen vergleichen. Den zwei Minuten lang gespeicherten Android-Wert beachten: Wiederholtes Ablesen liefert keine neuen Messungen.
|
1. Client/Build, Android-WebView-Version, die `web.retry_jitter`-Richtlinie der geladenen Bridge, Carrier, öffentlichen Endpunkt, IP-Familie, Netzwerk, Direct/ME-Route, DC und Last erfassen. Unter gleichen Bedingungen vergleichen. Den zwei Minuten lang gespeicherten Android-Wert beachten: Wiederholtes Ablesen liefert keine neuen Messungen.
|
||||||
2. Drei Experimente unterscheiden: neue Prüfung in der Proxyliste; neuer logischer Stream auf einem bereiten Carrier; Anwendungs-RPC in einer bestehenden MTProto-Sitzung. Die letzten beiden benötigen geeignete Client-Instrumentierung und werden nicht automatisch von der Proxyliste bereitgestellt. Einzelwerte und Verteilungen erfassen, statt einen kalten mit einem warmen Einzelwert zu vergleichen.
|
2. Drei Experimente unterscheiden: neue Prüfung in der Proxyliste; neuer logischer Stream auf einem bereiten Carrier; Anwendungs-RPC in einer bestehenden MTProto-Sitzung. Die letzten beiden benötigen geeignete Client-Instrumentierung und werden nicht automatisch von der Proxyliste bereitgestellt. Einzelwerte und Verteilungen erfassen, statt einen kalten mit einem warmen Einzelwert zu vergleichen.
|
||||||
3. Das authentifizierte `GET /web-status` und vorhandene `[web.debug]`-Einstellungen mit `capture_timings=true`, `capture_frames=true`, `body_capture="metadata"` verwenden. Begrenzte Erfassung gemäß [WEB-Diagnoseanleitung](WEB_PROXY.de.md) aktivieren und danach den vorherigen Zustand wiederherstellen. Payloads, Capabilities und Secrets sind hierfür unnötig.
|
3. Das authentifizierte `GET /web-status` und vorhandene `[web.debug]`-Einstellungen mit `capture_timings=true`, `capture_frames=true`, `body_capture="metadata"` verwenden. Begrenzte Erfassung gemäß [WEB-Diagnoseanleitung](WEB_PROXY.de.md) aktivieren und danach den vorherigen Zustand wiederherstellen. Payloads, Capabilities und Secrets sind hierfür unnötig.
|
||||||
4. Sitzungserstellung, Carrier-Auswahl/Commit/Fehler, `stream_admitted`, `stream_first_byte`, `handshake_succeeded`, OPEN/DATA, HTTP-Statuscodes und Retries korrelieren. `relay_started` liegt vor der Upstream-Arbeit und ist kein DC-Bereitschaftszeitpunkt. `GET /v1/runtime/web/status` und `GET /v1/runtime/web/sessions` liefern Kapazitäts- und Warteschlangenkontext, keinen Ende-zu-Ende-RTT.
|
4. Sitzungserstellung, Carrier-Auswahl/Commit/Fehler, `stream_admitted`, `stream_first_byte`, `handshake_succeeded`, OPEN/DATA, HTTP-Statuscodes und Retries korrelieren. `relay_started` liegt vor der Upstream-Arbeit und ist kein DC-Bereitschaftszeitpunkt. `GET /v1/runtime/web/status` und `GET /v1/runtime/web/sessions` liefern Kapazitäts- und Warteschlangenkontext, keinen Ende-zu-Ende-RTT.
|
||||||
@@ -184,7 +211,7 @@ Vereinfacht umfasst eine WEB-Messung **verbleibenden Aufbau + Transport-/Netzwer
|
|||||||
6. Verbindungs-/TLS-/Anfragezeiten des Frontends und Client-Zeitstempel ergänzen, um Verzögerungen außerhalb von Telemt zu lokalisieren. Wiederverwendung von Verbindungen, ausgehandelte HTTP-Version, Pufferung und Upgrade prüfen. Sideband-Ereignisse zum Bridge-Start/HELLO ergeben keine vollständige Client-Zeitleiste. Für Vergleiche zwischen Hosts Uhren synchronisieren oder lokale Dauern verwenden.
|
6. Verbindungs-/TLS-/Anfragezeiten des Frontends und Client-Zeitstempel ergänzen, um Verzögerungen außerhalb von Telemt zu lokalisieren. Wiederverwendung von Verbindungen, ausgehandelte HTTP-Version, Pufferung und Upgrade prüfen. Sideband-Ereignisse zum Bridge-Start/HELLO ergeben keine vollständige Client-Zeitleiste. Für Vergleiche zwischen Hosts Uhren synchronisieren oder lokale Dauern verwenden.
|
||||||
7. Bei ME den vorhandenen Trace `ME RTT sample` (`rtt_ms`, `ema_ms`, `base_ms`, `degraded`) vergleichen. Der Zeitstempel liegt vor Writer-Warteschlange/Flush; die EMA besteht aus 80% vorherigem Wert und 20% neuer Messung. Keepalive-Scheduling vor diesem Zeitstempel ist ausgeschlossen. Ein niedriger ME-Wert bei hohem Android-Ping weist auf Arbeit außerhalb dieses ME-Messbereichs hin, benennt aber keine konkrete Ursache. Siehe [Writer][writer] und [Reader][reader].
|
7. Bei ME den vorhandenen Trace `ME RTT sample` (`rtt_ms`, `ema_ms`, `base_ms`, `degraded`) vergleichen. Der Zeitstempel liegt vor Writer-Warteschlange/Flush; die EMA besteht aus 80% vorherigem Wert und 20% neuer Messung. Keepalive-Scheduling vor diesem Zeitstempel ist ausgeschlossen. Ein niedriger ME-Wert bei hohem Android-Ping weist auf Arbeit außerhalb dieses ME-Messbereichs hin, benennt aber keine konkrete Ursache. Siehe [Writer][writer] und [Reader][reader].
|
||||||
|
|
||||||
Interpretationsbeispiele: Schnelle Telemt-Verarbeitung bei später Client-Zustellung lenkt die Untersuchung auf Frontend, Netzwerk und Client-Warteschlangen; `503` mit `Retry-After: 1` belegt eine Retry-Pause; lange Upstream-Arbeit erfordert eine Direct/ME-Untersuchung. Keines dieser Muster beweist allein, dass TLS-Kryptografie 1000–1500 ms verursacht. Kompatibilität, Zertifikatsprüfung, Zulassungslimits und Backpressure während der Untersuchung beibehalten.
|
Interpretationsbeispiele: Schnelle Telemt-Verarbeitung bei später Client-Zustellung lenkt die Untersuchung auf Frontend, Netzwerk und Client-Warteschlangen; `503` und die Retry-Header bestimmen die Basispause, während die geladene Jitter-Richtlinie und Client-Zeitstempel die tatsächliche Pause belegen; lange Upstream-Arbeit erfordert eine Direct/ME-Untersuchung. Keines dieser Muster beweist allein, dass TLS-Kryptografie 1000–1500 ms verursacht. Kompatibilität, Zertifikatsprüfung, Zulassungslimits und Backpressure während der Untersuchung beibehalten.
|
||||||
|
|
||||||
## Grenzen der Belege
|
## Grenzen der Belege
|
||||||
|
|
||||||
|
|||||||
+39
-12
@@ -94,7 +94,7 @@ flowchart LR
|
|||||||
W5 --> W6["TL_pong received<br/>Displayed sample ends"]
|
W5 --> W6["TL_pong received<br/>Displayed sample ends"]
|
||||||
X["Only if another connection is needed<br/>TCP + TLS, possible WebSocket Upgrade<br/>No handshake per ping on a reused connection"] -.-> W3
|
X["Only if another connection is needed<br/>TCP + TLS, possible WebSocket Upgrade<br/>No handshake per ping on a reused connection"] -.-> W3
|
||||||
X -.-> W5
|
X -.-> W5
|
||||||
R["Only on errors or overload<br/>Retries and backoff<br/>Retry-After: 1 can add about one second"] -.-> W3
|
R["Only on errors or overload<br/>Retries and backoff<br/>Telemt base 250 ms<br/>Plus optional jitter"] -.-> W3
|
||||||
R -.-> W5
|
R -.-> W5
|
||||||
end
|
end
|
||||||
classDef preparation fill:#eeeeee,stroke:#666666,color:#111111
|
classDef preparation fill:#eeeeee,stroke:#666666,color:#111111
|
||||||
@@ -113,6 +113,30 @@ On a reused carrier, the conditional TCP/TLS/Upgrade cost disappears, while fram
|
|||||||
|
|
||||||
Thus the visible difference can include remaining WEB stream setup, additional connection setup, carrier handling and scheduling, plus retries when observed. It is not a fixed TLS surcharge or an arithmetic sum of all boxes. The initial real TLS handshake is shown outside the Android timer deliberately: it affects total time to check, but normally not the displayed sample. The separate checker transport also means that an active app connection does not guarantee a warm proxy-list check.
|
Thus the visible difference can include remaining WEB stream setup, additional connection setup, carrier handling and scheduling, plus retries when observed. It is not a fixed TLS surcharge or an arithmetic sum of all boxes. The initial real TLS handshake is shown outside the Android timer deliberately: it affects total time to check, but normally not the displayed sample. The separate checker transport also means that an active app connection does not guarantee a warm proxy-list check.
|
||||||
|
|
||||||
|
### Configurable HTTP retry jitter
|
||||||
|
|
||||||
|
`[web.retry_jitter]` adds an independently sampled delay to every existing bridge HTTP retry (network errors and 408/429/502/503/504). It requires no Telegram application changes. Without this section, or with `enabled = false`, the existing 250 ms Telemt hint and legacy backoff/jitter remain unchanged.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[web.retry_jitter]
|
||||||
|
enabled = true
|
||||||
|
min_ms = 0
|
||||||
|
max_ms = 250
|
||||||
|
distribution = "uniform"
|
||||||
|
# Only for distribution = "triangular":
|
||||||
|
# peak_ms = 125
|
||||||
|
```
|
||||||
|
|
||||||
|
The range describes an **addition**, not the total pause: the Telemt 250 ms hint plus this example gives 250–500 ms. Without a positive server hint, the base remains 250, 500, 1000, then 2000 ms. Enabled jitter replaces the legacy 25% jitter. A valid standard `Retry-After` is not shortened to the legacy 30-second cap in enabled mode. If the pause exceeds the remaining operation budget, the budget expires without an early retry.
|
||||||
|
|
||||||
|
Defaults are `enabled = false`, `min_ms = 0`, `max_ms = 250`, `distribution = "uniform"`, and no `peak_ms`. Require `0 <= min_ms <= max_ms <= 30000`. `uniform` samples integer milliseconds; `triangular` samples a triangular density and rounds to milliseconds. Its optional peak defaults to the midpoint and must be within the interval. An explicit peak with `uniform`, unknown keys/distributions and invalid ranges are rejected even when disabled. Equal bounds produce a constant addition.
|
||||||
|
|
||||||
|
The policy is frozen into each bridge page. Config/API reload affects newly loaded pages; existing pages retain it through recovery. Recovery JSON and HTTP compatibility headers remain unchanged. Sampling prefers `crypto.getRandomValues`, with `Math.random` as a compatibility fallback. Successful traffic is not delayed. Attempt limits, absolute budgets, cancellation and payload/sequence replay remain intact; longer pauses can exhaust a startup/recovery budget sooner in terms of completed attempts.
|
||||||
|
|
||||||
|
This reduces fixed retry timing, without guaranteeing resistance to DPI. Browser scheduling, network queues and other protocol timing remain observable. Existing timeline examples describe the default disabled mode. To evaluate enabled mode, add a sampled delay to each retry pause, not to the initial connection or every data frame.
|
||||||
|
|
||||||
|
The policy changes existing retry waits only. Stricter per-call limits still apply: ordinary `/down` polls and committed `/up` calls use one attempt; their recovery replay permits two. This option does not create new retry loops. It neither extends `web.timeouts.bridge_retry_secs` nor any startup/recovery deadline.
|
||||||
|
|
||||||
## Illustrative timeline with approximate durations
|
## Illustrative timeline with approximate durations
|
||||||
|
|
||||||
**An explanatory model, not a benchmark or an expected latency range.** The numbers below are chosen to show how the stages combine. They do not reconstruct the reported 1000–1500 ms. Assume cached DNS, a 40 ms client-to-frontend RTT, a new TCP connection, a full TLS 1.3 handshake where required, an existing DC authorization key, and no loss or native request-timestamp reset. The baseline is Classic/DD. EE adds its own FakeTLS setup before the native timer.
|
**An explanatory model, not a benchmark or an expected latency range.** The numbers below are chosen to show how the stages combine. They do not reconstruct the reported 1000–1500 ms. Assume cached DNS, a 40 ms client-to-frontend RTT, a new TCP connection, a full TLS 1.3 handshake where required, an existing DC authorization key, and no loss or native request-timestamp reset. The baseline is Classic/DD. EE adds its own FakeTLS setup before the native timer.
|
||||||
@@ -126,10 +150,10 @@ The diagram starts at each checker's **latest request timestamp**, not at app la
|
|||||||
gantt
|
gantt
|
||||||
dateFormat x
|
dateFormat x
|
||||||
axisFormat %S.%L
|
axisFormat %S.%L
|
||||||
tickInterval 200millisecond
|
tickInterval 100millisecond
|
||||||
todayMarker off
|
todayMarker off
|
||||||
title Displayed ping - illustrative model
|
title Displayed ping - jitter off
|
||||||
accTitle: Displayed ping - illustrative model
|
accTitle: Displayed ping - jitter off
|
||||||
accDescr: Seconds from the request timestamp, labels show milliseconds
|
accDescr: Seconds from the request timestamp, labels show milliseconds
|
||||||
section Classic/DD - 100 ms
|
section Classic/DD - 100 ms
|
||||||
R 100 ms :n_r, 0, 100ms
|
R 100 ms :n_r, 0, 100ms
|
||||||
@@ -137,28 +161,31 @@ gantt
|
|||||||
U 40 ms :w_u, 0, 40ms
|
U 40 ms :w_u, 0, 40ms
|
||||||
R 100 ms :w_r, after w_u, 100ms
|
R 100 ms :w_r, after w_u, 100ms
|
||||||
D 60 ms :w_d, after w_r, 60ms
|
D 60 ms :w_d, after w_r, 60ms
|
||||||
section WEB with retry - 1240 ms
|
section WEB with retry - 490 ms
|
||||||
F 40 ms :crit, f_u, 0, 40ms
|
F 40 ms :crit, f_u, 0, 40ms
|
||||||
Wait 1000 ms :crit, retry_wait, after f_u, 1000ms
|
Wait 250 ms :crit, retry_wait, after f_u, 250ms
|
||||||
U 40 ms :retry_u, after retry_wait, 40ms
|
U 40 ms :retry_u, after retry_wait, 40ms
|
||||||
R 100 ms :retry_r, after retry_u, 100ms
|
R 100 ms :retry_r, after retry_u, 100ms
|
||||||
D 60 ms :retry_d, after retry_r, 60ms
|
D 60 ms :retry_d, after retry_r, 60ms
|
||||||
```
|
```
|
||||||
|
|
||||||
Stage durations: `R` = 100 ms of baseline MTProxy relay/network/DC request-response work. `U` = 40 ms of additional WEB uplink/OPEN/client work. `D` = 60 ms of additional WEB downlink/delivery work. `F` = 40 ms spent on one failed upload attempt. `Wait` = the 1000 ms wait requested by `Retry-After: 1`. `U` and `D` are illustrative incremental costs beyond `R`, not a second count of the full network round trip. ACK/commit gating is included only insofar as it actually delays delivery.
|
Stage durations: `R` = 100 ms of baseline MTProxy relay/network/DC request-response work. `U` = 40 ms of additional WEB uplink/OPEN/client work. `D` = 60 ms of additional WEB downlink/delivery work. `F` = 40 ms spent on one failed upload attempt. `Wait` = the 250 ms wait requested by `X-Telemt-Retry-After-Ms: 250`. `U` and `D` are illustrative incremental costs beyond `R`, not a second count of the full network round trip. ACK/commit gating is included only insofar as it actually delays delivery.
|
||||||
|
|
||||||
| Scenario | Before ping timer | Displayed ping | Total check time in this model |
|
| Scenario | Before ping timer | Displayed ping | Total check time in this model |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| Classic/DD | 40 ms | 100 ms | 140 ms |
|
| Classic/DD | 40 ms | 100 ms | 140 ms |
|
||||||
| WEB, no errors | 750 ms | 40 + 100 + 60 = 200 ms | 950 ms |
|
| WEB, no errors | 750 ms | 40 + 100 + 60 = 200 ms | 950 ms |
|
||||||
| WEB, one failed upload and one retry wait | 750 ms | 40 + 1000 + 40 + 100 + 60 = 1240 ms | 1990 ms |
|
| WEB, one failed upload and one retry wait | 750 ms | 40 + 250 + 40 + 100 + 60 = 490 ms | 1240 ms |
|
||||||
|
| WEB, same retry with uniform jitter 0–250 ms | 750 ms | 490–740 ms | 1240–1490 ms |
|
||||||
|
|
||||||
A further TCP + TLS 1.3 connection opened **inside** the measured interval could add approximately 80 ms here, if fully sequential: the 200 ms sample would become 280 ms. With connection reuse, that extra handshake cost is zero. Switching the initial full handshake from TLS 1.3 to TLS 1.2 adds about 40 ms to preparation under these assumptions, not to the displayed ping. These examples omit TLS processing, resumption and packet loss.
|
A further TCP + TLS 1.3 connection opened **inside** the measured interval could add approximately 80 ms here, if fully sequential: the 200 ms sample would become 280 ms. With connection reuse, that extra handshake cost is zero. Switching the initial full handshake from TLS 1.3 to TLS 1.2 adds about 40 ms to preparation under these assumptions, not to the displayed ping. These examples omit TLS processing, resumption and packet loss.
|
||||||
|
|
||||||
The 1240 ms row demonstrates one possible mechanism for a second-scale result: a retry confirmed by HTTP traces. It is not evidence that retries caused the original observation. Without such a retry, a large result requires locating other measured delays, such as queues, frontend buffering, connection setup or upstream work. Do not insert timeout values as waiting periods or force overlapping stages into this serial model.
|
The 490 ms row and diagram illustrate one retry with jitter disabled. The extra table row applies `enabled = true`, `min_ms = 0`, `max_ms = 250`, `distribution = "uniform"` to that same retry; its range comes from this model, not measurements. An earlier JavaScript bridge without the millisecond extension, or an intermediary removing that hint when jitter is disabled, retains the standard one-second fallback: the same model then gives a displayed ping of 1240 ms. Neither scenario identifies the cause of the original observation. Without trace evidence of retries, locate other delays such as queues, frontend buffering, connection setup or upstream work. Do not insert timeouts as waiting periods or force overlapping stages into this serial model.
|
||||||
|
|
||||||
## HTTP, WebSocket and other delay sources
|
## HTTP, WebSocket and other delay sources
|
||||||
|
|
||||||
|
Telemt overload responses carry `Retry-After: 1` and `X-Telemt-Retry-After-Ms: 250`. Only status `503` with that exact header pair selects a **250 ms base delay** in the generated bridge. With `web.retry_jitter.enabled = false`, the pause is 250 ms; when enabled, the configured random addition applies. Other responses use the standard `Retry-After` handling or fallback backoff described below. Earlier JavaScript bridge pages without support for the millisecond hint use the one-second fallback until replaced by a newly loaded page; this does not require updating the Telegram application. Attempt limits, absolute budgets, cancellation and admission limits remain unchanged.
|
||||||
|
|
||||||
| Factor | Effect and evidence |
|
| Factor | Effect and evidence |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| HTTP uplink | The generated bridge offers `X-Telemt-Up-Window: 4`; the server accepts 1–4, with legacy fallback 1. Window 1 waits for an ACK before the next upload; window 4 permits bounded concurrency. Not all HTTP traffic is stop-and-wait. See [negotiation][runtime] and [session handler][session]. |
|
| HTTP uplink | The generated bridge offers `X-Telemt-Up-Window: 4`; the server accepts 1–4, with legacy fallback 1. Window 1 waits for an ACK before the next upload; window 4 permits bounded concurrency. Not all HTTP traffic is stop-and-wait. See [negotiation][runtime] and [session handler][session]. |
|
||||||
@@ -168,7 +195,7 @@ The 1240 ms row demonstrates one possible mechanism for a second-scale result: a
|
|||||||
| Frontend buffering | Request/response buffering or missing streaming/Upgrade support can delay small messages. Compare with the existing NGINX example; preserve routing, authentication and limits. |
|
| Frontend buffering | Request/response buffering or missing streaming/Upgrade support can delay small messages. Compare with the existing NGINX example; preserve routing, authentication and limits. |
|
||||||
| Client scheduling | Java accept/read threads, UI dispatch, WebView/JavaScript and delivery back to native code add queues. CPU pressure, mobile power management and network transitions can amplify them. |
|
| Client scheduling | Java accept/read threads, UI dispatch, WebView/JavaScript and delivery back to native code add queues. CPU pressure, mobile power management and network transitions can amplify them. |
|
||||||
| Relay and network | Remaining stream admission, inner MTProxy handshake, Direct connection or ME registration, Telegram response, loss/retransmission and queue pressure can contribute. A ready WEB session does not prove a ready upstream. |
|
| Relay and network | Remaining stream admission, inner MTProxy handshake, Direct connection or ME registration, Telegram response, loss/retransmission and queue pressure can contribute. A ready WEB session does not prove a ready upstream. |
|
||||||
| Errors and retries | Telemt can return `503` with `Retry-After: 1`. The bridge honors it; other retry backoff starts at 250 ms and doubles up to 2000 ms plus jitter up to approximately 25%, within the retry budget. Retryable HTTP statuses include 408/429/502/503/504. A trace must show such events before attributing a one-second step to them. See [responses][response] and [retry logic][request]. |
|
| Errors and retries | Retryable statuses are 408/429/502/503/504. With jitter disabled, the exact Telemt overload hint gives a 250 ms pause; without a positive server hint, backoff starts at 250 ms and doubles to a 2000 ms base plus legacy jitter below 25%. With jitter enabled, the pause is the positive server hint or that base **plus** the configured sample, replacing legacy jitter. Budgets and per-call attempt limits still apply. Record the loaded bridge policy and actual retry timestamps. See [responses][response] and [retry logic][request]. |
|
||||||
|
|
||||||
Deadlines are not mandatory sleeps. The default 10 s bridge-request deadline, 90 s retry budget, 30 s stream-first-byte deadline and 10 s stream-handshake deadline must not be summed into normal ping. `carrier_probe_coalesce_ms=0` disables that optional coalescing delay. Carrier fallback deadlines affect failed attempts, not every successful exchange. See [timeout defaults](../../src/config/types/web/defaults.rs).
|
Deadlines are not mandatory sleeps. The default 10 s bridge-request deadline, 90 s retry budget, 30 s stream-first-byte deadline and 10 s stream-handshake deadline must not be summed into normal ping. `carrier_probe_coalesce_ms=0` disables that optional coalescing delay. Carrier fallback deadlines affect failed attempts, not every successful exchange. See [timeout defaults](../../src/config/types/web/defaults.rs).
|
||||||
|
|
||||||
@@ -176,7 +203,7 @@ A conceptual WEB sample is **remaining setup + carrier/network transit + queues
|
|||||||
|
|
||||||
## Diagnosis without changing protections
|
## Diagnosis without changing protections
|
||||||
|
|
||||||
1. Record client/build, Android WebView version, carrier, public endpoint, IP family, network, Direct/ME route, DC and load. Match these conditions for comparison. Respect Android's two-minute cached result; do not treat repeated UI reads as new samples.
|
1. Record client/build, Android WebView version, the loaded bridge’s `web.retry_jitter` policy, carrier, public endpoint, IP family, network, Direct/ME route, DC and load. Match these conditions for comparison. Respect Android's two-minute cached result; do not treat repeated UI reads as new samples.
|
||||||
2. Separate three experiments: a new proxy-list check; a new logical stream on a ready carrier; application RPC on an established MTProto session. The latter two require suitable client instrumentation and are not automatically provided by the proxy-list display. Record individual samples and distributions rather than comparing one cold sample with one warm sample.
|
2. Separate three experiments: a new proxy-list check; a new logical stream on a ready carrier; application RPC on an established MTProto session. The latter two require suitable client instrumentation and are not automatically provided by the proxy-list display. Record individual samples and distributions rather than comparing one cold sample with one warm sample.
|
||||||
3. Use the authenticated `GET /web-status` and existing `[web.debug]` controls with `capture_timings=true`, `capture_frames=true`, `body_capture="metadata"`. Enable bounded capture as described in the [WEB diagnostics guide](WEB_PROXY.en.md), then restore its prior state. Payloads, capabilities and secrets are unnecessary for this investigation.
|
3. Use the authenticated `GET /web-status` and existing `[web.debug]` controls with `capture_timings=true`, `capture_frames=true`, `body_capture="metadata"`. Enable bounded capture as described in the [WEB diagnostics guide](WEB_PROXY.en.md), then restore its prior state. Payloads, capabilities and secrets are unnecessary for this investigation.
|
||||||
4. Correlate session creation, carrier selection/commit/failure, `stream_admitted`, `stream_first_byte`, `handshake_succeeded`, OPEN/DATA, HTTP status and retries. `relay_started` precedes upstream work and is not a DC-ready timestamp. Use `GET /v1/runtime/web/status` and `GET /v1/runtime/web/sessions` for capacity and queue-pressure context, not end-to-end RTT.
|
4. Correlate session creation, carrier selection/commit/failure, `stream_admitted`, `stream_first_byte`, `handshake_succeeded`, OPEN/DATA, HTTP status and retries. `relay_started` precedes upstream work and is not a DC-ready timestamp. Use `GET /v1/runtime/web/status` and `GET /v1/runtime/web/sessions` for capacity and queue-pressure context, not end-to-end RTT.
|
||||||
@@ -184,7 +211,7 @@ A conceptual WEB sample is **remaining setup + carrier/network transit + queues
|
|||||||
6. Add frontend connection/TLS/request timing and client timestamps to locate delays outside Telemt. Establish connection reuse, negotiated HTTP version, buffering and Upgrade behavior. Bridge startup/HELLO sideband events do not provide a complete client timeline. Synchronize clocks for cross-host comparisons or use durations on each host.
|
6. Add frontend connection/TLS/request timing and client timestamps to locate delays outside Telemt. Establish connection reuse, negotiated HTTP version, buffering and Upgrade behavior. Bridge startup/HELLO sideband events do not provide a complete client timeline. Synchronize clocks for cross-host comparisons or use durations on each host.
|
||||||
7. If ME is involved, compare the existing `ME RTT sample` trace (`rtt_ms`, `ema_ms`, `base_ms`, `degraded`). The timestamp precedes the writer queue/flush, and the EMA uses 80% previous value plus 20% new sample. Keepalive scheduling before that timestamp is excluded. A low ME value with high Android ping points to work outside that measured ME segment, without identifying one particular cause. See [writer][writer] and [reader][reader].
|
7. If ME is involved, compare the existing `ME RTT sample` trace (`rtt_ms`, `ema_ms`, `base_ms`, `degraded`). The timestamp precedes the writer queue/flush, and the EMA uses 80% previous value plus 20% new sample. Keepalive scheduling before that timestamp is excluded. A low ME value with high Android ping points to work outside that measured ME segment, without identifying one particular cause. See [writer][writer] and [reader][reader].
|
||||||
|
|
||||||
Evidence patterns: fast Telemt handling with late client delivery suggests investigating frontend/network/client queues; `503` plus `Retry-After: 1` supports a retry delay; long upstream work calls for Direct/ME investigation. None alone proves that TLS cryptography causes 1000–1500 ms. Keep compatibility, certificate verification, admission limits and backpressure intact while collecting evidence.
|
Evidence patterns: fast Telemt handling with late client delivery suggests investigating frontend/network/client queues; `503` and its retry headers identify the base delay, while the loaded jitter policy and client timestamps establish the actual pause; long upstream work calls for Direct/ME investigation. None alone proves that TLS cryptography causes 1000–1500 ms. Keep compatibility, certificate verification, admission limits and backpressure intact while collecting evidence.
|
||||||
|
|
||||||
## Evidence scope
|
## Evidence scope
|
||||||
|
|
||||||
|
|||||||
+39
-12
@@ -94,7 +94,7 @@ flowchart LR
|
|||||||
W5 --> W6["Получен TL_pong<br/>Отображаемый замер завершён"]
|
W5 --> W6["Получен TL_pong<br/>Отображаемый замер завершён"]
|
||||||
X["Только если нужно ещё одно соединение<br/>TCP + TLS, возможный WebSocket Upgrade<br/>При переиспользовании нет handshake на каждый ping"] -.-> W3
|
X["Только если нужно ещё одно соединение<br/>TCP + TLS, возможный WebSocket Upgrade<br/>При переиспользовании нет handshake на каждый ping"] -.-> W3
|
||||||
X -.-> W5
|
X -.-> W5
|
||||||
R["Только при ошибках или перегрузке<br/>Повторы и backoff<br/>Retry-After: 1 может добавить около секунды"] -.-> W3
|
R["Только при ошибках или перегрузке<br/>Повторы и backoff<br/>База Telemt 250 мс<br/>Плюс опциональный jitter"] -.-> W3
|
||||||
R -.-> W5
|
R -.-> W5
|
||||||
end
|
end
|
||||||
classDef preparation fill:#eeeeee,stroke:#666666,color:#111111
|
classDef preparation fill:#eeeeee,stroke:#666666,color:#111111
|
||||||
@@ -113,6 +113,30 @@ flowchart LR
|
|||||||
|
|
||||||
Таким образом, в видимую разницу могут войти оставшееся открытие WEB-потока, дополнительные соединения, обработка транспорта, планирование и подтверждённые повторы. Это не фиксированная надбавка TLS и не арифметическая сумма блоков. Начальный настоящий TLS намеренно показан до таймера Android: он влияет на полное время проверки, но обычно не на отображаемый замер. Отдельный транспорт проверки также означает, что активное соединение приложения не гарантирует прогретую проверку в списке прокси.
|
Таким образом, в видимую разницу могут войти оставшееся открытие WEB-потока, дополнительные соединения, обработка транспорта, планирование и подтверждённые повторы. Это не фиксированная надбавка TLS и не арифметическая сумма блоков. Начальный настоящий TLS намеренно показан до таймера Android: он влияет на полное время проверки, но обычно не на отображаемый замер. Отдельный транспорт проверки также означает, что активное соединение приложения не гарантирует прогретую проверку в списке прокси.
|
||||||
|
|
||||||
|
### Настраиваемый jitter HTTP-повторов
|
||||||
|
|
||||||
|
`[web.retry_jitter]` добавляет независимо выбранную задержку к каждому существующему HTTP-повтору бриджа: сетевым ошибкам и ответам 408/429/502/503/504. Менять приложения Telegram не требуется. Без секции или при `enabled = false` сохраняются подсказка Telemt на 250 мс и прежний backoff/jitter.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[web.retry_jitter]
|
||||||
|
enabled = true
|
||||||
|
min_ms = 0
|
||||||
|
max_ms = 250
|
||||||
|
distribution = "uniform"
|
||||||
|
# Only for distribution = "triangular":
|
||||||
|
# peak_ms = 125
|
||||||
|
```
|
||||||
|
|
||||||
|
Диапазон задаёт **добавку**, а не полную паузу: подсказка Telemt 250 мс с этим примером даёт 250–500 мс. Без положительной серверной подсказки база остаётся 250, 500, 1000, затем 2000 мс. Включённый jitter заменяет прежний jitter до 25%. Корректный стандартный `Retry-After` во включённом режиме не сокращается прежним пределом в 30 секунд. Если пауза не помещается в оставшийся бюджет операции, бюджет истекает без раннего повтора.
|
||||||
|
|
||||||
|
Значения по умолчанию: `enabled = false`, `min_ms = 0`, `max_ms = 250`, `distribution = "uniform"`, `peak_ms` отсутствует. Требуется `0 <= min_ms <= max_ms <= 30000`. `uniform` выбирает целые миллисекунды равномерно; `triangular` использует треугольную плотность с округлением до миллисекунд. Необязательный пик по умолчанию находится посередине и должен входить в диапазон. Явный пик для `uniform`, неизвестные ключи/распределения и неверные границы отклоняются даже при выключенной опции. Одинаковые границы дают постоянную добавку.
|
||||||
|
|
||||||
|
Политика фиксируется в каждой странице бриджа. Reload через конфиг/API влияет на новые страницы; активные сохраняют настройки при recovery. Recovery JSON и HTTP-заголовки совместимости не меняются. Используется `crypto.getRandomValues`, при недоступности — `Math.random` для совместимости. Успешный трафик не задерживается. Лимиты попыток, общий бюджет, отмена и повтор неизменных payload/sequence сохраняются; более длинные паузы могут уменьшить число попыток, помещающихся в startup/recovery-бюджет.
|
||||||
|
|
||||||
|
Это размывает фиксированные интервалы повторов, но не гарантирует защиту от DPI. Планирование браузера, сетевые очереди и другие временные характеристики протокола остаются наблюдаемыми. Существующие примеры временной шкалы описывают выключенную опцию. Для включённого режима добавляйте выбранную задержку к каждой паузе повтора, а не к первому соединению или каждому кадру данных.
|
||||||
|
|
||||||
|
Политика меняет только уже предусмотренные паузы перед повтором. Более строгие ограничения отдельных вызовов сохраняются: обычный poll `/down` и вызов `/up` после commit выполняют одну попытку; их replay при восстановлении допускает две. Опция не создаёт новых циклов повторов. Она не продлевает `web.timeouts.bridge_retry_secs` и сроки запуска или восстановления.
|
||||||
|
|
||||||
## Ориентировочная временная шкала
|
## Ориентировочная временная шкала
|
||||||
|
|
||||||
**Поясняющая модель, а не бенчмарк и не норматив задержки.** Числа подобраны, чтобы показать сложение этапов. Они не восстанавливают наблюдавшиеся 1000–1500 мс. Условия примера: DNS уже закеширован, RTT от клиента до фронтенда — 40 мс, TCP-соединение новое, при необходимости выполняется полный TLS 1.3 handshake, ключ авторизации DC уже есть, потерь и сброса нативной временной метки запроса нет. Базовый вариант — Classic/DD. Для EE собственная подготовка FakeTLS добавляется до нативного таймера.
|
**Поясняющая модель, а не бенчмарк и не норматив задержки.** Числа подобраны, чтобы показать сложение этапов. Они не восстанавливают наблюдавшиеся 1000–1500 мс. Условия примера: DNS уже закеширован, RTT от клиента до фронтенда — 40 мс, TCP-соединение новое, при необходимости выполняется полный TLS 1.3 handshake, ключ авторизации DC уже есть, потерь и сброса нативной временной метки запроса нет. Базовый вариант — Classic/DD. Для EE собственная подготовка FakeTLS добавляется до нативного таймера.
|
||||||
@@ -126,10 +150,10 @@ flowchart LR
|
|||||||
gantt
|
gantt
|
||||||
dateFormat x
|
dateFormat x
|
||||||
axisFormat %S.%L
|
axisFormat %S.%L
|
||||||
tickInterval 200millisecond
|
tickInterval 100millisecond
|
||||||
todayMarker off
|
todayMarker off
|
||||||
title Отображаемый ping - условная модель
|
title Отображаемый ping - jitter выключен
|
||||||
accTitle: Отображаемый ping - условная модель
|
accTitle: Отображаемый ping - jitter выключен
|
||||||
accDescr: Секунды от метки запроса, подписи этапов в миллисекундах
|
accDescr: Секунды от метки запроса, подписи этапов в миллисекундах
|
||||||
section Classic/DD - 100 мс
|
section Classic/DD - 100 мс
|
||||||
R 100 мс :n_r, 0, 100ms
|
R 100 мс :n_r, 0, 100ms
|
||||||
@@ -137,28 +161,31 @@ gantt
|
|||||||
U 40 мс :w_u, 0, 40ms
|
U 40 мс :w_u, 0, 40ms
|
||||||
R 100 мс :w_r, after w_u, 100ms
|
R 100 мс :w_r, after w_u, 100ms
|
||||||
D 60 мс :w_d, after w_r, 60ms
|
D 60 мс :w_d, after w_r, 60ms
|
||||||
section WEB с повтором - 1240 мс
|
section WEB с повтором - 490 мс
|
||||||
F 40 мс :crit, f_u, 0, 40ms
|
F 40 мс :crit, f_u, 0, 40ms
|
||||||
Ожидание 1000 мс :crit, retry_wait, after f_u, 1000ms
|
Ожидание 250 мс :crit, retry_wait, after f_u, 250ms
|
||||||
U 40 мс :retry_u, after retry_wait, 40ms
|
U 40 мс :retry_u, after retry_wait, 40ms
|
||||||
R 100 мс :retry_r, after retry_u, 100ms
|
R 100 мс :retry_r, after retry_u, 100ms
|
||||||
D 60 мс :retry_d, after retry_r, 60ms
|
D 60 мс :retry_d, after retry_r, 60ms
|
||||||
```
|
```
|
||||||
|
|
||||||
Длительности этапов: `R` = 100 мс базовой работы MTProxy relay/сети/DC для запроса и ответа. `U` = 40 мс дополнительной работы WEB на отправке/OPEN/клиенте. `D` = 60 мс дополнительной работы WEB на приёме и доставке. `F` = 40 мс одной неудачной попытки upload. `Ожидание` = 1000 мс ожидания по `Retry-After: 1`. `U` и `D` — условные дополнительные затраты сверх `R`, а не повторный учёт полного сетевого RTT. Ожидание ACK/commit учитывается лишь в той мере, в какой оно действительно задержало доставку.
|
Длительности этапов: `R` = 100 мс базовой работы MTProxy relay/сети/DC для запроса и ответа. `U` = 40 мс дополнительной работы WEB на отправке/OPEN/клиенте. `D` = 60 мс дополнительной работы WEB на приёме и доставке. `F` = 40 мс одной неудачной попытки upload. `Ожидание` = 250 мс ожидания по `X-Telemt-Retry-After-Ms: 250`. `U` и `D` — условные дополнительные затраты сверх `R`, а не повторный учёт полного сетевого RTT. Ожидание ACK/commit учитывается лишь в той мере, в какой оно действительно задержало доставку.
|
||||||
|
|
||||||
| Сценарий | До таймера ping | Отображаемый ping | Полное время проверки в модели |
|
| Сценарий | До таймера ping | Отображаемый ping | Полное время проверки в модели |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| Classic/DD | 40 мс | 100 мс | 140 мс |
|
| Classic/DD | 40 мс | 100 мс | 140 мс |
|
||||||
| WEB без ошибок | 750 мс | 40 + 100 + 60 = 200 мс | 950 мс |
|
| WEB без ошибок | 750 мс | 40 + 100 + 60 = 200 мс | 950 мс |
|
||||||
| WEB с одной неудачной загрузкой и одним ожиданием повтора | 750 мс | 40 + 1000 + 40 + 100 + 60 = 1240 мс | 1990 мс |
|
| WEB с одной неудачной загрузкой и одним ожиданием повтора | 750 мс | 40 + 250 + 40 + 100 + 60 = 490 мс | 1240 мс |
|
||||||
|
| WEB, тот же повтор с uniform jitter 0–250 мс | 750 мс | 490–740 мс | 1240–1490 мс |
|
||||||
|
|
||||||
Ещё одно TCP + TLS 1.3 соединение, открытое **внутри** замера, могло бы добавить здесь около 80 мс при полностью последовательном выполнении: замер 200 мс превратился бы в 280 мс. При переиспользовании соединения затраты на этот дополнительный handshake равны нулю. Замена начального полного TLS 1.3 handshake на TLS 1.2 при этих условиях добавляет примерно 40 мс к подготовке, а не к показанному ping. В примерах не учтены обработка TLS, возобновление сессии и потери пакетов.
|
Ещё одно TCP + TLS 1.3 соединение, открытое **внутри** замера, могло бы добавить здесь около 80 мс при полностью последовательном выполнении: замер 200 мс превратился бы в 280 мс. При переиспользовании соединения затраты на этот дополнительный handshake равны нулю. Замена начального полного TLS 1.3 handshake на TLS 1.2 при этих условиях добавляет примерно 40 мс к подготовке, а не к показанному ping. В примерах не учтены обработка TLS, возобновление сессии и потери пакетов.
|
||||||
|
|
||||||
Строка с 1240 мс показывает один возможный механизм секундного результата — повтор, подтверждённый HTTP-трассировкой. Она не доказывает, что исходное наблюдение вызвано повторами. Если такого повтора нет, нужно найти другие фактические задержки: очереди, буферизацию фронтенда, открытие соединений или работу upstream. Не подставляйте таймауты вместо пауз и не переносите перекрывающиеся этапы в эту последовательную модель без проверки.
|
Строка с 490 мс и диаграмма показывают один повтор при выключенном jitter. Дополнительная строка таблицы применяет к тому же повтору `enabled = true`, `min_ms = 0`, `max_ms = 250`, `distribution = "uniform"`; её диапазон получен из модели, а не измерений. Прежний JavaScript-мост без миллисекундного расширения или посредник, удаляющий эту подсказку при выключенном jitter, сохраняет стандартную секундную паузу: отображаемый ping в той же модели составит 1240 мс. Ни один сценарий не устанавливает причину исходного наблюдения. Если повторы не подтверждены трассировкой, ищите другие задержки: очереди, буферизацию фронтенда, открытие соединений или upstream. Не подставляйте таймауты вместо пауз и не переносите перекрывающиеся этапы в эту последовательную модель без проверки.
|
||||||
|
|
||||||
## HTTP, WebSocket и другие источники задержки
|
## HTTP, WebSocket и другие источники задержки
|
||||||
|
|
||||||
|
Ответы Telemt при перегрузке содержат `Retry-After: 1` и `X-Telemt-Retry-After-Ms: 250`. Только статус `503` с этой точной парой заголовков задаёт сгенерированному мосту **базовую паузу 250 мс**. При `web.retry_jitter.enabled = false` пауза равна 250 мс; при включении добавляется настроенная случайная задержка. Для остальных ответов действуют стандартная обработка `Retry-After` или резервный backoff, описанные ниже. Ранее загруженные страницы JavaScript-моста без поддержки миллисекундной подсказки используют секундную паузу до загрузки новой страницы; обновлять приложение Telegram для этого не нужно. Лимиты попыток, абсолютные бюджеты, отмена и ограничения admission не меняются.
|
||||||
|
|
||||||
| Фактор | Влияние и подтверждение |
|
| Фактор | Влияние и подтверждение |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| HTTP uplink | Генерируемый мост предлагает `X-Telemt-Up-Window: 4`; сервер принимает 1–4, при отсутствии согласования используется 1. Окно 1 ждёт ACK перед следующей загрузкой, окно 4 допускает ограниченный параллелизм. Не весь HTTP работает по схеме «отправить и ждать». См. [согласование][runtime] и [обработчик сессии][session]. |
|
| HTTP uplink | Генерируемый мост предлагает `X-Telemt-Up-Window: 4`; сервер принимает 1–4, при отсутствии согласования используется 1. Окно 1 ждёт ACK перед следующей загрузкой, окно 4 допускает ограниченный параллелизм. Не весь HTTP работает по схеме «отправить и ждать». См. [согласование][runtime] и [обработчик сессии][session]. |
|
||||||
@@ -168,7 +195,7 @@ gantt
|
|||||||
| Буферизация фронтенда | Буферизация запросов/ответов или отсутствие поддержки streaming/Upgrade могут задерживать короткие сообщения. Сверьте настройки с существующим примером NGINX, сохраняя маршрутизацию, аутентификацию и лимиты. |
|
| Буферизация фронтенда | Буферизация запросов/ответов или отсутствие поддержки streaming/Upgrade могут задерживать короткие сообщения. Сверьте настройки с существующим примером NGINX, сохраняя маршрутизацию, аутентификацию и лимиты. |
|
||||||
| Планирование клиента | Java accept/read, UI dispatch, WebView/JavaScript и возврат в нативный код добавляют очереди. Нагрузка CPU, энергосбережение и смена мобильной сети могут усиливать задержки. |
|
| Планирование клиента | Java accept/read, UI dispatch, WebView/JavaScript и возврат в нативный код добавляют очереди. Нагрузка CPU, энергосбережение и смена мобильной сети могут усиливать задержки. |
|
||||||
| Пересылка и сеть | Могут учитываться оставшийся admission потока, внутренний MTProxy-handshake, подключение Direct или регистрация ME, ответ Telegram, потери/повторная передача и очереди. Готовая WEB-сессия не доказывает готовность upstream. |
|
| Пересылка и сеть | Могут учитываться оставшийся admission потока, внутренний MTProxy-handshake, подключение Direct или регистрация ME, ответ Telegram, потери/повторная передача и очереди. Готовая WEB-сессия не доказывает готовность upstream. |
|
||||||
| Ошибки и повторы | Telemt может вернуть `503` с `Retry-After: 1`. Мост учитывает его; для других повторов backoff начинается с 250 мс и удваивается до 2000 мс плюс jitter примерно до 25%, в пределах бюджета повторов. Повторяемые HTTP-статусы включают 408/429/502/503/504. Прежде чем объяснять секундную ступень этим механизмом, нужно увидеть события в трассировке. См. [ответы][response] и [повторы][request]. |
|
| Ошибки и повторы | Повторяемые статусы: 408/429/502/503/504. При выключенном jitter точная подсказка Telemt задаёт паузу 250 мс; без положительной подсказки сервера backoff начинается с 250 мс и удваивается до базовых 2000 мс плюс прежний jitter менее 25%. При включённом jitter пауза равна положительной подсказке сервера или этой базе **плюс** настроенная случайная добавка, заменяющая прежний jitter. Бюджеты и ограничения попыток отдельных вызовов сохраняются. Фиксируйте политику загруженного моста и фактическое время повторов. См. [ответы][response] и [повторы][request]. |
|
||||||
|
|
||||||
Дедлайны не являются обязательными паузами. Стандартные 10 с для запроса моста, 90 с бюджета повторов, 30 с ожидания первого байта потока и 10 с handshake потока нельзя складывать в обычный ping. `carrier_probe_coalesce_ms=0` отключает соответствующую дополнительную задержку объединения проб. Дедлайны переключения транспорта относятся к неудачным попыткам, а не к каждому успешному обмену. См. [значения по умолчанию](../../src/config/types/web/defaults.rs).
|
Дедлайны не являются обязательными паузами. Стандартные 10 с для запроса моста, 90 с бюджета повторов, 30 с ожидания первого байта потока и 10 с handshake потока нельзя складывать в обычный ping. `carrier_probe_coalesce_ms=0` отключает соответствующую дополнительную задержку объединения проб. Дедлайны переключения транспорта относятся к неудачным попыткам, а не к каждому успешному обмену. См. [значения по умолчанию](../../src/config/types/web/defaults.rs).
|
||||||
|
|
||||||
@@ -176,7 +203,7 @@ gantt
|
|||||||
|
|
||||||
## Диагностика с сохранением защит
|
## Диагностика с сохранением защит
|
||||||
|
|
||||||
1. Запишите клиент/сборку, версию Android WebView, транспорт, публичный endpoint, семейство IP, сеть, маршрут Direct/ME, DC и нагрузку. Сравнивайте при одинаковых условиях. Учитывайте двухминутное кеширование Android: повторное чтение интерфейса не означает новый замер.
|
1. Запишите клиент/сборку, версию Android WebView, политику `web.retry_jitter` загруженного моста, транспорт, публичный endpoint, семейство IP, сеть, маршрут Direct/ME, DC и нагрузку. Сравнивайте при одинаковых условиях. Учитывайте двухминутное кеширование Android: повторное чтение интерфейса не означает новый замер.
|
||||||
2. Разделяйте три эксперимента: новую проверку в списке прокси; новый логический поток на готовом транспорте; прикладной RPC в установленной MTProto-сессии. Последние два требуют подходящих средств измерения в клиенте и не предоставляются автоматически списком прокси. Собирайте отдельные замеры и распределения, а не сравнивайте единичный холодный замер с прогретым.
|
2. Разделяйте три эксперимента: новую проверку в списке прокси; новый логический поток на готовом транспорте; прикладной RPC в установленной MTProto-сессии. Последние два требуют подходящих средств измерения в клиенте и не предоставляются автоматически списком прокси. Собирайте отдельные замеры и распределения, а не сравнивайте единичный холодный замер с прогретым.
|
||||||
3. Используйте аутентифицированный `GET /web-status` и существующие настройки `[web.debug]`: `capture_timings=true`, `capture_frames=true`, `body_capture="metadata"`. Включите ограниченный сбор по [руководству диагностики WEB](WEB_PROXY.ru.md), затем восстановите предыдущее состояние. Payload, capabilities и секреты для этой задачи не нужны.
|
3. Используйте аутентифицированный `GET /web-status` и существующие настройки `[web.debug]`: `capture_timings=true`, `capture_frames=true`, `body_capture="metadata"`. Включите ограниченный сбор по [руководству диагностики WEB](WEB_PROXY.ru.md), затем восстановите предыдущее состояние. Payload, capabilities и секреты для этой задачи не нужны.
|
||||||
4. Сопоставьте создание сессии, выбор/commit/ошибку транспорта, `stream_admitted`, `stream_first_byte`, `handshake_succeeded`, OPEN/DATA, HTTP-статусы и повторы. `relay_started` предшествует работе с upstream и не означает готовность DC. `GET /v1/runtime/web/status` и `GET /v1/runtime/web/sessions` дают контекст ёмкости и давления очередей, а не сквозной RTT.
|
4. Сопоставьте создание сессии, выбор/commit/ошибку транспорта, `stream_admitted`, `stream_first_byte`, `handshake_succeeded`, OPEN/DATA, HTTP-статусы и повторы. `relay_started` предшествует работе с upstream и не означает готовность DC. `GET /v1/runtime/web/status` и `GET /v1/runtime/web/sessions` дают контекст ёмкости и давления очередей, а не сквозной RTT.
|
||||||
@@ -184,7 +211,7 @@ gantt
|
|||||||
6. Добавьте измерения соединений/TLS/запросов фронтенда и временные метки клиента, чтобы найти задержку вне Telemt. Проверьте повторное использование соединений, согласованный HTTP, буферизацию и Upgrade. Sideband-события запуска моста/HELLO не дают полную временную шкалу клиента. Для сравнения разных хостов синхронизируйте часы либо используйте локальные длительности.
|
6. Добавьте измерения соединений/TLS/запросов фронтенда и временные метки клиента, чтобы найти задержку вне Telemt. Проверьте повторное использование соединений, согласованный HTTP, буферизацию и Upgrade. Sideband-события запуска моста/HELLO не дают полную временную шкалу клиента. Для сравнения разных хостов синхронизируйте часы либо используйте локальные длительности.
|
||||||
7. При ME сопоставьте существующий trace `ME RTT sample` (`rtt_ms`, `ema_ms`, `base_ms`, `degraded`). Метка ставится до очереди writer/flush; EMA состоит из 80% прежнего значения и 20% нового замера. Планирование keepalive до этой метки не учитывается. Низкий ME RTT при высоком Android ping указывает на работу вне измеренного участка ME, но не определяет конкретную причину. См. [writer][writer] и [reader][reader].
|
7. При ME сопоставьте существующий trace `ME RTT sample` (`rtt_ms`, `ema_ms`, `base_ms`, `degraded`). Метка ставится до очереди writer/flush; EMA состоит из 80% прежнего значения и 20% нового замера. Планирование keepalive до этой метки не учитывается. Низкий ME RTT при высоком Android ping указывает на работу вне измеренного участка ME, но не определяет конкретную причину. См. [writer][writer] и [reader][reader].
|
||||||
|
|
||||||
Примеры интерпретации: быстрая обработка Telemt при поздней доставке клиенту направляет проверку к фронтенду, сети и очередям клиента; `503` вместе с `Retry-After: 1` подтверждает задержку повтора; длительная работа upstream требует изучения Direct/ME. Ни один из признаков сам по себе не доказывает, что 1000–1500 мс вызваны криптографией TLS. При сборе данных сохраняйте совместимость, проверку сертификатов, лимиты admission и backpressure.
|
Примеры интерпретации: быстрая обработка Telemt при поздней доставке клиенту направляет проверку к фронтенду, сети и очередям клиента; `503` и его retry-заголовки определяют базовую задержку, а политика jitter загруженного моста и клиентские отметки времени позволяют установить фактическую паузу; длительная работа upstream требует изучения Direct/ME. Ни один из признаков сам по себе не доказывает, что 1000–1500 мс вызваны криптографией TLS. При сборе данных сохраняйте совместимость, проверку сертификатов, лимиты admission и backpressure.
|
||||||
|
|
||||||
## Границы подтверждения
|
## Границы подтверждения
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ Leiten Sie den vollständigen konfigurierten WEB-Bereich an Telemt weiter. Beim
|
|||||||
|
|
||||||
- Bei leerem `base_path` lautet der öffentliche Endpunkt `https://HOST:443/`, andernfalls `https://HOST:443/BASE/`. Der Basispfad ist groß-/kleinschreibungssensitiv und exakt; Telemt leitet ihn nicht um, normalisiert ihn nicht und entfernt ihn nicht vor der Decoy-Weiterleitung.
|
- Bei leerem `base_path` lautet der öffentliche Endpunkt `https://HOST:443/`, andernfalls `https://HOST:443/BASE/`. Der Basispfad ist groß-/kleinschreibungssensitiv und exakt; Telemt leitet ihn nicht um, normalisiert ihn nicht und entfernt ihn nicht vor der Decoy-Weiterleitung.
|
||||||
- Unterstützt werden 16-Byte-MTProxy-Secrets in den Modi `plain` und `dd`. FakeTLS-Secrets mit `ee` werden im WEB-Modus nicht unterstützt.
|
- Unterstützt werden 16-Byte-MTProxy-Secrets in den Modi `plain` und `dd`. FakeTLS-Secrets mit `ee` werden im WEB-Modus nicht unterstützt.
|
||||||
- `web.carrier` wählt den einzigen Carrier bei deaktivierter Auto-Negotiation und den letzten Fallback bei aktivierter Negotiation. `https` verwendet serialisierte HTTPS-Uplinks und Long Polling. `https-lanes` verwendet unabhängige HTTPS-Sequenzen und Polls pro logischem Stream. `websocket` verwendet einen geordneten WebSocket für alle Streams. `websocket-lanes` verwendet einen unabhängig verwalteten WebSocket für jeden logischen Stream ungleich null.
|
- `web.carrier` wählt den einzigen Carrier bei deaktivierter Auto-Negotiation und den letzten Fallback bei aktivierter Negotiation. `https` verwendet eine gemeinsame HTTPS-Uplink-Sequenz und Long Polling. `https-lanes` verwendet unabhängige HTTPS-Sequenzen und Polls pro logischem Stream. `websocket` verwendet einen geordneten WebSocket für alle Streams. `websocket-lanes` verwendet einen unabhängig verwalteten WebSocket für jeden logischen Stream ungleich null.
|
||||||
- Ein fehlendes `web.carriers` oder `web.carriers = false` deaktiviert Auto-Negotiation und Lernen. Ein nicht leeres Array aktiviert ausschließlich die sequenzielle Start-Negotiation; eine bereits festgeschriebene Sitzung wird nie migriert.
|
- Ein fehlendes `web.carriers` oder `web.carriers = false` deaktiviert Auto-Negotiation und Lernen. Ein nicht leeres Array aktiviert ausschließlich die sequenzielle Start-Negotiation; eine bereits festgeschriebene Sitzung wird nie migriert.
|
||||||
- Native Clients ohne kanonische Carrier-Negotiation-Header verwenden den konfigurierten festen `carrier`, auch wenn `carriers` die Negotiation für fähige Clients aktiviert. Das aktuelle Telegram iOS unterstützt nur `https`; für metadatafreies iOS muss der Betreiber daher `web.carrier = "https"` setzen, `https-lanes` wird nicht unterstützt. User-Agent-Werte einschließlich CFNetwork oder Darwin leiten niemals Capabilities ab. Sendet ein nativer iOS-Client explizite Negotiation-Metadaten, schneidet Telemt sie mit der serverautoritativen Obergrenze `{https}` und lehnt ein leeres Ergebnis ab; andere explizite Clients verwenden ihren angegebenen Capability-Satz.
|
- Native Clients ohne kanonische Carrier-Negotiation-Header verwenden den konfigurierten festen `carrier`, auch wenn `carriers` die Negotiation für fähige Clients aktiviert. Das aktuelle Telegram iOS unterstützt nur `https`; für metadatafreies iOS muss der Betreiber daher `web.carrier = "https"` setzen, `https-lanes` wird nicht unterstützt. User-Agent-Werte einschließlich CFNetwork oder Darwin leiten niemals Capabilities ab. Sendet ein nativer iOS-Client explizite Negotiation-Metadaten, schneidet Telemt sie mit der serverautoritativen Obergrenze `{https}` und lehnt ein leeres Ergebnis ab; andere explizite Clients verwenden ihren angegebenen Capability-Satz.
|
||||||
- Capability-, Bootstrap- und Session-Zugangsdaten sind getrennte Werte mit begrenzter Lebensdauer. Carrier-Zugangsdaten sind geheim und dürfen nicht in Access-Logs erscheinen.
|
- Capability-, Bootstrap- und Session-Zugangsdaten sind getrennte Werte mit begrenzter Lebensdauer. Carrier-Zugangsdaten sind geheim und dürfen nicht in Access-Logs erscheinen.
|
||||||
@@ -316,9 +316,11 @@ Versuche laufen streng sequenziell. Akzeptierter `OPEN`- oder `DATA`-Fortschritt
|
|||||||
|
|
||||||
Nach dem Commit wiederholt ein HTTP-Fehler zunächst den exakten unveränderlichen Request mit dem aktuellen Bearer. Ein erfolgreicher Replay behält die aktuelle Sitzung. WebSocket-Verlust oder ein Foreground-, Online- oder natives Ereignis nach mindestens `reconnect_grace_secs` Scheduler-Lücke startet eine Recovery-Epoche. Die Bridge sendet genau einen GET an ihren ursprünglichen konfigurierten Basis-Root mit `bridge=<capability>`, `Accept: application/vnd.telemt.web-recovery+json` und optionaler aktueller Bearer-Authorization. Eine positive Antwort ist ein nicht cachebares JSON-Dokument mit höchstens 1024 Bytes, einem frischen Bootstrap und den aktuellen Limits, Timeouts sowie der Negotiation-Richtlinie. Telemt gibt diesen Bootstrap aus, bevor eine passende aktuelle Sitzung synchron beendet wird, sodass eine Neuerstellung auch bei Kapazität für nur eine Sitzung möglich bleibt. Unbekannte oder bereits beendete Bearer erhalten dieselbe positive Repräsentation; fehlerhafte Recovery-Header sowie deaktivierte Admission, Pause, Drain und Kapazitätsablehnung folgen dem bereinigten Decoy-Pfad.
|
Nach dem Commit wiederholt ein HTTP-Fehler zunächst den exakten unveränderlichen Request mit dem aktuellen Bearer. Ein erfolgreicher Replay behält die aktuelle Sitzung. WebSocket-Verlust oder ein Foreground-, Online- oder natives Ereignis nach mindestens `reconnect_grace_secs` Scheduler-Lücke startet eine Recovery-Epoche. Die Bridge sendet genau einen GET an ihren ursprünglichen konfigurierten Basis-Root mit `bridge=<capability>`, `Accept: application/vnd.telemt.web-recovery+json` und optionaler aktueller Bearer-Authorization. Eine positive Antwort ist ein nicht cachebares JSON-Dokument mit höchstens 1024 Bytes, einem frischen Bootstrap und den aktuellen Limits, Timeouts sowie der Negotiation-Richtlinie. Telemt gibt diesen Bootstrap aus, bevor eine passende aktuelle Sitzung synchron beendet wird, sodass eine Neuerstellung auch bei Kapazität für nur eine Sitzung möglich bleibt. Unbekannte oder bereits beendete Bearer erhalten dieselbe positive Repräsentation; fehlerhafte Recovery-Header sowie deaktivierte Admission, Pause, Drain und Kapazitätsablehnung folgen dem bereinigten Decoy-Pfad.
|
||||||
|
|
||||||
Die Recovery-Epoche besitzt eine gemeinsame absolute Wall-/Monotonic-Deadline `bridge_recovery_secs`, genau einen Request für das Recovery-Dokument und begrenzte Carrier-Wiederholungen mit Backoff von 250 ms bis 2 s. Während der Recovery wird der Status höchstens alle 2,5 Sekunden wiederholt. Eine frische Inkarnation bricht alte Requests, Sockets, Lanes und Queues ab und gibt sie frei, sendet für jeden noch aktiven nativen Stream genau ein synthetisches `CLOSE`, unterdrückt ein zweites `WELCOME` und committed erst nach echtem Carrier-Fortschritt. Beendete Stream-IDs bleiben in einer begrenzten Menge, damit gültige verspätete Frames nicht in einen neuen Stream gelangen; die native Seite muss eine neue Stream-ID vergeben. Häufige native Reconnect-Versuche sind zulässig, verlängern aber weder die Recovery-Epoche noch halten sie alten Inkarnationszustand. Das Zerstören der WebView zerstört auch diesen Recovery-Owner; ein nativer Supervisor muss danach ein neues Bridge-Dokument erzeugen.
|
Die Recovery-Epoche besitzt eine gemeinsame absolute Wall-/Monotonic-Deadline `bridge_recovery_secs`, genau einen Request für das Recovery-Dokument und begrenzte Carrier-Wiederholungen mit einer Backoff-Basis von 250 ms bis 2 s ohne Serverhinweis, unter Berücksichtigung von Serverhinweisen und der Jitter-Richtlinie der Seite. Während der Recovery wird der Status höchstens alle 2,5 Sekunden wiederholt. Eine frische Inkarnation bricht alte Requests, Sockets, Lanes und Queues ab und gibt sie frei, sendet für jeden noch aktiven nativen Stream genau ein synthetisches `CLOSE`, unterdrückt ein zweites `WELCOME` und committed erst nach echtem Carrier-Fortschritt. Beendete Stream-IDs bleiben in einer begrenzten Menge, damit gültige verspätete Frames nicht in einen neuen Stream gelangen; die native Seite muss eine neue Stream-ID vergeben. Häufige native Reconnect-Versuche sind zulässig, verlängern aber weder die Recovery-Epoche noch halten sie alten Inkarnationszustand. Das Zerstören der WebView zerstört auch diesen Recovery-Owner; ein nativer Supervisor muss danach ein neues Bridge-Dokument erzeugen.
|
||||||
|
|
||||||
Jede reguläre HTTP-Carrier-Operation der Bridge besitzt ein absolutes Budget `bridge_retry_secs` und höchstens neun Versuche. `bridge_request_secs` umfasst sowohl den Fetch-Response-Head als auch das vollständige Lesen des Response-Bodys; ein Downlink-Versuch erhält zusätzlich das konfigurierte Long-Poll-Intervall. Netzwerkfehler und Antworten mit `408`, `429`, `502`, `503` oder `504` verwenden begrenzten exponentiellen Backoff, während `Retry-After` das absolute Budget nicht verlängern kann. `carrier_probe_coalesce_ms = 0` sendet den ersten geordneten `OPEN`-Probe sofort. Ein Wert bis 10 ms kann passendes `DATA` aus diesem Fenster aufnehmen; multiplexierte Carrier bewahren die vollständige vorhergehende Frame-Reihenfolge, Lane-Carrier beanspruchen nur die ausgewählte Lane. Vor der Probe-Bestätigung startet kein HTTP-Downlink. Ein multiplexierter WebSocket-Upgrade kann unmittelbar nach seiner Auswahl durch `/session` beginnen und danach eingereihte Probe-Daten aufnehmen; ein Lane-WebSocket wartet auf die bekannte Stream-ID.
|
Überlastungsantworten von Telemt enthalten `Retry-After: 1` und `X-Telemt-Retry-After-Ms: 250`. Nur Status `503` mit diesem exakten Header-Paar legt in der generierten Bridge eine **Basispause von 250 ms** fest. Bei `web.retry_jitter.enabled = false` beträgt die Pause 250 ms; bei aktiviertem Jitter kommt der konfigurierte zufällige Zuschlag hinzu. Andere Antworten verwenden die unten beschriebene Standardbehandlung von `Retry-After` oder den Backoff ohne Serverhinweis. Frühere JavaScript-Bridge-Seiten ohne Unterstützung des Millisekundenhinweises verwenden bis zum Laden einer neuen Seite die Sekundenpause; ein Update der Telegram-App ist dafür nicht erforderlich. Versuchslimits, absolute Budgets, Abbruchverhalten und Zulassungsgrenzen bleiben unverändert.
|
||||||
|
|
||||||
|
Jede reguläre HTTP-Carrier-Operation der Bridge besitzt ein absolutes Budget `bridge_retry_secs` und höchstens neun Versuche. `bridge_request_secs` umfasst sowohl den Fetch-Response-Head als auch das vollständige Lesen des Response-Bodys; ein Downlink-Versuch erhält zusätzlich das konfigurierte Long-Poll-Intervall. Netzwerkfehler und Antworten mit `408`, `429`, `502`, `503` oder `504` verwenden einen positiven Serverhinweis oder exponentiellen Backoff mit der jeweiligen Jitter-Richtlinie; `Retry-After` kann das absolute Budget nicht verlängern. `carrier_probe_coalesce_ms = 0` sendet den ersten geordneten `OPEN`-Probe sofort. Ein Wert bis 10 ms kann passendes `DATA` aus diesem Fenster aufnehmen; multiplexierte Carrier bewahren die vollständige vorhergehende Frame-Reihenfolge, Lane-Carrier beanspruchen nur die ausgewählte Lane. Der HTTP-Downlink kann parallel zum ersten Upload starten; die native Zustellung wartet auf dessen erste gültige ACK/Commit-Bestätigung. Ein multiplexierter WebSocket-Upgrade kann unmittelbar nach seiner Auswahl durch `/session` beginnen und danach eingereihte Probe-Daten aufnehmen; ein Lane-WebSocket wartet auf die bekannte Stream-ID.
|
||||||
|
|
||||||
Response-Bodys werden innerhalb expliziter Endpunktgrenzen gestreamt: `/session` enthält exakt acht Bytes, ein erfolgreicher `/down` höchstens `carrier_batch_bytes`, und bodylose Antworten akzeptieren null Bytes. Deklarierter Überlauf wird vor dem Lesen abgelehnt; ein Überlauf beim Streaming oder zu viele Chunks bricht den Reader ab, und Bodys wiederholbarer Antworten werden vor dem Backoff verworfen. Die terminale Bridge-Bereinigung sendet höchstens ein authentifiziertes `DELETE`. Kanonische Transportfehler werden für Diagnosen nach `X-Carrier-Failure` kopiert, Navigation und explizites Schließen bleiben nicht lernende Gründe.
|
Response-Bodys werden innerhalb expliziter Endpunktgrenzen gestreamt: `/session` enthält exakt acht Bytes, ein erfolgreicher `/down` höchstens `carrier_batch_bytes`, und bodylose Antworten akzeptieren null Bytes. Deklarierter Überlauf wird vor dem Lesen abgelehnt; ein Überlauf beim Streaming oder zu viele Chunks bricht den Reader ab, und Bodys wiederholbarer Antworten werden vor dem Backoff verworfen. Die terminale Bridge-Bereinigung sendet höchstens ein authentifiziertes `DELETE`. Kanonische Transportfehler werden für Diagnosen nach `X-Carrier-Failure` kopiert, Navigation und explizites Schließen bleiben nicht lernende Gründe.
|
||||||
|
|
||||||
@@ -328,7 +330,7 @@ Ein festgeschriebener Versuch wird erst healthy, wenn transportspezifische bidir
|
|||||||
|
|
||||||
Das Lernen ist prozesslokal, speicherresident, ausschließlich positiv und durch `max_carrier_learning_entries` begrenzt. Es sortiert nur vom Client unterstützte konfigurierte Kandidaten, hält den konfigurierten Fallback stets zuletzt und bewahrt bei gleichen Scores die Konfigurationsreihenfolge. User-Agent- und Profilevidenz haben Primärgewicht; eine zulässige IP dient nur als Tie-Breaker. IP-Evidenz erfordert genau eine explizite, global routbare `X-Forwarded-For`-Adresse; private, Loopback-, Link-Local-, Carrier-Grade-NAT-, Dokumentations-, Multicast- und entsprechende IPv4-Mapped-Adressen sind ausgeschlossen. Vom Client gemeldete Fehlerkategorien und Request-Latenz sind ausschließlich diagnostisch und erzeugen weder negative noch Ranking-Evidenz. `conservative` erfordert 3 User-Agent-Ergebnisse oder 8 Profilergebnisse aus 4 Kohorten und deaktiviert IP-Evidenz; `balanced` verwendet 2, 6 aus 3 Kohorten und 3 zulässige IP-Ergebnisse; `aggressive` verwendet 1, 4 aus 2 Kohorten und 1 IP-Ergebnis. Ein Generationswechsel mit identischer Learning-Semantik bewahrt die Evidenz und veröffentlicht deren Generation-Fence atomar neu. Das Deaktivieren des Learnings oder eine Änderung von Aggressiveness, Evidenz-Lebensdauer oder Health-Fenster erhöht die Evidenz-Epoche und trennt inkompatiblen Zustand ab; veraltete Ergebnisse können ihn nicht erneut füllen.
|
Das Lernen ist prozesslokal, speicherresident, ausschließlich positiv und durch `max_carrier_learning_entries` begrenzt. Es sortiert nur vom Client unterstützte konfigurierte Kandidaten, hält den konfigurierten Fallback stets zuletzt und bewahrt bei gleichen Scores die Konfigurationsreihenfolge. User-Agent- und Profilevidenz haben Primärgewicht; eine zulässige IP dient nur als Tie-Breaker. IP-Evidenz erfordert genau eine explizite, global routbare `X-Forwarded-For`-Adresse; private, Loopback-, Link-Local-, Carrier-Grade-NAT-, Dokumentations-, Multicast- und entsprechende IPv4-Mapped-Adressen sind ausgeschlossen. Vom Client gemeldete Fehlerkategorien und Request-Latenz sind ausschließlich diagnostisch und erzeugen weder negative noch Ranking-Evidenz. `conservative` erfordert 3 User-Agent-Ergebnisse oder 8 Profilergebnisse aus 4 Kohorten und deaktiviert IP-Evidenz; `balanced` verwendet 2, 6 aus 3 Kohorten und 3 zulässige IP-Ergebnisse; `aggressive` verwendet 1, 4 aus 2 Kohorten und 1 IP-Ergebnis. Ein Generationswechsel mit identischer Learning-Semantik bewahrt die Evidenz und veröffentlicht deren Generation-Fence atomar neu. Das Deaktivieren des Learnings oder eine Änderung von Aggressiveness, Evidenz-Lebensdauer oder Health-Fenster erhöht die Evidenz-Epoche und trennt inkompatiblen Zustand ab; veraltete Ergebnisse können ihn nicht erneut füllen.
|
||||||
|
|
||||||
`https` bleibt der Default und behält das ursprüngliche serialisierte Verhalten bei. Bei `https-lanes` ist Lane null für Session-Steuerung reserviert, und jeder logische Stream ungleich null erhält eine eigene Lane. Jede Lane besitzt eigene Uplink-Sequenzen, Retry-Digests, Downlink-Cursor, nicht bestätigte Replay-Batches, Queues und einen Newest-Poll-Wins-Lebenszyklus. Ein langsamer Stream blockiert daher keinen anderen Stream auf der WEB-Protokollebene.
|
`https` bleibt der Default. Das Upload-Fenster wird zwischen 1 und 4 ausgehandelt; die generierte Bridge bietet `X-Telemt-Up-Window: 4` an, während Fenster 1 serielle Uploads beibehält. Bei `https-lanes` ist Lane null für Session-Steuerung reserviert, und jeder logische Stream ungleich null erhält eine eigene Lane. Jede Lane besitzt eigene Uplink-Sequenzen, Retry-Digests, Downlink-Cursor, nicht bestätigte Replay-Batches, Queues und einen Newest-Poll-Wins-Lebenszyklus. Ein langsamer Stream blockiert daher keinen anderen Stream auf der WEB-Protokollebene.
|
||||||
|
|
||||||
Damit entfällt die Serialisierung zwischen WEB-Streams auf Anwendungsebene. Öffentliches HTTP/2 läuft weiterhin über eine oder mehrere TCP-Verbindungen, sodass Paketverlust Head-of-Line-Blocking auf Transportebene verursachen kann; `https-lanes` ist kein HTTP/3- oder QUIC-Carrier.
|
Damit entfällt die Serialisierung zwischen WEB-Streams auf Anwendungsebene. Öffentliches HTTP/2 läuft weiterhin über eine oder mehrere TCP-Verbindungen, sodass Paketverlust Head-of-Line-Blocking auf Transportebene verursachen kann; `https-lanes` ist kein HTTP/3- oder QUIC-Carrier.
|
||||||
|
|
||||||
@@ -363,6 +365,30 @@ Statische Dateien werden beim Start und bei einem erfolgreichen Konfigurations-R
|
|||||||
|
|
||||||
Alle WEB-Schlüssel und Defaults sind in der [Konfigurationsreferenz](../Config_params/CONFIG_PARAMS.de.md#web) aufgeführt.
|
Alle WEB-Schlüssel und Defaults sind in der [Konfigurationsreferenz](../Config_params/CONFIG_PARAMS.de.md#web) aufgeführt.
|
||||||
|
|
||||||
|
### Konfigurierbarer Jitter für HTTP-Wiederholungen
|
||||||
|
|
||||||
|
`[web.retry_jitter]` ergänzt jeden bestehenden HTTP-Retry der Bridge um eine unabhängig gewählte Verzögerung: Netzwerkfehler und Antworten mit 408/429/502/503/504. Telegram-Anwendungen müssen nicht geändert werden. Ohne diesen Abschnitt oder mit `enabled = false` bleiben der 250-ms-Hinweis von Telemt und das bisherige Backoff/Jitter-Verhalten erhalten.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[web.retry_jitter]
|
||||||
|
enabled = true
|
||||||
|
min_ms = 0
|
||||||
|
max_ms = 250
|
||||||
|
distribution = "uniform"
|
||||||
|
# Only for distribution = "triangular":
|
||||||
|
# peak_ms = 125
|
||||||
|
```
|
||||||
|
|
||||||
|
Der Bereich beschreibt einen **Zuschlag**, nicht die gesamte Pause: Zusammen mit dem Telemt-Hinweis von 250 ms ergibt dieses Beispiel 250–500 ms. Ohne positiven Serverhinweis bleibt die Basis bei 250, 500, 1000, dann 2000 ms. Aktivierter Jitter ersetzt den bisherigen Jitter von bis zu 25%. Ein gültiger standardmäßiger `Retry-After` wird im aktivierten Modus nicht auf die bisherige Grenze von 30 Sekunden verkürzt. Übersteigt die Pause das verbleibende Operationsbudget, läuft das Budget ohne vorzeitigen Retry ab.
|
||||||
|
|
||||||
|
Standardwerte: `enabled = false`, `min_ms = 0`, `max_ms = 250`, `distribution = "uniform"`, ohne `peak_ms`. Es gilt `0 <= min_ms <= max_ms <= 30000`. `uniform` verteilt ganze Millisekunden gleichmäßig; `triangular` verwendet eine Dreiecksverteilung mit Rundung auf Millisekunden. Der optionale Gipfel liegt standardmäßig in der Mitte und muss innerhalb des Intervalls liegen. Ein expliziter Gipfel bei `uniform`, unbekannte Schlüssel/Verteilungen und ungültige Grenzen werden auch im deaktivierten Zustand abgelehnt. Gleiche Grenzen ergeben einen konstanten Zuschlag.
|
||||||
|
|
||||||
|
Die Richtlinie wird pro Bridge-Seite festgeschrieben. Konfigurations-/API-Reload wirkt auf neu geladene Seiten; bestehende Seiten behalten ihre Einstellungen bei Recovery. Recovery-JSON und HTTP-Kompatibilitätsheader bleiben unverändert. Die Auswahl bevorzugt `crypto.getRandomValues`, mit `Math.random` als Kompatibilitätsfallback. Erfolgreicher Datenverkehr wird nicht verzögert. Versuchslimits, absolute Budgets, Abbruch und unveränderte Payload-/Sequence-Wiederholung bleiben erhalten; längere Pausen können die Anzahl der Versuche innerhalb eines Startup-/Recovery-Budgets reduzieren.
|
||||||
|
|
||||||
|
Dies streut feste Retry-Intervalle, garantiert aber keinen Schutz vor DPI. Browser-Scheduling, Netzwerkwarteschlangen und andere Protokollzeiten bleiben beobachtbar. Bestehende Zeitleisten zeigen den deaktivierten Standardmodus. Bei aktiviertem Modus wird zu jeder Retry-Pause eine gezogene Verzögerung addiert, nicht zum ersten Verbindungsaufbau oder zu jedem Datenframe.
|
||||||
|
|
||||||
|
Die Richtlinie ändert nur bereits vorhandene Retry-Pausen. Strengere Limits einzelner Aufrufe bleiben erhalten: Reguläre `/down`-Polls und `/up`-Aufrufe nach dem Commit führen einen Versuch aus; ihr Recovery-Replay erlaubt zwei. Die Option erzeugt keine neuen Retry-Schleifen. Sie verlängert weder `web.timeouts.bridge_retry_secs` noch Start- oder Recovery-Deadlines.
|
||||||
|
|
||||||
## TLS-Terminierung mit NGINX
|
## TLS-Terminierung mit NGINX
|
||||||
|
|
||||||
```nginx
|
```nginx
|
||||||
@@ -510,9 +536,10 @@ Tragen Sie in `web_trusted_proxy_cidrs` die Adresse ein, von der aus Caddy Telem
|
|||||||
| Bestand der WEB-Listener, Bind-Adresse und Vertrauensrichtlinie | Prozesseigen; Telemt neu starten. |
|
| Bestand der WEB-Listener, Bind-Adresse und Vertrauensrichtlinie | Prozesseigen; Telemt neu starten. |
|
||||||
| `web.allow_wildcard_hosts` und jeder Wert in `[web.limits]` | Prozesseigener Speicher- und Ressourcenvertrag; Telemt neu starten. |
|
| `web.allow_wildcard_hosts` und jeder Wert in `[web.limits]` | Prozesseigener Speicher- und Ressourcenvertrag; Telemt neu starten. |
|
||||||
| `web.enabled`, Carrier-/Negotiation-Richtlinie, `web.debug`, Timeouts, vhosts, Profile und Decoys | Werden vom Config-Watcher oder durch einen Runtime-Generations-Reload angewendet. |
|
| `web.enabled`, Carrier-/Negotiation-Richtlinie, `web.debug`, Timeouts, vhosts, Profile und Decoys | Werden vom Config-Watcher oder durch einen Runtime-Generations-Reload angewendet. |
|
||||||
|
| `web.retry_jitter` | Reload gilt nur für neu erzeugte Bridge-Seiten. Geladene Seiten behalten ihre Richtlinie auch bei Recovery; Änderungen erfordern eine neue Seite. |
|
||||||
| Änderung des `base_path` eines vhost | Schaltet Routing neuer HTTP-Requests und Capability-Ableitung atomar um. Geben Sie den generierten Link neu aus. Bereits hochgestufte WebSockets und laufende geroutete Austauschvorgänge laufen weiter. Spätere Requests an die alte Basis mit einem prozessauthentischen Bootstrap- oder Session-Token erhalten ein lokales, nicht cachebares `404`; die nun inaktive alte Capability folgt der gewöhnlichen Decoy-Behandlung. Ein bestehender Session-Bearer bleibt nur an der neuen exakten Basis verwendbar, während ein für die alte Capability ausgegebener ungenutzter Bootstrap an der neuen Basis keine Sitzung erstellen kann. |
|
| Änderung des `base_path` eines vhost | Schaltet Routing neuer HTTP-Requests und Capability-Ableitung atomar um. Geben Sie den generierten Link neu aus. Bereits hochgestufte WebSockets und laufende geroutete Austauschvorgänge laufen weiter. Spätere Requests an die alte Basis mit einem prozessauthentischen Bootstrap- oder Session-Token erhalten ein lokales, nicht cachebares `404`; die nun inaktive alte Capability folgt der gewöhnlichen Decoy-Behandlung. Ein bestehender Session-Bearer bleibt nur an der neuen exakten Basis verwendbar, während ein für die alte Capability ausgegebener ungenutzter Bootstrap an der neuen Basis keine Sitzung erstellen kann. |
|
||||||
| Operator-Pause/-Drain-Zustand | Prozesseigen und flüchtig; übersteht einen Generations-Reload, schreibt niemals Konfiguration und wird nach einem Prozessneustart auf `running` zurückgesetzt. |
|
| Operator-Pause/-Drain-Zustand | Prozesseigen und flüchtig; übersteht einen Generations-Reload, schreibt niemals Konfiguration und wird nach einem Prozessneustart auf `running` zurückgesetzt. |
|
||||||
| Bestehende HTTP-Verbindungen und WEB-Sitzungen | Behalten HTTP-Idle-Grenze, Carrier-Kandidaten, Grenzen, Body-Timeout, Lebensdauer des Replay-Markers geschlossener Token sowie absolute Session-/Negotiation-Deadlines ihres Erstellungszeitpunkts; jede ausgegebene Bridge enthält ihre Request-, Retry-, Recovery- und Probe-Coalescing-Werte. Eine Recovery-Epoche fixiert ihr aktuelles Bridge-Budget; eine erfolgreiche Recovery-Repräsentation aktualisiert die Richtlinie für spätere Epochen und die frische Sitzung. WebSocket-Upgrade-, Open-, Write-, Backpressure- und Eviction-Vorgänge verwenden die unveränderlichen Deadlines der Parent-Sitzung. Neue Bridges verwenden die aktive Richtlinie, neue logische Streams die aktive Relay-Generation. |
|
| Bestehende HTTP-Verbindungen und WEB-Sitzungen | Behalten HTTP-Idle-Grenze, Carrier-Kandidaten, Grenzen, Body-Timeout, Lebensdauer des Replay-Markers geschlossener Token sowie absolute Session-/Negotiation-Deadlines ihres Erstellungszeitpunkts; jede ausgegebene Bridge enthält ihre Request-, Retry-, Recovery- und Probe-Coalescing-Werte. Eine Recovery-Epoche fixiert ihr aktuelles Bridge-Budget; eine erfolgreiche Recovery-Repräsentation aktualisiert die Richtlinie für spätere Epochen und die frische Sitzung. WebSocket-Upgrade-, Open-, Write-, Backpressure- und Eviction-Vorgänge verwenden die unveränderlichen Deadlines der Parent-Sitzung. Neue Bridges verwenden die aktive Richtlinie, neue logische Streams die aktive Relay-Generation. `web.retry_jitter` und die HTTP-Methode des Carriers bleiben an die Seite gebunden und werden durch Recovery nicht aktualisiert. |
|
||||||
| Beenden des Prozesses | Erfasst den zuletzt geladenen Wert von `web.timeouts.shutdown_secs` einmalig und verwendet dieselbe absolute Deadline für Listener-Acceptoren und Verbindungen sowie WEB-Sitzungen und Hilfstasks. Aufeinanderfolgende Komponenten erhalten keine separaten vollständigen Budgets. |
|
| Beenden des Prozesses | Erfasst den zuletzt geladenen Wert von `web.timeouts.shutdown_secs` einmalig und verwendet dieselbe absolute Deadline für Listener-Acceptoren und Verbindungen sowie WEB-Sitzungen und Hilfstasks. Aufeinanderfolgende Komponenten erhalten keine separaten vollständigen Budgets. |
|
||||||
|
|
||||||
Jeder logische Stream behält die Client-IP seiner Sitzung und besitzt während der gesamten Relay-Lebensdauer einen prozessweit eindeutigen, von null verschiedenen synthetischen Quellport. Damit bleibt für Direct- und Middle-End-KDF-Routing ein stabiles, kollisionsfreies Quell-/Ziel-Tupel erhalten.
|
Jeder logische Stream behält die Client-IP seiner Sitzung und besitzt während der gesamten Relay-Lebensdauer einen prozessweit eindeutigen, von null verschiedenen synthetischen Quellport. Damit bleibt für Direct- und Middle-End-KDF-Routing ein stabiles, kollisionsfreies Quell-/Ziel-Tupel erhalten.
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ Let `BASE` mean `/` for an empty `base_path`, or `/<base_path>/` otherwise. The
|
|||||||
|
|
||||||
- The public endpoint is `https://HOST:443/` when `base_path` is empty and `https://HOST:443/BASE/` otherwise. The base is case-sensitive and exact; Telemt does not redirect, normalize, or strip it before decoy forwarding.
|
- The public endpoint is `https://HOST:443/` when `base_path` is empty and `https://HOST:443/BASE/` otherwise. The base is case-sensitive and exact; Telemt does not redirect, normalize, or strip it before decoy forwarding.
|
||||||
- `plain` and `dd` 16-byte MTProxy secrets are supported. `ee` FakeTLS secrets are not supported by WEB mode.
|
- `plain` and `dd` 16-byte MTProxy secrets are supported. `ee` FakeTLS secrets are not supported by WEB mode.
|
||||||
- `web.carrier` selects the sole carrier when auto-negotiation is disabled and the final fallback when it is enabled. `https` uses serialized HTTPS uplink and long polling. `https-lanes` uses independent HTTPS sequencing and polling per logical stream. `websocket` uses one ordered WebSocket for all streams. `websocket-lanes` uses one independently owned WebSocket per non-zero logical stream.
|
- `web.carrier` selects the sole carrier when auto-negotiation is disabled and the final fallback when it is enabled. `https` uses a shared HTTPS uplink sequence and long polling. `https-lanes` uses independent HTTPS sequencing and polling per logical stream. `websocket` uses one ordered WebSocket for all streams. `websocket-lanes` uses one independently owned WebSocket per non-zero logical stream.
|
||||||
- Missing `web.carriers` or `web.carriers = false` disables auto-negotiation and learning. A non-empty array enables startup-only sequential negotiation; it never migrates an already committed session.
|
- Missing `web.carriers` or `web.carriers = false` disables auto-negotiation and learning. A non-empty array enables startup-only sequential negotiation; it never migrates an already committed session.
|
||||||
- Native clients without canonical carrier-negotiation headers use the configured fixed `carrier`, even when `carriers` enables negotiation for capable clients. Current Telegram iOS supports only `https`, so an operator serving metadata-free iOS clients must set `web.carrier = "https"`; it does not support `https-lanes`. User-Agent values, including CFNetwork or Darwin, never infer capabilities. When a native iOS request does send explicit negotiation metadata, Telemt intersects it with the server-authoritative `{https}` ceiling and rejects an empty result; other explicit clients use their advertised capability set.
|
- Native clients without canonical carrier-negotiation headers use the configured fixed `carrier`, even when `carriers` enables negotiation for capable clients. Current Telegram iOS supports only `https`, so an operator serving metadata-free iOS clients must set `web.carrier = "https"`; it does not support `https-lanes`. User-Agent values, including CFNetwork or Darwin, never infer capabilities. When a native iOS request does send explicit negotiation metadata, Telemt intersects it with the server-authoritative `{https}` ceiling and rejects an empty result; other explicit clients use their advertised capability set.
|
||||||
- Capability, bootstrap, and session credentials are separate bounded-lifetime values. Carrier credentials must be treated as secrets and must not appear in access logs.
|
- Capability, bootstrap, and session credentials are separate bounded-lifetime values. Carrier credentials must be treated as secrets and must not appear in access logs.
|
||||||
@@ -302,9 +302,11 @@ Attempts are strictly sequential. Accepted `OPEN` or `DATA` progress commits the
|
|||||||
|
|
||||||
After commit, an HTTP failure first replays the exact frozen request against the current bearer. A successful replay keeps the current session. WebSocket loss, or a foreground/online/native event after at least `reconnect_grace_secs` of scheduler gap, starts one recovery epoch. The bridge performs exactly one GET at its original configured base root with `bridge=<capability>`, `Accept: application/vnd.telemt.web-recovery+json`, and optional current bearer authorization. A positive response is an uncacheable JSON document of at most 1024 bytes containing a fresh bootstrap plus current limits, timeouts, and negotiation policy. Telemt issues that bootstrap before synchronously retiring a matching current session, so recreation remains possible with a one-session capacity. Unknown or already retired bearer authorization receives the same positive representation; malformed recovery headers, disabled admission, pause, drain, and capacity rejection follow the sanitized decoy path.
|
After commit, an HTTP failure first replays the exact frozen request against the current bearer. A successful replay keeps the current session. WebSocket loss, or a foreground/online/native event after at least `reconnect_grace_secs` of scheduler gap, starts one recovery epoch. The bridge performs exactly one GET at its original configured base root with `bridge=<capability>`, `Accept: application/vnd.telemt.web-recovery+json`, and optional current bearer authorization. A positive response is an uncacheable JSON document of at most 1024 bytes containing a fresh bootstrap plus current limits, timeouts, and negotiation policy. Telemt issues that bootstrap before synchronously retiring a matching current session, so recreation remains possible with a one-session capacity. Unknown or already retired bearer authorization receives the same positive representation; malformed recovery headers, disabled admission, pause, drain, and capacity rejection follow the sanitized decoy path.
|
||||||
|
|
||||||
The recovery epoch has one dual wall/monotonic absolute `bridge_recovery_secs` deadline, a single recovery-document request, and bounded carrier retries with 250 ms through 2 s backoff. Recovery status is repeated at most every 2.5 seconds while active. A fresh incarnation aborts and releases old requests, sockets, lanes, and queues, sends one synthetic `CLOSE` for each still-active native stream, suppresses a second `WELCOME`, and commits only after real carrier progress. Retired stream IDs are retained in a bounded set so valid late frames cannot enter a new stream; the native side must allocate a new stream ID. Frequent native reconnect attempts are valid, but they neither extend the recovery epoch nor retain old incarnation state. Destroying the WebView destroys this recovery owner; a native supervisor must then create a new bridge document.
|
The recovery epoch has one dual wall/monotonic absolute `bridge_recovery_secs` deadline, a single recovery-document request, and bounded carrier retries with a 250 ms through 2 s fallback base, subject to server hints and the page’s jitter policy. Recovery status is repeated at most every 2.5 seconds while active. A fresh incarnation aborts and releases old requests, sockets, lanes, and queues, sends one synthetic `CLOSE` for each still-active native stream, suppresses a second `WELCOME`, and commits only after real carrier progress. Retired stream IDs are retained in a bounded set so valid late frames cannot enter a new stream; the native side must allocate a new stream ID. Frequent native reconnect attempts are valid, but they neither extend the recovery epoch nor retain old incarnation state. Destroying the WebView destroys this recovery owner; a native supervisor must then create a new bridge document.
|
||||||
|
|
||||||
Each ordinary bridge carrier HTTP operation has an absolute `bridge_retry_secs` budget and at most nine attempts. `bridge_request_secs` covers both the Fetch response head and complete response body; a downlink attempt additionally receives the configured long-poll interval. Network failures and `408`, `429`, `502`, `503`, or `504` responses use bounded exponential backoff, while `Retry-After` cannot extend the absolute budget. `carrier_probe_coalesce_ms = 0` sends the first ordered `OPEN` probe immediately. A value up to 10 ms may include matching `DATA` that arrives in that window; multiplexed carriers preserve the complete preceding frame order, while lane carriers claim only the selected lane. No HTTP downlink starts before the probe acknowledgement. Multiplexed WebSocket Upgrade may begin as soon as `/session` selects it and then absorbs queued probe data; a lane WebSocket waits until its stream ID is known.
|
Telemt overload responses carry `Retry-After: 1` and `X-Telemt-Retry-After-Ms: 250`. Only status `503` with that exact header pair selects a **250 ms base delay** in the generated bridge. With `web.retry_jitter.enabled = false`, the pause is 250 ms; when enabled, the configured random addition applies. Other responses use the standard `Retry-After` handling or fallback backoff described below. Earlier JavaScript bridge pages without support for the millisecond hint use the one-second fallback until replaced by a newly loaded page; this does not require updating the Telegram application. Attempt limits, absolute budgets, cancellation and admission limits remain unchanged.
|
||||||
|
|
||||||
|
Each ordinary bridge carrier HTTP operation has an absolute `bridge_retry_secs` budget and at most nine attempts. `bridge_request_secs` covers both the Fetch response head and complete response body; a downlink attempt additionally receives the configured long-poll interval. Network failures and `408`, `429`, `502`, `503`, or `504` responses use a positive server hint or exponential fallback backoff, with the applicable jitter policy; `Retry-After` cannot extend the absolute budget. `carrier_probe_coalesce_ms = 0` sends the first ordered `OPEN` probe immediately. A value up to 10 ms may include matching `DATA` that arrives in that window; multiplexed carriers preserve the complete preceding frame order, while lane carriers claim only the selected lane. HTTP downlink can start alongside the first upload; native delivery waits for the first valid upload ACK/commit. Multiplexed WebSocket Upgrade may begin as soon as `/session` selects it and then absorbs queued probe data; a lane WebSocket waits until its stream ID is known.
|
||||||
|
|
||||||
Response bodies are streamed into explicit endpoint bounds: `/session` is exactly eight bytes, a successful `/down` is at most `carrier_batch_bytes`, and bodyless responses accept zero bytes. Declared overflow is rejected before reading, streamed overflow or excessive chunk count cancels the reader, and retryable response bodies are canceled before backoff. Terminal bridge cleanup sends at most one authenticated `DELETE`; canonical transport failures are copied to `X-Carrier-Failure` for diagnostics, while navigation and explicit close remain non-learning reasons.
|
Response bodies are streamed into explicit endpoint bounds: `/session` is exactly eight bytes, a successful `/down` is at most `carrier_batch_bytes`, and bodyless responses accept zero bytes. Declared overflow is rejected before reading, streamed overflow or excessive chunk count cancels the reader, and retryable response bodies are canceled before backoff. Terminal bridge cleanup sends at most one authenticated `DELETE`; canonical transport failures are copied to `X-Carrier-Failure` for diagnostics, while navigation and explicit close remain non-learning reasons.
|
||||||
|
|
||||||
@@ -314,7 +316,7 @@ A committed attempt becomes healthy only after transport-specific bidirectional
|
|||||||
|
|
||||||
Learning is process-local, in-memory, positive-only, and bounded by `max_carrier_learning_entries`. It ranks only client-supported configured candidates, keeps the configured fallback last, and uses configured order for equal scores. User-Agent and profile evidence have primary weight; an eligible IP is only a tie-breaker. IP evidence requires exactly one explicit, globally routable `X-Forwarded-For` address; private, loopback, link-local, carrier-grade NAT, documentation, multicast, and IPv4-mapped equivalents are excluded. Client-reported failure categories and request latency are diagnostics, not negative or ranking evidence. `conservative` requires 3 User-Agent outcomes or 8 profile outcomes across 4 cohorts and disables IP evidence; `balanced` uses 2, 6 across 3, and 3 eligible-IP outcomes; `aggressive` uses 1, 4 across 2, and 1 eligible-IP outcome. A generation change with identical learning semantics preserves evidence and atomically republishes its generation fence. Disabling learning or changing aggressiveness, evidence lifetime, or health window advances the evidence epoch and detaches incompatible state; stale outcomes cannot repopulate it.
|
Learning is process-local, in-memory, positive-only, and bounded by `max_carrier_learning_entries`. It ranks only client-supported configured candidates, keeps the configured fallback last, and uses configured order for equal scores. User-Agent and profile evidence have primary weight; an eligible IP is only a tie-breaker. IP evidence requires exactly one explicit, globally routable `X-Forwarded-For` address; private, loopback, link-local, carrier-grade NAT, documentation, multicast, and IPv4-mapped equivalents are excluded. Client-reported failure categories and request latency are diagnostics, not negative or ranking evidence. `conservative` requires 3 User-Agent outcomes or 8 profile outcomes across 4 cohorts and disables IP evidence; `balanced` uses 2, 6 across 3, and 3 eligible-IP outcomes; `aggressive` uses 1, 4 across 2, and 1 eligible-IP outcome. A generation change with identical learning semantics preserves evidence and atomically republishes its generation fence. Disabling learning or changing aggressiveness, evidence lifetime, or health window advances the evidence epoch and detaches incompatible state; stale outcomes cannot repopulate it.
|
||||||
|
|
||||||
`https` remains the default and preserves the original serialized behavior. `https-lanes` assigns lane zero to session control and one lane to every non-zero logical stream. Each lane has its own uplink sequence, retry digest, downlink cursor, unacknowledged replay batch, queue, and newest-poll-wins lifecycle. A slow stream therefore does not block another stream at the WEB protocol layer.
|
`https` remains the default. Its upload window is negotiated from 1 to 4; the generated bridge advertises `X-Telemt-Up-Window: 4`, while window 1 retains serialized uploads. `https-lanes` assigns lane zero to session control and one lane to every non-zero logical stream. Each lane has its own uplink sequence, retry digest, downlink cursor, unacknowledged replay batch, queue, and newest-poll-wins lifecycle. A slow stream therefore does not block another stream at the WEB protocol layer.
|
||||||
|
|
||||||
This removes application-level serialization between WEB streams. Public HTTP/2 still runs over one or more TCP connections, so packet loss can cause transport-level head-of-line blocking; `https-lanes` is not an HTTP/3 or QUIC carrier.
|
This removes application-level serialization between WEB streams. Public HTTP/2 still runs over one or more TCP connections, so packet loss can cause transport-level head-of-line blocking; `https-lanes` is not an HTTP/3 or QUIC carrier.
|
||||||
|
|
||||||
@@ -349,6 +351,30 @@ Static files are read at startup and successful configuration reload. Entry coun
|
|||||||
|
|
||||||
All WEB keys and defaults are listed in the [configuration reference](../Config_params/CONFIG_PARAMS.en.md#web).
|
All WEB keys and defaults are listed in the [configuration reference](../Config_params/CONFIG_PARAMS.en.md#web).
|
||||||
|
|
||||||
|
### Configurable HTTP retry jitter
|
||||||
|
|
||||||
|
`[web.retry_jitter]` adds an independently sampled delay to every existing bridge HTTP retry (network errors and 408/429/502/503/504). It requires no Telegram application changes. Without this section, or with `enabled = false`, the existing 250 ms Telemt hint and legacy backoff/jitter remain unchanged.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[web.retry_jitter]
|
||||||
|
enabled = true
|
||||||
|
min_ms = 0
|
||||||
|
max_ms = 250
|
||||||
|
distribution = "uniform"
|
||||||
|
# Only for distribution = "triangular":
|
||||||
|
# peak_ms = 125
|
||||||
|
```
|
||||||
|
|
||||||
|
The range describes an **addition**, not the total pause: the Telemt 250 ms hint plus this example gives 250–500 ms. Without a positive server hint, the base remains 250, 500, 1000, then 2000 ms. Enabled jitter replaces the legacy 25% jitter. A valid standard `Retry-After` is not shortened to the legacy 30-second cap in enabled mode. If the pause exceeds the remaining operation budget, the budget expires without an early retry.
|
||||||
|
|
||||||
|
Defaults are `enabled = false`, `min_ms = 0`, `max_ms = 250`, `distribution = "uniform"`, and no `peak_ms`. Require `0 <= min_ms <= max_ms <= 30000`. `uniform` samples integer milliseconds; `triangular` samples a triangular density and rounds to milliseconds. Its optional peak defaults to the midpoint and must be within the interval. An explicit peak with `uniform`, unknown keys/distributions and invalid ranges are rejected even when disabled. Equal bounds produce a constant addition.
|
||||||
|
|
||||||
|
The policy is frozen into each bridge page. Config/API reload affects newly loaded pages; existing pages retain it through recovery. Recovery JSON and HTTP compatibility headers remain unchanged. Sampling prefers `crypto.getRandomValues`, with `Math.random` as a compatibility fallback. Successful traffic is not delayed. Attempt limits, absolute budgets, cancellation and payload/sequence replay remain intact; longer pauses can exhaust a startup/recovery budget sooner in terms of completed attempts.
|
||||||
|
|
||||||
|
This reduces fixed retry timing, without guaranteeing resistance to DPI. Browser scheduling, network queues and other protocol timing remain observable. Existing timeline examples describe the default disabled mode. To evaluate enabled mode, add a sampled delay to each retry pause, not to the initial connection or every data frame.
|
||||||
|
|
||||||
|
The policy changes existing retry waits only. Stricter per-call limits still apply: ordinary `/down` polls and committed `/up` calls use one attempt; their recovery replay permits two. This option does not create new retry loops. It neither extends `web.timeouts.bridge_retry_secs` nor any startup/recovery deadline.
|
||||||
|
|
||||||
## NGINX TLS termination
|
## NGINX TLS termination
|
||||||
|
|
||||||
```nginx
|
```nginx
|
||||||
@@ -496,9 +522,10 @@ Set `web_trusted_proxy_cidrs` to the address Caddy uses to connect to Telemt, fo
|
|||||||
| WEB listener inventory, bind address, and trust policy | Process-owned; restart Telemt. |
|
| WEB listener inventory, bind address, and trust policy | Process-owned; restart Telemt. |
|
||||||
| `web.allow_wildcard_hosts` and any `[web.limits]` value | Process-owned memory/resource contract; restart Telemt. |
|
| `web.allow_wildcard_hosts` and any `[web.limits]` value | Process-owned memory/resource contract; restart Telemt. |
|
||||||
| `web.enabled`, carrier/negotiation policy, `web.debug`, timeouts, vhosts, profiles, and decoys | Applied by the config watcher or a runtime generation reload. |
|
| `web.enabled`, carrier/negotiation policy, `web.debug`, timeouts, vhosts, profiles, and decoys | Applied by the config watcher or a runtime generation reload. |
|
||||||
|
| `web.retry_jitter` | Reload applies to newly rendered bridge pages only. Existing pages retain their policy through recovery; load a new page to adopt changes. |
|
||||||
| A vhost `base_path` change | Atomically switches new HTTP routing and capability derivation. Reissue the generated link. Already upgraded WebSockets and in-flight routed exchanges continue. Later old-base requests carrying a process-authentic bootstrap or session token receive a local no-store `404`; the now-inactive old capability follows ordinary decoy handling. An existing session bearer remains usable only on the new exact base, while an unused bootstrap issued for the old capability cannot create a session on the new base. |
|
| A vhost `base_path` change | Atomically switches new HTTP routing and capability derivation. Reissue the generated link. Already upgraded WebSockets and in-flight routed exchanges continue. Later old-base requests carrying a process-authentic bootstrap or session token receive a local no-store `404`; the now-inactive old capability follows ordinary decoy handling. An existing session bearer remains usable only on the new exact base, while an unused bootstrap issued for the old capability cannot create a session on the new base. |
|
||||||
| Operator pause/drain state | Process-owned and ephemeral; survives generation reload, never writes config, and resets to `running` after process restart. |
|
| Operator pause/drain state | Process-owned and ephemeral; survives generation reload, never writes config, and resets to `running` after process restart. |
|
||||||
| Existing HTTP connections and WEB sessions | Keep their acquisition-time HTTP idle limit, carrier candidates, limits, body timeout, closed-token replay lifetime, and absolute session/negotiation deadlines; each issued bridge embeds its request, retry, recovery, and probe-coalescing values. A recovery epoch freezes its current bridge budget, while a successful recovery representation refreshes the policy used by later epochs and the fresh session. WebSocket upgrade, open, write, backpressure, and eviction operations use the parent session's frozen deadlines. Newly issued bridges use the active policy, while new logical streams use the active relay generation. |
|
| Existing HTTP connections and WEB sessions | Keep their acquisition-time HTTP idle limit, carrier candidates, limits, body timeout, closed-token replay lifetime, and absolute session/negotiation deadlines; each issued bridge embeds its request, retry, recovery, and probe-coalescing values. A recovery epoch freezes its current bridge budget, while a successful recovery representation refreshes the policy used by later epochs and the fresh session. WebSocket upgrade, open, write, backpressure, and eviction operations use the parent session's frozen deadlines. Newly issued bridges use the active policy, while new logical streams use the active relay generation. `web.retry_jitter` and the HTTP carrier method remain page-owned and are not refreshed by recovery. |
|
||||||
| Process shutdown | Captures the latest reloaded `web.timeouts.shutdown_secs` once and shares that single absolute deadline across listener acceptors and connections plus WEB sessions and auxiliary tasks. The waits do not receive sequential per-component budgets. |
|
| Process shutdown | Captures the latest reloaded `web.timeouts.shutdown_secs` once and shares that single absolute deadline across listener acceptors and connections plus WEB sessions and auxiliary tasks. The waits do not receive sequential per-component budgets. |
|
||||||
|
|
||||||
Each logical stream keeps its session's creation-time client IP and owns a process-unique, non-zero synthetic source port for the complete relay lifetime. This preserves one stable, non-colliding source/destination tuple for Direct and Middle-End KDF routing.
|
Each logical stream keeps its session's creation-time client IP and owns a process-unique, non-zero synthetic source port for the complete relay lifetime. This preserves one stable, non-colliding source/destination tuple for Direct and Middle-End KDF routing.
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ WEB-listener Telemt
|
|||||||
|
|
||||||
- При пустом `base_path` публичный endpoint имеет вид `https://HOST:443/`, иначе — `https://HOST:443/BASE/`. Base path регистрозависим и проверяется точно; Telemt не перенаправляет, не нормализует и не удаляет его перед отправкой в decoy.
|
- При пустом `base_path` публичный endpoint имеет вид `https://HOST:443/`, иначе — `https://HOST:443/BASE/`. Base path регистрозависим и проверяется точно; Telemt не перенаправляет, не нормализует и не удаляет его перед отправкой в decoy.
|
||||||
- Поддерживаются 16-байтовые MTProxy-секреты `plain` и `dd`. FakeTLS-секреты `ee` в WEB-режиме не поддерживаются.
|
- Поддерживаются 16-байтовые MTProxy-секреты `plain` и `dd`. FakeTLS-секреты `ee` в WEB-режиме не поддерживаются.
|
||||||
- `web.carrier` выбирает единственный carrier при выключенном auto-negotiation и последний fallback при включённом. `https` использует сериализованные HTTPS uplink и long polling. `https-lanes` использует независимые HTTPS sequencing и polling для каждого logical stream. `websocket` использует один упорядоченный WebSocket для всех streams. `websocket-lanes` использует отдельный WebSocket с независимым ownership для каждого ненулевого logical stream.
|
- `web.carrier` выбирает единственный carrier при выключенном auto-negotiation и последний fallback при включённом. `https` использует общую последовательность HTTPS uplink и long polling. `https-lanes` использует независимые HTTPS sequencing и polling для каждого logical stream. `websocket` использует один упорядоченный WebSocket для всех streams. `websocket-lanes` использует отдельный WebSocket с независимым ownership для каждого ненулевого logical stream.
|
||||||
- Отсутствующий `web.carriers` или `web.carriers = false` отключает auto-negotiation и обучение. Непустой массив включает только стартовый последовательный перебор; уже committed session никогда не мигрирует.
|
- Отсутствующий `web.carriers` или `web.carriers = false` отключает auto-negotiation и обучение. Непустой массив включает только стартовый последовательный перебор; уже committed session никогда не мигрирует.
|
||||||
- Нативные клиенты без канонических headers carrier negotiation используют настроенный фиксированный `carrier`, даже когда `carriers` включает negotiation для поддерживающих его клиентов. Текущий Telegram iOS поддерживает только `https`, поэтому для metadata-free iOS оператор должен задать `web.carrier = "https"`; `https-lanes` этим клиентом не поддерживается. User-Agent, включая CFNetwork или Darwin, никогда не выводит capabilities неявно. Если нативный iOS всё же отправляет явные negotiation metadata, Telemt пересекает их с server-authoritative ceiling `{https}` и отклоняет пустой результат; остальные явные клиенты используют заявленный capability set.
|
- Нативные клиенты без канонических headers carrier negotiation используют настроенный фиксированный `carrier`, даже когда `carriers` включает negotiation для поддерживающих его клиентов. Текущий Telegram iOS поддерживает только `https`, поэтому для metadata-free iOS оператор должен задать `web.carrier = "https"`; `https-lanes` этим клиентом не поддерживается. User-Agent, включая CFNetwork или Darwin, никогда не выводит capabilities неявно. Если нативный iOS всё же отправляет явные negotiation metadata, Telemt пересекает их с server-authoritative ceiling `{https}` и отклоняет пустой результат; остальные явные клиенты используют заявленный capability set.
|
||||||
- Capability, bootstrap и session credentials — отдельные значения с ограниченным сроком жизни. Carrier credentials считаются секретами и не должны попадать в access logs.
|
- Capability, bootstrap и session credentials — отдельные значения с ограниченным сроком жизни. Carrier credentials считаются секретами и не должны попадать в access logs.
|
||||||
@@ -309,9 +309,11 @@ Bridge отправляет additive status objects v1 с полями `state`,
|
|||||||
|
|
||||||
После commit при HTTP failure сначала точно повторяется замороженный request с текущим bearer. Успешный replay сохраняет текущую session. Потеря WebSocket либо событие foreground, online или native после scheduler gap не короче `reconnect_grace_secs` запускает одну recovery epoch. Bridge выполняет ровно один GET к исходному настроенному base root с `bridge=<capability>`, `Accept: application/vnd.telemt.web-recovery+json` и необязательной authorization текущим bearer. Положительный ответ — не кэшируемый JSON document размером не более 1024 байт со свежим bootstrap и текущими limits, timeouts и negotiation policy. Telemt выдаёт этот bootstrap до синхронного завершения совпавшей текущей session, поэтому пересоздание остаётся возможным при capacity в одну session. Неизвестный или уже retired bearer получает то же положительное representation; malformed recovery headers, выключенная admission, pause, drain и capacity rejection следуют по очищенному decoy path.
|
После commit при HTTP failure сначала точно повторяется замороженный request с текущим bearer. Успешный replay сохраняет текущую session. Потеря WebSocket либо событие foreground, online или native после scheduler gap не короче `reconnect_grace_secs` запускает одну recovery epoch. Bridge выполняет ровно один GET к исходному настроенному base root с `bridge=<capability>`, `Accept: application/vnd.telemt.web-recovery+json` и необязательной authorization текущим bearer. Положительный ответ — не кэшируемый JSON document размером не более 1024 байт со свежим bootstrap и текущими limits, timeouts и negotiation policy. Telemt выдаёт этот bootstrap до синхронного завершения совпавшей текущей session, поэтому пересоздание остаётся возможным при capacity в одну session. Неизвестный или уже retired bearer получает то же положительное representation; malformed recovery headers, выключенная admission, pause, drain и capacity rejection следуют по очищенному decoy path.
|
||||||
|
|
||||||
Recovery epoch имеет единый абсолютный wall/monotonic deadline `bridge_recovery_secs`, один request recovery document и bounded carrier retries с backoff от 250 мс до 2 с. Активный recovery status повторяется не чаще одного раза в 2,5 секунды. Новая incarnation прерывает и освобождает старые requests, sockets, lanes и queues, отправляет один synthetic `CLOSE` для каждого ещё активного native stream, подавляет второй `WELCOME` и выполняет commit только после реального carrier progress. Retired stream IDs сохраняются в bounded set, чтобы корректные поздние frames не попали в новый stream; native side должна выделить новый stream ID. Частые native reconnect attempts допустимы, но не продлевают recovery epoch и не удерживают старое состояние incarnation. Уничтожение WebView уничтожает этого recovery owner; после этого native supervisor должен создать новый bridge document.
|
Recovery epoch имеет единый абсолютный wall/monotonic deadline `bridge_recovery_secs`, один request recovery document и bounded carrier retries с резервной базовой паузой от 250 мс до 2 с с учётом подсказок сервера и политики jitter страницы. Активный recovery status повторяется не чаще одного раза в 2,5 секунды. Новая incarnation прерывает и освобождает старые requests, sockets, lanes и queues, отправляет один synthetic `CLOSE` для каждого ещё активного native stream, подавляет второй `WELCOME` и выполняет commit только после реального carrier progress. Retired stream IDs сохраняются в bounded set, чтобы корректные поздние frames не попали в новый stream; native side должна выделить новый stream ID. Частые native reconnect attempts допустимы, но не продлевают recovery epoch и не удерживают старое состояние incarnation. Уничтожение WebView уничтожает этого recovery owner; после этого native supervisor должен создать новый bridge document.
|
||||||
|
|
||||||
Каждая обычная carrier HTTP-операция bridge имеет абсолютный budget `bridge_retry_secs` и не более девяти attempts. `bridge_request_secs` охватывает Fetch response head и полное чтение response body; для downlink attempt дополнительно разрешён настроенный long-poll interval. Network failures и ответы `408`, `429`, `502`, `503` или `504` используют bounded exponential backoff, а `Retry-After` не может расширить абсолютный budget. При `carrier_probe_coalesce_ms = 0` первый упорядоченный probe с `OPEN` отправляется немедленно. Значение до 10 мс позволяет включить соответствующий `DATA`, пришедший в этом окне; multiplexed carriers сохраняют весь предшествующий порядок frames, а lane carriers забирают только выбранную lane. HTTP downlink не запускается до acknowledgement probe. Multiplexed WebSocket Upgrade может начаться сразу после его выбора ответом `/session` и затем включить queued probe data; lane WebSocket ждёт известного stream ID.
|
Ответы Telemt при перегрузке содержат `Retry-After: 1` и `X-Telemt-Retry-After-Ms: 250`. Только статус `503` с этой точной парой заголовков задаёт сгенерированному мосту **базовую паузу 250 мс**. При `web.retry_jitter.enabled = false` пауза равна 250 мс; при включении добавляется настроенная случайная задержка. Для остальных ответов действуют стандартная обработка `Retry-After` или резервный backoff, описанные ниже. Ранее загруженные страницы JavaScript-моста без поддержки миллисекундной подсказки используют секундную паузу до загрузки новой страницы; обновлять приложение Telegram для этого не нужно. Лимиты попыток, абсолютные бюджеты, отмена и ограничения admission не меняются.
|
||||||
|
|
||||||
|
Каждая обычная carrier HTTP-операция bridge имеет абсолютный budget `bridge_retry_secs` и не более девяти attempts. `bridge_request_secs` охватывает Fetch response head и полное чтение response body; для downlink attempt дополнительно разрешён настроенный long-poll interval. Network failures и ответы `408`, `429`, `502`, `503` или `504` используют положительную подсказку сервера или экспоненциальный backoff с действующей политикой jitter; `Retry-After` не может расширить абсолютный budget. При `carrier_probe_coalesce_ms = 0` первый упорядоченный probe с `OPEN` отправляется немедленно. Значение до 10 мс позволяет включить соответствующий `DATA`, пришедший в этом окне; multiplexed carriers сохраняют весь предшествующий порядок frames, а lane carriers забирают только выбранную lane. HTTP downlink может запускаться одновременно с первым upload; доставка в native-клиент ждёт первого корректного ACK/commit upload. Multiplexed WebSocket Upgrade может начаться сразу после его выбора ответом `/session` и затем включить queued probe data; lane WebSocket ждёт известного stream ID.
|
||||||
|
|
||||||
Response bodies читаются потоково с явными bounds endpoint: `/session` содержит ровно восемь байт, успешный `/down` — не более `carrier_batch_bytes`, а bodyless responses допускают ноль байт. Заявленный overflow отклоняется до чтения; overflow при streaming или избыточное число chunks отменяет reader, а bodies retryable responses отменяются до backoff. Финальный cleanup bridge отправляет не более одного аутентифицированного `DELETE`; канонические transport failures копируются в `X-Carrier-Failure` для диагностики, а navigation и explicit close остаются non-learning reasons.
|
Response bodies читаются потоково с явными bounds endpoint: `/session` содержит ровно восемь байт, успешный `/down` — не более `carrier_batch_bytes`, а bodyless responses допускают ноль байт. Заявленный overflow отклоняется до чтения; overflow при streaming или избыточное число chunks отменяет reader, а bodies retryable responses отменяются до backoff. Финальный cleanup bridge отправляет не более одного аутентифицированного `DELETE`; канонические transport failures копируются в `X-Carrier-Failure` для диагностики, а navigation и explicit close остаются non-learning reasons.
|
||||||
|
|
||||||
@@ -321,7 +323,7 @@ Committed attempt становится healthy, только когда transpor
|
|||||||
|
|
||||||
Обучение process-local, in-memory, positive-only и ограничено `max_carrier_learning_entries`. Оно ранжирует только поддерживаемые клиентом настроенные candidates, всегда оставляет fallback последним и сохраняет настроенный порядок при равных scores. Evidence User-Agent и профиля имеет основной вес; допустимый IP служит только tie-breaker. Для IP evidence требуется ровно один явный глобально маршрутизируемый `X-Forwarded-For`; private, loopback, link-local, carrier-grade NAT, documentation, multicast и их IPv4-mapped эквиваленты исключаются. Категории ошибок от клиента и request latency используются только для диагностики и не создают отрицательный или ranking evidence. `conservative` требует 3 outcomes User-Agent или 8 outcomes профиля в 4 cohorts и отключает IP evidence; `balanced` использует соответственно 2, 6 в 3 cohorts и 3 outcomes допустимого IP; `aggressive` — 1, 4 в 2 cohorts и 1 outcome IP. Смена generation при неизменной learning semantics сохраняет evidence и атомарно перепубликует его generation fence. Выключение обучения или изменение aggressiveness, lifetime evidence либо health window увеличивает evidence epoch и отсоединяет несовместимое состояние; stale outcomes не могут заполнить его снова.
|
Обучение process-local, in-memory, positive-only и ограничено `max_carrier_learning_entries`. Оно ранжирует только поддерживаемые клиентом настроенные candidates, всегда оставляет fallback последним и сохраняет настроенный порядок при равных scores. Evidence User-Agent и профиля имеет основной вес; допустимый IP служит только tie-breaker. Для IP evidence требуется ровно один явный глобально маршрутизируемый `X-Forwarded-For`; private, loopback, link-local, carrier-grade NAT, documentation, multicast и их IPv4-mapped эквиваленты исключаются. Категории ошибок от клиента и request latency используются только для диагностики и не создают отрицательный или ranking evidence. `conservative` требует 3 outcomes User-Agent или 8 outcomes профиля в 4 cohorts и отключает IP evidence; `balanced` использует соответственно 2, 6 в 3 cohorts и 3 outcomes допустимого IP; `aggressive` — 1, 4 в 2 cohorts и 1 outcome IP. Смена generation при неизменной learning semantics сохраняет evidence и атомарно перепубликует его generation fence. Выключение обучения или изменение aggressiveness, lifetime evidence либо health window увеличивает evidence epoch и отсоединяет несовместимое состояние; stale outcomes не могут заполнить его снова.
|
||||||
|
|
||||||
`https` остаётся default и сохраняет исходное сериализованное поведение. В `https-lanes` lane zero отведена под session control, а каждому ненулевому logical stream соответствует своя lane. У каждой lane собственные uplink sequence, retry digest, downlink cursor, unacknowledged replay batch, очередь и lifecycle newest-poll-wins. Поэтому медленный stream не блокирует другой stream на уровне WEB-протокола.
|
`https` остаётся default. Окно upload согласуется в диапазоне от 1 до 4; сгенерированный мост предлагает `X-Telemt-Up-Window: 4`, а окно 1 сохраняет последовательную отправку. В `https-lanes` lane zero отведена под session control, а каждому ненулевому logical stream соответствует своя lane. У каждой lane собственные uplink sequence, retry digest, downlink cursor, unacknowledged replay batch, очередь и lifecycle newest-poll-wins. Поэтому медленный stream не блокирует другой stream на уровне WEB-протокола.
|
||||||
|
|
||||||
Это устраняет сериализацию между WEB-streams на уровне приложения. Публичный HTTP/2 всё ещё работает поверх одного или нескольких TCP-connections, поэтому потеря пакетов может вызвать transport-level head-of-line blocking; `https-lanes` не является HTTP/3- или QUIC-carrier.
|
Это устраняет сериализацию между WEB-streams на уровне приложения. Публичный HTTP/2 всё ещё работает поверх одного или нескольких TCP-connections, поэтому потеря пакетов может вызвать transport-level head-of-line blocking; `https-lanes` не является HTTP/3- или QUIC-carrier.
|
||||||
|
|
||||||
@@ -356,6 +358,30 @@ index = "index.html"
|
|||||||
|
|
||||||
Все WEB-ключи и defaults перечислены в [справочнике конфигурации](../Config_params/CONFIG_PARAMS.ru.md#web).
|
Все WEB-ключи и defaults перечислены в [справочнике конфигурации](../Config_params/CONFIG_PARAMS.ru.md#web).
|
||||||
|
|
||||||
|
### Настраиваемый jitter HTTP-повторов
|
||||||
|
|
||||||
|
`[web.retry_jitter]` добавляет независимо выбранную задержку к каждому существующему HTTP-повтору бриджа: сетевым ошибкам и ответам 408/429/502/503/504. Менять приложения Telegram не требуется. Без секции или при `enabled = false` сохраняются подсказка Telemt на 250 мс и прежний backoff/jitter.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[web.retry_jitter]
|
||||||
|
enabled = true
|
||||||
|
min_ms = 0
|
||||||
|
max_ms = 250
|
||||||
|
distribution = "uniform"
|
||||||
|
# Only for distribution = "triangular":
|
||||||
|
# peak_ms = 125
|
||||||
|
```
|
||||||
|
|
||||||
|
Диапазон задаёт **добавку**, а не полную паузу: подсказка Telemt 250 мс с этим примером даёт 250–500 мс. Без положительной серверной подсказки база остаётся 250, 500, 1000, затем 2000 мс. Включённый jitter заменяет прежний jitter до 25%. Корректный стандартный `Retry-After` во включённом режиме не сокращается прежним пределом в 30 секунд. Если пауза не помещается в оставшийся бюджет операции, бюджет истекает без раннего повтора.
|
||||||
|
|
||||||
|
Значения по умолчанию: `enabled = false`, `min_ms = 0`, `max_ms = 250`, `distribution = "uniform"`, `peak_ms` отсутствует. Требуется `0 <= min_ms <= max_ms <= 30000`. `uniform` выбирает целые миллисекунды равномерно; `triangular` использует треугольную плотность с округлением до миллисекунд. Необязательный пик по умолчанию находится посередине и должен входить в диапазон. Явный пик для `uniform`, неизвестные ключи/распределения и неверные границы отклоняются даже при выключенной опции. Одинаковые границы дают постоянную добавку.
|
||||||
|
|
||||||
|
Политика фиксируется в каждой странице бриджа. Reload через конфиг/API влияет на новые страницы; активные сохраняют настройки при recovery. Recovery JSON и HTTP-заголовки совместимости не меняются. Используется `crypto.getRandomValues`, при недоступности — `Math.random` для совместимости. Успешный трафик не задерживается. Лимиты попыток, общий бюджет, отмена и повтор неизменных payload/sequence сохраняются; более длинные паузы могут уменьшить число попыток, помещающихся в startup/recovery-бюджет.
|
||||||
|
|
||||||
|
Это размывает фиксированные интервалы повторов, но не гарантирует защиту от DPI. Планирование браузера, сетевые очереди и другие временные характеристики протокола остаются наблюдаемыми. Существующие примеры временной шкалы описывают выключенную опцию. Для включённого режима добавляйте выбранную задержку к каждой паузе повтора, а не к первому соединению или каждому кадру данных.
|
||||||
|
|
||||||
|
Политика меняет только уже предусмотренные паузы перед повтором. Более строгие ограничения отдельных вызовов сохраняются: обычный poll `/down` и вызов `/up` после commit выполняют одну попытку; их replay при восстановлении допускает две. Опция не создаёт новых циклов повторов. Она не продлевает `web.timeouts.bridge_retry_secs` и сроки запуска или восстановления.
|
||||||
|
|
||||||
## Терминация TLS на NGINX
|
## Терминация TLS на NGINX
|
||||||
|
|
||||||
```nginx
|
```nginx
|
||||||
@@ -503,9 +529,10 @@ log {
|
|||||||
| Состав WEB-listeners, bind address и trust policy | Принадлежат процессу; перезапустите Telemt. |
|
| Состав WEB-listeners, bind address и trust policy | Принадлежат процессу; перезапустите Telemt. |
|
||||||
| `web.allow_wildcard_hosts` и любое значение `[web.limits]` | Process-owned контракт памяти и ресурсов; перезапустите Telemt. |
|
| `web.allow_wildcard_hosts` и любое значение `[web.limits]` | Process-owned контракт памяти и ресурсов; перезапустите Telemt. |
|
||||||
| `web.enabled`, policy carrier/negotiation, `web.debug`, timeouts, vhosts, profiles и decoys | Применяются config watcher или runtime generation reload. |
|
| `web.enabled`, policy carrier/negotiation, `web.debug`, timeouts, vhosts, profiles и decoys | Применяются config watcher или runtime generation reload. |
|
||||||
|
| `web.retry_jitter` | Reload действует только для новых страниц моста. Уже загруженные страницы сохраняют политику при recovery; для применения изменений нужна новая страница. |
|
||||||
| Изменение `base_path` vhost | Атомарно переключает маршрутизацию новых HTTP-запросов и derivation capability. Выпустите новую сгенерированную ссылку. Уже upgraded WebSockets и начатые маршрутизированные обмены продолжаются. Последующие запросы к старому base с подлинным для процесса bootstrap- или session-token получают локальный no-store `404`, а ставшая неактивной прежняя capability обрабатывается как обычный decoy traffic. Существующий session bearer остаётся пригодным только на новом точном base, а неиспользованный bootstrap, выданный для старой capability, не может создать session на новом base. |
|
| Изменение `base_path` vhost | Атомарно переключает маршрутизацию новых HTTP-запросов и derivation capability. Выпустите новую сгенерированную ссылку. Уже upgraded WebSockets и начатые маршрутизированные обмены продолжаются. Последующие запросы к старому base с подлинным для процесса bootstrap- или session-token получают локальный no-store `404`, а ставшая неактивной прежняя capability обрабатывается как обычный decoy traffic. Существующий session bearer остаётся пригодным только на новом точном base, а неиспользованный bootstrap, выданный для старой capability, не может создать session на новом base. |
|
||||||
| Operator pause/drain state | Process-owned и ephemeral; переживает generation reload, никогда не записывает конфигурацию и после перезапуска процесса возвращается в `running`. |
|
| Operator pause/drain state | Process-owned и ephemeral; переживает generation reload, никогда не записывает конфигурацию и после перезапуска процесса возвращается в `running`. |
|
||||||
| Существующие HTTP connections и WEB sessions | Сохраняют HTTP idle limit, carrier candidates, лимиты, body timeout, lifetime replay-marker закрытого token и абсолютные session/negotiation deadlines своего момента создания; каждый выданный bridge содержит собственные request, retry, recovery и probe-coalescing значения. Recovery epoch фиксирует текущий bridge budget, а успешное recovery representation обновляет policy для последующих epochs и новой session. WebSocket Upgrade, open, write, backpressure и eviction operations используют замороженные deadlines parent session. Новые bridges получают активную policy, а новые logical streams используют активное relay generation. |
|
| Существующие HTTP connections и WEB sessions | Сохраняют HTTP idle limit, carrier candidates, лимиты, body timeout, lifetime replay-marker закрытого token и абсолютные session/negotiation deadlines своего момента создания; каждый выданный bridge содержит собственные request, retry, recovery и probe-coalescing значения. Recovery epoch фиксирует текущий bridge budget, а успешное recovery representation обновляет policy для последующих epochs и новой session. WebSocket Upgrade, open, write, backpressure и eviction operations используют замороженные deadlines parent session. Новые bridges получают активную policy, а новые logical streams используют активное relay generation. `web.retry_jitter` и HTTP-метод carrier остаются свойствами страницы и не обновляются при recovery. |
|
||||||
| Завершение процесса | Один раз фиксирует последнее применённое значение `web.timeouts.shutdown_secs` и использует единый абсолютный deadline для listener acceptors и connections, WEB sessions и auxiliary tasks. Последовательные компоненты не получают отдельные полные бюджеты. |
|
| Завершение процесса | Один раз фиксирует последнее применённое значение `web.timeouts.shutdown_secs` и использует единый абсолютный deadline для listener acceptors и connections, WEB sessions и auxiliary tasks. Последовательные компоненты не получают отдельные полные бюджеты. |
|
||||||
|
|
||||||
Каждый logical stream сохраняет client IP своей сессии и владеет уникальным в пределах процесса ненулевым synthetic source port до завершения relay. Это сохраняет один стабильный непересекающийся source/destination tuple для Direct и Middle-End KDF routing.
|
Каждый logical stream сохраняет client IP своей сессии и владеет уникальным в пределах процесса ненулевым synthetic source port до завершения relay. Это сохраняет один стабильный непересекающийся source/destination tuple для Direct и Middle-End KDF routing.
|
||||||
|
|||||||
Reference in New Issue
Block a user