Для AI-агентов: markdown этой страницы — /docs-content/infra/galaxy-sleep.md индекс документации — /llms.txt
Сон и пробуждение Galaxy-приложения
Galaxy-приложение засыпает по простою вместе с галактикой-носителем, и на время сна его контейнер остановлен. Эта страница описывает, что именно останавливается, какие поля показывают настоящее состояние, чем приложение поднять и сколько это занимает.
Что останавливается · Поля состояния · Чем поднять · Логи · Окно по расписанию
Что останавливается во сне
Приложение живёт в контейнере на общем хосте — галактике. Спать могут обе части, и это разные состояния.
| Что спит | Как это выглядит | Что нужно, чтобы поднять |
|---|---|---|
| Контейнер приложения, галактика работает | Приложение не отвечает, соседние приложения той же галактики работают | Запуск контейнера — секунды |
| Галактика вместе со всеми контейнерами | Не отвечает ни одно приложение этой галактики | Загрузка машины галактики, затем запуск контейнера — минуты |
Постоянный том /data сон переживает. Пробуждение запускает тот же контейнер, а не создаёт новый, поэтому строки, которые приложение записало в свой поток вывода до сна, доступны и после пробуждения. Полностью новый контейнер появляется только при повторной загрузке кода — вот она журнал предыдущего контейнера не сохраняет.
Поля status и reachability отвечают на разные вопросы
Поле status в ответе GET /v1/infra/servers/:id — это состояние учётной записи приложения на платформе. Пробуждение переводит запись в running в конце, когда контейнер уже запущен, поэтому во время подъёма галактики запись остаётся в sleeping — на холодной машине это занимает минуты. Обратное расхождение тоже возможно: запись может числиться в running, пока контейнер уже не работает.
Поэтому рядом идёт блок reachability — он отвечает на вопрос «может ли приложение ответить прямо сейчас». Блок приходит только у приложения, kind равен GALAXY_APP, у остальных типов серверов там null.
{
"success": true,
"data": {
"id": "e22bb297-8a0a-4597-9b42-47d059cd1090",
"kind": "GALAXY_APP",
"status": "sleeping",
"reachability": {
"effectiveStatus": "running",
"hostStatus": "running",
"hostTunnel": "CONNECTED",
"container": "running",
"forwarder": "active",
"publicEntry": "live",
"probe": "ok",
"probedAt": "2026-08-12T13:24:58.117Z"
}
}
}
Показаны поля, относящиеся к сну. Полный ответ — GET /v1/infra/servers/:id.
| Поле | Описание |
|---|---|
effectiveStatus |
Сводный ответ о доступности — running, sleeping, waking, unreachable или unknown. Как он выводится, показано в таблице ниже |
hostStatus |
Состояние галактики-носителя в том же наборе значений, что и status сервера |
hostTunnel |
Соединение галактики с платформой — CONNECTED, DISCONNECTED или NONE |
container |
Контейнер приложения — running, stopped или unknown. Значение unknown означает, что платформа не смогла посмотреть, а не что контейнер остановлен |
forwarder |
Маршрутизация к контейнеру на хосте — active, inactive или unknown. Во сне останавливается вместе с контейнером |
publicEntry |
Публичный адрес приложения — live (у шлюза есть живой туннель на поддомен приложения), no-tunnel (туннеля нет, снаружи адрес не обслуживается) или unknown (спросить шлюз не удалось). Значение unknown вердикт никогда не ухудшает |
probe |
Чем закончился живой опрос хоста — ok, host-down (галактика спит или недоступна, опрос не отправлялся), host-busy (хост занят другой операцией), failed или not-attempted |
probedAt |
Время опроса по стандарту ISO 8601. Значение null означает, что опроса не было |
Как складывается effectiveStatus:
| Состояние | effectiveStatus |
|---|---|
| Галактика загружается | waking |
| Галактика спит | sleeping |
| Галактика работает, контейнер остановлен | sleeping |
| Галактика работает, контейнер работает, маршрутизация активна, у публичного адреса есть туннель | running |
| Галактика работает, контейнер работает, маршрутизация активна, туннеля у публичного адреса нет | unreachable |
| Галактика работает, контейнер работает, маршрутизация остановлена | unreachable |
| Галактика в ошибке либо потеряла соединение с платформой | unreachable |
| Посмотреть не удалось | unknown |
Публичный вход проверяется отдельно. Контейнер и маршрутизация измеряются на самой галактике, а последний участок пути до https://app-XXXX.vibecode.bitrix24.tech — это туннель приложения на шлюзе, и на галактике его не видно: запущенный юнит маршрутизации означает, что его запустили, а не что он дозвонился до шлюза. Поэтому приложение с живым контейнером и активной маршрутизацией, но без туннеля, отвечает unreachable, а не running — снаружи такой адрес не обслуживается. Если состояние шлюза узнать не удалось, publicEntry равен unknown и вердикт остаётся прежним: «не смогли посмотреть» — это не «ничего не работает».
Важно: живой опрос хоста платформа делает только когда галактика работает и соединена с платформой. Спящую галактику чтение состояния не будит, поэтому у спящей галактики container и forwarder всегда unknown, а probe равен host-down. Результат опроса платформа держит несколько секунд и отдаёт из памяти: опрос занимает канал команд, общий для всех приложений галактики, поэтому частый опрос состояния его не занимает.
Чем поднять спящее приложение
| Способ | Что делает |
|---|---|
POST /v1/infra/servers/:id/wake |
Поднимает приложение через хост. При необходимости запускает галактику, затем стартует контейнер |
POST /v1/infra/servers/:id/start |
То же самое. Отдельного смысла у двух вызовов для приложения нет |
| Загрузка кода | Поднимает галактику сама и оставляет приложение работающим |
| Обращение к адресу приложения | Запрос через шлюз поднимает приложение и до готовности отвечает кодом BH_SERVER_WAKING с заголовком Retry-After — подробности в Авторизации в приложении на Black Hole |
| Доставка события портала | Платформа поднимает приложение перед доставкой |
Ответ на вызов пробуждения приходит сразу, а не по готовности: у приложения нет своей облачной машины, и параметр ?wait=true ожидания здесь не даёт. Готовность проверяйте опросом GET /v1/infra/servers/:id по полю reachability.effectiveStatus — значение waking означает, что галактика ещё загружается.
Сколько ждать: подъём холодной галактики платформа ждёт до 15 минут и столько же готова ждать от вызывающего. Точное значение бюджета приходит в ответе на чтение логов спящего приложения, поле recovery.coldBootBudgetSeconds. Приложение на уже работающей галактике стартует за секунды.
Запрет пробуждения на хосте блокирует оба вызова, и /start его не снимает. Коды отказов — в таблице жизненного цикла на странице Galaxy-приложение.
Логи спящего приложения
Чтение GET /v1/infra/servers/:id/logs не будит ни приложение, ни галактику. Пока галактика спит или недоступна, ответ приходит со статусом 200, пустым массивом data.logs и двумя диагностическими полями.
{
"success": true,
"data": {
"logs": [],
"lines": [],
"hint": "Galaxy host is asleep or unreachable, so the container log cannot be read right now. …",
"recovery": {
"reason": "The galaxy host carrying this container is not RUNNING + CONNECTED. …",
"recoveryAction": "POST /v1/infra/servers/e22bb297-8a0a-4597-9b42-47d059cd1090/wake",
"logsPreserved": true,
"coldBootBudgetSeconds": 900,
"poll": "GET /v1/infra/servers/e22bb297-8a0a-4597-9b42-47d059cd1090 (read `reachability`)",
"wakeSchedule": { "available": true, "code": null }
}
}
}
| Поле | Описание |
|---|---|
hint |
Та же подсказка обычным текстом, одной строкой. Текст зависит от того, может ли вызывающий позвать пробуждение: когда может — называет вызов пробуждения; когда нет — адреса пробуждения не называет вовсе, зато называет ровно то условие, которое сработало именно у него. Второй путь подъёма подсказка называет только тогда, когда он этому вызывающему доступен, то есть вместе с полем recovery.deliveryWakesHost, а не всегда |
recovery.reason |
Почему журнал сейчас не читается |
recovery.recoveryAction |
Вызов ПРОБУЖДЕНИЯ. Поле условное — его может не быть. Отсутствует всякий раз, когда вызывающий пробуждение позвать не может. Перечень таких состояний открыт и растёт, поэтому ветвитесь по НАЛИЧИЮ поля, а не по списку. Сегодня в него входят режим «только чтение», ключ Коворка/Кода, выключенный пилот галактик, ключ обслуживания агента, владелец с идущим удалением аккаунта и доступ к приложению по связи, когда сервером владеет другой ключ. Сюда же входит запрет пробуждения на самом ХОСТЕ галактики: он отбивает пробуждение любому вызывающему, включая полноправного владельца, поэтому в этом состоянии поля тоже нет. Проверяйте наличие ключа перед обращением: в этом состоянии адреса пробуждения нет ни в одном поле ответа — ни здесь, ни в hint. Важно: обратное не гарантия. НАЛИЧИЕ поля означает, что пробуждение не отбито ни по вызывающему, ни запретом на хосте, — но не что вызов состоится в любом случае: остаются отказы по СОСТОЯНИЮ пары, которые ответ логов не предсказывает (422, когда приложение не в том статусе или хост не загрузился, 404, когда галактика осиротела). Обрабатывайте такой отказ, а не считайте наличие поля гарантией |
recovery.logsPreserved |
Значение true означает, что строки, записанные до сна, доступны после пробуждения |
recovery.coldBootBudgetSeconds |
Бюджет подъёма холодной галактики в секундах |
recovery.poll |
Чем проверять готовность вместо повторного чтения логов. Поле условное — его может не быть. Отсутствует, когда GET /v1/infra/servers/{id} отказывает самому вызывающему: у ключа обслуживания агента этого маршрута нет в перечне, а у владельца с идущим удалением аккаунта он живёт в замороженном контуре, в отличие от чтения журнала. Нет поля — просто перечитайте журнал позже, подсказка так и говорит |
recovery.deliveryWakesHost |
Второй путь подъёма. Поле условное вдвойне: приходит, только когда пробуждение вызывающему недоступно И деплой ему при этом доступен. action — вызов деплоя, cost — его цена словами. Деплой на спящее галакси-приложение поднимает хост сам, но это ВЫКЛАДКА КОДА и расход баланса, а не пробуждение — ради одного лишь чтения журнала его звать не надо. Важно: отсутствие поля означает, что и этот путь закрыт: послабление режима «только чтение» снимает у деплоя гейт РЕЖИМА и только его, а ключу Коворка/Кода, выключенному пилоту и ключу обслуживания агента деплой отказывают те же двери, что и пробуждению. Поле отсутствует и при запрете пробуждения на хосте — деплой спящий хост с таким запретом НЕ поднимает, а отвечает 502 |
recovery.wakeSchedule |
Доступно ли окно пробуждения по расписанию этому вызывающему: и пригодность самого приложения, и право вызывающего на запись — одним вердиктом. Поле available — ответ, поле code при отказе несёт тот же код, которым ответит создание окна. Когда recoveryAction отсутствует, поле приходит available: false с кодом той двери, которая отбила пробуждение: создание окна — та же запись и отбивают её те же двери. Исключение — дверь окна, которая проверяется раньше этой: тогда code называет дверь окна, и hint называет ту же дверь, а не говорит, что окно отбивает то же условие, что и пробуждение. Важно: у окна есть и ДВЕ собственные двери, которых у пробуждения нет, поэтому code может назвать отказ, которого в списке дверей пробуждения не найти, а available: false может прийти и при наличии recoveryAction. Первая проверяется раньше всех остальных: маршрут окна отсутствует в перечне маршрутов ключа внешнего участника, тогда как пробуждение, деплой и чтение журнала в этом перечне есть, — EXTERNAL_COLLABORATOR_KEY_OUT_OF_SCOPE. Вторая проверяется позже дверей режима, заморозки, Коворка и пилота, но РАНЬШЕ проверки владения сервером: маршруту окна нужен скоуп vibe:infra, которого чтение логов и пробуждение не требуют, поэтому до этого отказа доходит и обычный ключ без скоупа — INFRA_SCOPE_REQUIRED, и лечится он выдачей скоупа, а не сменой режима. Владение проверяется после скоупа, поэтому вызывающему, пришедшему по связи приложения и не несущему скоуп, придёт INFRA_SCOPE_REQUIRED, а не NOT_FOUND |
Порядок действий: поднять приложение вызовом из recovery.recoveryAction, дождаться reachability.effectiveStatus равного running, повторить чтение логов.
Если поля recoveryAction в ответе нет — пробуждение откажут. Причина бывает двух родов, и hint называет ту, что сработала: либо дверь самого вызывающего (перечень ниже), либо запрет пробуждения на ХОСТЕ галактики — тогда ключ ни при чём, отказ придёт любому, и снимать запрет идёт владелец аккаунта. Вызов пробуждения в этом состоянии отвечает 403 SERVER_WAKE_BLOCKED, а пока у аккаунта просрочен доступ — 402 с кодом подписочной или тарифной стены. Окно по расписанию в этом состоянии создать можно, но хост оно не поднимет: запрет действует и на пробуждение по расписанию. Адреса пробуждения нет и в прозе: в этом состоянии ответ намеренно не называет ни POST …/wake, ни создание окна по расписанию — окно отбивает та же дверь. hint вместо адреса называет ровно то условие, которое сработало у него самого, а не список через «или», — и называет ПЕРВОЕ по порядку, в каком двери отбивают на самом деле. Порядок такой: у ключа обслуживания агента пробуждения нет в перечне маршрутов; при идущем удалении аккаунта пробуждение закрыто целиком, и смена ключа не поможет — заморожен владелец, а не ключ (доставка при этом остаётся открытой, см. ниже про второй путь); режим ключа переключается по Режиму доступа; ключу Коворка/Кода управляющий контур закрыт целиком; выключенный пилот галактик снимает администратор аккаунта; и последняя — доступ к приложению по связи, когда сервером владеет другой ключ: пробуждение проверяет владение строже, чем чтение журнала, поэтому такому вызывающему оно отвечает 404, и помогает только вызов ключом-владельцем сервера.
У части вызывающих выход всё же есть, и это не пробуждение. Ключу в режиме «только чтение» разрешён деплой на свой сервер, а деплой на спящее галакси-приложение поднимает хост сам. Тот же путь открыт ещё двум вызывающим, которым отказано в пробуждении: владельцу с идущим удалением аккаунта (заморозка стоит на плагине /v1/infra, а доставка живёт в другом) и тому, кого пустили по связи приложения (владение доставка проверяет мягче, чем пробуждение). Закрыт этот путь ровно трём: ключу Коворка/Кода, ключу обслуживания агента и вызывающему на аккаунте с выключенным пилотом галактик. Когда этот путь открыт, платформа называет его машинно — полем recovery.deliveryWakesHost (action — вызов, cost — цена словами), и цена тут не формальность: это выкладка кода и расход баланса Вайбкод, а не пробуждение. Звать его ради одного лишь чтения журнала не надо.
Открыт он не всем, и поле это показывает. Послабление для режима «только чтение» снимает у деплоя гейт РЕЖИМА и только его. Ключу Коворка/Кода управляющий контур закрыт целиком, при выключенном пилоте галактик отказывают любые не-GET по этому семейству, а у ключа обслуживания агента деплоя нет в его перечне маршрутов — всем троим POST …/deploy ответит отказом ровно так же, как и пробуждение. Поэтому проверяйте наличие deliveryWakesHost, а не предполагайте его: нет поля — открытого пути нет, и надо менять условие из hint. Важно: обратное тоже не гарантировано, ровно как у recoveryAction: наличие поля означает, что деплой не отбит ни по identity и режиму ключа, ни запретом на хосте. Оно не отвечает за состояние счёта НА МОМЕНТ ВЫЗОВА: заморозка баланса закрывает всё семейство /v1/infra целиком (402 ACCOUNT_FROZEN), и если она наступит после этого чтения, названный action получит именно её — тем более что деплой тратит баланс по построению. Пока условие не изменилось, повторять чтение логов в цикле смысла нет: ответ не изменится.
Окно пробуждения по расписанию
Окно пробуждения поднимает приложение по расписанию, без вызова руками. Доступно оно не каждому приложению, и проверять это следует по ответу платформы, а не по общему правилу: поле recovery.wakeSchedule в ответе на чтение логов спящего приложения даёт готовый ответ для конкретного приложения, а при отказе — его код.
Ответ этот — и про приложение, и про вызывающего сразу. Создание окна остаётся записью, поэтому ключу в режиме «только чтение», ключу Коворка/Кода и порталу с выключенным пилотом галактик оно откажет; в этих состояниях поле приходит available: false с кодом отбившей двери. Пробуждение — хороший первый признак: нет recovery.recoveryAction — окна этому вызывающему тоже не создать. Но признак этот не полный, потому что у окна есть две двери, которых у пробуждения нет: маршрут отсутствует в перечне ключа внешнего участника (EXTERNAL_COLLABORATOR_KEY_OUT_OF_SCOPE) и требует скоуп vibe:infra, которого пробуждение не требует (INFRA_SCOPE_REQUIRED). Любая из двух откажет в окне и тому, кто приложение разбудить может, — поэтому читайте само поле recovery.wakeSchedule, а не выводите его из recoveryAction.
Приложение в галактике отказ ALWAYS_ON_CONFLICT не получает: тариф оно не выбирает, а наследует от галактики, и режимом «Всегда онлайн» платформа его не считает. Это касается и агентов, и ботов: своего таймера простоя у них нет, но окно пробуждения им доступно на общих условиях. Остальные отказы окна при этом действуют — например, WAKE_SCHEDULE_GALAXY_DISABLED, когда на платформе выключена возможность для приложений галактики.
Список окон, создание, изменение и удаление — Пробуждение по расписанию.