1.0.12

Fixed (#309)

  • Асинхронная MCP-инициализация при старте (#309, follow-up #308): начальный connectAll выполнялся синхронно внутри mcp.Manager.Start до открытия порта HTTP-сервером — N недоступных сетевых эндпоинтов давали N×30с задержки старта (наблюдалось ~60с на chat.a2v.space с двумя мёртвыми z.ai-эндпоинтами). Теперь Start переносит connectAll в фоновую горутину и возвращается немедленно: порт 14888 открывается за секунды независимо от состояния MCP-серверов, упавшие сессии помечаются status=error в фоне и догоняются health-loop’ом (тик 60с) и ленивым on-demand GetSession. Сопутствующая защита от новых гонок асинхронности: флаг stopped (под мьютексом) не позволяет init-горутине сохранить сессию в очищенный Stop’ом map (утечка, для stdio — осиротевший subprocess); при гонке init vs параллельный GetSession живая сессия сохраняется, дубликат закрывается; Stop ждёт init-горутину bounded-grace 2с (после cancel попытка падает быстро) и закрывает сессии вне мьютекса; GetSession отказывает в подключении после Stop (раньше мог заспавнить stdio-процесс, чьё время жизни намеренно отвязано от ctx — #336); recover в init-горутине — осознанный trade-off доступность > fail-fast (паника больше не валит работающий сервер, алерт — по строке «serving continues with MCP degraded»); подавлены ложные ERROR/WARN в логах при чистом shutdown (cancelled-ctx не логируется как «initial connect failed»/«retries exhausted»); закрытие duplicate-сессий вынесено из-под лока (Close — блокирующий I/O). Тесты: Start возвращается немедленно при дефолтных 30с-таймаутах и мёртвом эндпоинте (до фикса блокировал бы ~30с); мёртвый эндпоинт маркируется error в фоне и не регистрируется сессией; гонка Start vs GetSession сходится к одной живой сессии без подмены; Stop во время init не оставляет сессий и не блокируется. ocr review — 10 итераций, финальный прогон 0 замечаний.