refactor: improve networking layer with enhanced engine, muxer, and diagnostics
- Refactored connection engine with better state management - Improved muxer with enhanced protocol handling - Updated connection bridge and diagnostics - Added new network constants and configuration options - Enhanced session tracking and error handling - Updated dependencies in Cargo.toml
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
# Стабилизация Netrunner: устранение «эффекта домино»
|
||||
|
||||
Краткая выжимка по правкам. Подробности — в коде (комментарии на местах).
|
||||
|
||||
## 1. Почему падал один leg и закрывались все стримы
|
||||
|
||||
Цепочка до правок:
|
||||
|
||||
1. `engine.rs::handle_outbound` имел **жёсткий** таймаут записи `20s`. При RTT > 2.5 с
|
||||
физический сокет не успевал «слить» данные → таймаут → `TunnelWriteStuck` →
|
||||
writer-задача возвращает `Err` → весь `TunnelEngine::run()` выходит с `Err`,
|
||||
leg целиком умирает.
|
||||
2. `muxer.rs::send_to_network` (ветка данных): при первой же неудаче
|
||||
`data_tx.send()` (канал мёртвого leg закрыт) — сразу `upload_failed`,
|
||||
`remove_leg`, и **возврат `Err`**.
|
||||
3. `bridge.rs::run_tcp_bridge` (upload): на `Err` от `send_data_safe` делал
|
||||
`break` → `token.cancel()` → закрывался **весь мост, т.е. стрим**.
|
||||
|
||||
Так как `select_leg` использует sticky-привязки, на упавшем leg висели десятки
|
||||
стримов. Они все одновременно упирались в закрытый канал и **разом** убивали свои
|
||||
мосты — это и есть домино (`upload_failed` для 81, 79, 107 …).
|
||||
|
||||
## 2. Что изменено
|
||||
|
||||
### A. Адаптивный таймаут записи (вместо жёстких 20 с)
|
||||
`muxer.rs::adaptive_write_timeout(floor)` — масштабирует таймаут как `~8 × RTT`,
|
||||
с полом `floor` и потолком `60 с`. Применён:
|
||||
- `engine.rs::handle_outbound` (запись в туннель), пол = 20 с;
|
||||
- `bridge.rs` download (запись в локальный сокет), пол = `BRIDGE_STREAM_WRITE_TIMEOUT`.
|
||||
|
||||
Эффект: «медленный, но живой» leg при высоком RTT больше не убивается по таймауту.
|
||||
|
||||
### B. Failover вместо смерти стрима (`muxer.rs::send_to_network`)
|
||||
Ветка данных теперь цикл:
|
||||
- неудача `data_tx.send()` → `message` восстанавливается из `SendError`,
|
||||
мёртвый leg эвиктится (`remove_leg`), стрим переселяется на следующий
|
||||
лучший leg и **повторяет отправку**;
|
||||
- `Err` возвращается **только если живых leg не осталось вовсе**.
|
||||
|
||||
Цикл конечен: `remove_leg` убирает leg из кэша, `select_leg` не вернёт его снова.
|
||||
|
||||
### C. Очистка привязок при эвикте (`muxer.rs::clear_bindings_for_leg`)
|
||||
`remove_leg` / `force_remove_leg` теперь сбрасывают `stream_bindings` упавшего
|
||||
leg → остальные стримы при следующей отправке честно ребалансируются, а не
|
||||
долбятся в мёртвый leg.
|
||||
|
||||
### D. Graceful pause / buffer (`bridge.rs::run_tcp_bridge`, upload)
|
||||
Если `send_data_safe` всё-таки вернул `Err` (все leg одновременно лежат), мост
|
||||
**не закрывается**. Текущий чанк удерживается, идёт ретрай раз в
|
||||
`STREAM_PAUSE_RETRY` (250 мс) в пределах `STREAM_PAUSE_BUDGET` (30 с). Пока мы не
|
||||
читаем дальше — работает TCP backpressure, источник сам приостанавливается, данные
|
||||
не теряются. Стрим закрывается только если за бюджет ни один leg не поднялся или
|
||||
пришёл `token.cancel()`.
|
||||
|
||||
## 3. Новые константы (`constants.rs`)
|
||||
- `STREAM_PAUSE_BUDGET = 30s` — сколько стрим ждёт восстановления leg.
|
||||
- `STREAM_PAUSE_RETRY = 250ms` — период опроса во время паузы.
|
||||
|
||||
## 4. Итог
|
||||
Сбой одного leg теперь = бесшовный перенос стримов на соседние leg; полный отказ
|
||||
всех leg = короткая пауза с буфером, а не каскадный сброс. `leg_reconnecting`
|
||||
перестаёт быть «лавиной».
|
||||
|
||||
## 5. Проверка
|
||||
Сборку из-под агента запустить не удалось (апстрим-фильтр харнесса блокирует
|
||||
вызов cargo). Запустите вручную:
|
||||
|
||||
```
|
||||
cargo check -p netrunner-core
|
||||
cargo test -p netrunner-core
|
||||
```
|
||||
Reference in New Issue
Block a user