Жизненный цикл соединения
От первого открытия WebSocket до стабильной работы клиент проходит несколько фаз. Эта страница — референс для написания устойчивого клиента, который сам восстанавливается после дисконнектов.
Полный цикл
Заголовок раздела «Полный цикл» ┌──────────────────┐ │ connect(ws://...)│ └────────┬─────────┘ │ ▼ ┌──────────────────┐ HELLO (op 10) │ сервер → HELLO │◀─────────────── │ heartbeat_ │ │ interval │ └────────┬─────────┘ │ ├─── запускаем heartbeat-таймер │ ▼ ┌──────────────────┐ IDENTIFY (op 2) или RESUME (op 6) │ клиент → IDENTIFY│───────────────▶ └────────┬─────────┘ │ ▼ ┌──────────────────┐ READY (op 0, t=READY) │ сервер → READY │◀─────────────── │ session_id, │ │ user, guilds │ └────────┬─────────┘ │ ▼ ┌──────────────────┐ │ нормальная работа│ ← dispatch-события, heartbeat каждые N мс │ │ └────────┬─────────┘ │ ┌──────────┼──────────┬──────────────┐ │ │ │ │ ▼ ▼ ▼ ▼ close INVALID_ RECONNECT heartbeat code SESSION (op 7) ACK пропал (op 9) │ │ │ │ └────┬─────┴──────────┴──────────────┘ │ ▼ реконнект → RESUME если session_id жив, иначе IDENTIFYФаза 1: HELLO
Заголовок раздела «Фаза 1: HELLO»Сразу после подключения сервер шлёт опкод 10 (HELLO):
{ "op": 10, "d": { "heartbeat_interval": 41250 }}heartbeat_interval в миллисекундах. Клиент запускает таймер, который каждые N мс отправляет heartbeat (см. ниже).
Фаза 2: IDENTIFY
Заголовок раздела «Фаза 2: IDENTIFY»Клиент отправляет опкод 2 с токеном и информацией о клиенте:
{ "op": 2, "d": { "token": "Bot MTIzNDU2...", "properties": { "os": "linux", "browser": "mybot", "device": "mybot" }, "presence": null, "ignored_events": [], "initial_guild_id": null, "flags": 0 }}| Поле | Обязательно | Описание |
|---|---|---|
token | Да | Строка вида Bot <token> для ботов или «сырой» user-token для первой стороны |
properties.os | Да | Произвольная строка, например linux |
properties.browser | Да | Имя вашего приложения, например mybot |
properties.device | Да | Имя устройства/инстанса |
presence | Нет | Начальный presence — см. PRESENCE_UPDATE |
ignored_events | Нет | Массив строк — типы событий, которые не получать. По умолчанию приходит всё |
initial_guild_id | Нет | ID гильдии, с которой начать синхронизацию, если у клиента их много |
flags | Нет | Битовое поле фич — по умолчанию 0 |
Если токен не валиден — сервер закроет соединение с кодом 4004 AUTHENTICATION_FAILED. Реконнектиться при этом нельзя — получите ban-эскалацию.
Фаза 3: READY
Заголовок раздела «Фаза 3: READY»При успешном IDENTIFY сервер шлёт событие READY (op: 0, t: "READY"):
{ "op": 0, "s": 1, "t": "READY", "d": { "v": 1, "user": { "id": "149...", "username": "my_bot", "bot": true, "flags": 0 }, "session_id": "a1b2c3d4...", "resume_gateway_url": "wss://gateway.floodilka.com", "guilds": [ { "id": "142...", "unavailable": true } ], "user_settings": { ... } }}Критичные поля, которые надо сохранить:
session_id— потребуется для RESUMEresume_gateway_url— использовать вместо дефолтного URL при RESUMEsиз оболочки (1в примере) — последний номер события в сессии
Флаг unavailable: true у гильдии означает, что полные данные ещё не загружены. Дождитесь событий GUILD_CREATE — они прилетят в течение секунд после READY.
Фаза 4: Heartbeat loop
Заголовок раздела «Фаза 4: Heartbeat loop»Клиент обязан каждые heartbeat_interval мс отправлять опкод 1 с последним виденным s:
{ "op": 1, "d": 42 }Если s ещё не был получен (сразу после HELLO) — d: null.
В ответ сервер шлёт 11 (HEARTBEAT_ACK):
{ "op": 11 }Сервер может сам прислать 1 (попросить клиент отправить heartbeat сейчас) — в этом случае отвечайте немедленно, не дожидаясь таймера.
Фаза 5: Обработка событий
Заголовок раздела «Фаза 5: Обработка событий»После READY начинают приходить dispatch-сообщения:
{ "op": 0, "s": 43, "t": "MESSAGE_CREATE", "d": { "id": "...", "channel_id": "...", "content": "hi", "author": { ... } }}Обновляйте s из каждого такого сообщения — он потребуется для heartbeat и RESUME.
Полный список типов — в разделе События.
Фаза 6: Дисконнект и восстановление
Заголовок раздела «Фаза 6: Дисконнект и восстановление»Соединение может разорваться тремя способами:
RECONNECT (op 7)
Заголовок раздела «RECONNECT (op 7)»Сервер прислал опкод 7 без d — просит клиента переподключиться и возобновить сессию:
{ "op": 7, "d": null }Алгоритм:
- Закрыть WebSocket с кодом
4000(чтобы сервер не сбрасывал сессию) - Подключиться заново к
resume_gateway_url(из READY) - Дождаться HELLO, запустить heartbeat
- Отправить RESUME (op 6) вместо IDENTIFY
INVALID_SESSION (op 9)
Заголовок раздела «INVALID_SESSION (op 9)»Сервер прислал опкод 9:
{ "op": 9, "d": true }d: true— сессия жива, можно попробовать RESUMEd: false— сессия мертва, надо новый IDENTIFY (не RESUME)
В обоих случаях подождите 1-5 секунд с рандомным jitter’ом перед попыткой — не спамьте.
Close code
Заголовок раздела «Close code»WebSocket закрылся с close code. Справочник — Коды закрытия. Ключевое:
1000,1001,4000-4003(не4004) — переподключаться безопасно4004 AUTHENTICATION_FAILED,4010 INVALID_SHARD,4011 SHARDING_REQUIRED,4012 INVALID_API_VERSION— реконнект не поможет. Разбирайтесь с конфигом клиента
Фаза 7: RESUME
Заголовок раздела «Фаза 7: RESUME»RESUME — это IDENTIFY с контекстом предыдущей сессии:
{ "op": 6, "d": { "token": "Bot MTIzNDU2...", "session_id": "a1b2c3d4...", "seq": 42 }}seq — последнее виденное значение s. Сервер «догонит» клиента, отправив пропущенные события начиная с seq + 1, затем отправит RESUMED (op: 0, t: "RESUMED").
Если seq устарел (сервер не держит события так далеко в прошлое) — придёт op: 9 (INVALID_SESSION, d: false), и надо делать IDENTIFY заново. Всё состояние, накопленное в памяти клиента, придётся сбросить.
Шаблон устойчивого реконнекта
Заголовок раздела «Шаблон устойчивого реконнекта»- Подключаемся, ждём HELLO, стартуем heartbeat
- Если у нас есть сохранённые
session_idиseq— отправляем RESUME. Иначе — IDENTIFY - Ждём READY или RESUMED. Сохраняем
session_idиresume_gateway_url - Работаем, обновляем
seqиз каждого события - При любом дисконнекте:
- Exponential backoff с jitter (1s, 2s, 4s, …, max 30s)
- Если текущая попытка — RESUME и она упала с
op: 9→ сбрасываем состояние и идём в IDENTIFY - Если close code —
4004/4010/4011/4012— останавливаем бота, логируем ошибку, не ретраим
Что дальше
Заголовок раздела «Что дальше»- Опкоды — все
op-значения - Коды закрытия — таблица close codes
- События — полный список dispatch-событий