tgoop.com/bminaiev_blog/38
Create:
Last Update:
Last Update:
AndThen
Хотел в честь 300 подписчиков на этом канале запустить прикольную штуку, но кодить я ее начал, когда подписчиков было уже 298, так что естественно я не успел. Поэтому расскажу пока историю одного бага, который я очень долго пытался поймать.
У нас есть сервис на Rust, который слушает какой-то порт, принимает там соединения, проверяет TLS и дальше как-то общается с каждым клиентом. Код, который это делает, выглядит примерно вот так:
let incoming = tokio_stream::wrappers::TcpListenerStream::new(В основном он работал хорошо. Но иногда, через несколько часов после запуска сервиса, он переставал принимать новые соединения.
tokio::net::TcpListener::bind(address).await?
);
let incoming = incoming.and_then(|stream| tls_acceptor.accept(stream));
…
let server = hyper::Server::builder(incoming)...;
Как такое дебажить не очень понятно. Можно добавлять какие-то логи, запускать много инстансов системы, а потом ждать несколько часов.
Кстати, вы умеете просто добавлять логи внутрь внешних библиотек? Я научился это делать, но может быть можно проще.
• Вначале запускаем
cargo tree
и смотрим какой версии библиотека используется. Скорее всего это будет не та же версия, которая написана в Cargo.toml
из-за других зависимостей.• Скачиваем локально исходный код библиотеки, делаем
git checkout
на нужную версию, добавляем логи.• Дописываем библиотеку в
Cargo.toml
через [patch.crates-io]
.После недели дебага я таки понял, в чем была проблема.
incoming.and_then
гарантирует, что порядок, в котором подключились пользователи, и порядок, в котором они придут в hyper::Server::builder
, будет один и тот же. А это значит, что если tls_acceptor.accept
для какого-то соединения будет работать долго, то все следующие соединения будут его ждать. Например, если пользователь разорвет соединение во время TLS-handshake, то tls_acceptor.accept
никогда не завершится, и новые соединения не будут приниматься.BY Боря программирует
Share with your friend now:
tgoop.com/bminaiev_blog/38