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-demandGetSession. Сопутствующая защита от новых гонок асинхронности: флаг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в фоне и не регистрируется сессией; гонкаStartvsGetSessionсходится к одной живой сессии без подмены; Stop во время init не оставляет сессий и не блокируется. ocr review — 10 итераций, финальный прогон 0 замечаний.