Перейти к содержимому

Резервное копирование, экспорт и импорт

Всё, что Control Center умеет копировать, передавать или принимать, и точная форма каждого артефакта. О том, как снять резервную копию на практике, см. Резервное копирование и восстановление; о том, почему хранилище устроено именно так, см. Рабочие пространства и изоляция.

Есть три артефакта копирования баз данных, с разными областями действия и политиками удаления.

Артефакт Кем создаётся Форма Что охватывает
Снимок установки server.backupNow Каталог с меткой времени Все базы данных установки
Резервная копия рабочего пространства конвейер Workspace backup Каталог с меткой времени с одним .db База данных одного рабочего пространства
Экспорт рабочего пространства workspace.export Один файл .db База данных одного рабочего пространства

Все они создаются с помощью SQLite VACUUM INTO, что безопасно для работающей базы данных с WAL: команда берёт транзакцию чтения, создаёт дефрагментированную и транзакционно согласованную копию и никогда не требует останавливать сервер.

<dataDir>/backups/2026-07-28T09-12-33-000Z/
manifest.json
global.db
<workspaceId>/workspace.db one directory per workspace

Структура в точности повторяет живой каталог данных — именно поэтому восстановление установки сводится к копированию обратно, а не к преобразованию. Имя каталога — это метка времени UTC, в которой : и . заменены на -, поэтому оно безопасно для файловой системы Windows и сортируется хронологически как обычная строка.

Запланированные резервные копии рабочих пространств лежат отдельно, по пути <dataDir>/backups/workspace-backups/<workspaceId>/<timestamp>/workspace.db. Они не включают манифест или global.db и не являются снимками установки. Шаг удаления по сроку хранения в недельном конвейере удаляет только резервные копии его собственного рабочего пространства старше настроенного срока (по умолчанию 30 дней); снимки установки, созданные вручную, этим шагом никогда не ротируются. server.listBackups перечисляет только снимки установки, включая неполные.

Поле Тип Значение
version int Версия формата манифеста. Сейчас 1
created_at ISO-8601 UTC Когда был снят снимок
global.file string Всегда global.db
global.schema_version int Версия схемы GlobalDatabase на момент снятия
global.bytes int Размер записанного global.db
workspace_schema_version int Версия схемы WorkspaceDatabase, общая для всех файлов рабочих пространств
workspaces[] array По одной записи на каждое снятое рабочее пространство
workspaces[].workspace_id string Рабочее пространство, которому принадлежит этот файл
workspaces[].file string Путь относительно корня снимка, <workspaceId>/workspace.db
workspaces[].bytes int Размер этого файла
skipped_workspaces[] массив строк Рабочие пространства, которые резервная копия не смогла снять

Рабочее пространство пропускается, когда оно зарегистрировано, но в него никогда не писали (поэтому файла ещё нет), или когда его VACUUM INTO завершился ошибкой. В любом случае снимок всё равно создаётся до конца, а манифест называет то, чего не хватает.

server.listBackups сообщает для каждого снимка флаг complete. Он равен false, когда манифест отсутствует или неразбираем, когда нет global.db или когда манифест называет файл рабочего пространства, которого нет на диске.

Неполный снимок всё равно попадает в список: снимок, которого оператор не видит, — это снимок, который он считает, что у него есть. Когда манифест не читается, список опирается на саму структуру и сообщает о тех файлах <workspaceId>/workspace.db, которые находит, — их по-прежнему можно по отдельности принять через workspace.import, хотя снимок в целом не может восстановить установку.

Оба артефакта — только базы данных. Каталог рабочего пространства содержит больше, чем его базу данных, и ничего из остального не переносится:

Путь В снимке? В экспорте рабочего пространства?
global.db Да Нет
<workspaceId>/workspace.db Да Да (это и есть файл)
<workspaceId>/blobs/ Нет Нет
<workspaceId>/skills/ Нет Нет
<workspaceId>/agents/ Нет Нет
<workspaceId>/chat_credentials/ Нет Нет
<workspaceId>/spaces/<spaceId>/ Нет Нет
<workspaceId>/pr_clones/ Нет Нет
secrets.json Нет Нет
models/ Нет Нет
meetings/<meetingId>/ Нет Нет
rigs/ Нет Нет

Часть этого можно воссоздать — spaces/ содержит worktree с копированием при записи, которые заново создаются из репозиториев, pr_clones/ — это кэш, models/ скачивается заново, rigs/ — это состояние машины. Часть — нет: blobs/ содержит вставленные изображения, на которые ссылаются строки базы данных, skills/ и agents/ содержат файлы, с которыми работает агент, а secrets.json содержит все ключи сопряжения, учётные данные провайдеров и настройки SSO установки. О том, как охватить остальное, см. Резервное копирование и восстановление.

RPC резервного копирования установки, а также экспорт и импорт рабочих пространств доступны только fullClient: сопряжённый телефон не может их запустить. На сервере без подключённого порта резервного копирования, например на демонстрационном сервере, они отсутствуют полностью — не отклоняются, а структурно отсутствуют.

Операция Тип Область Минимальная роль Аргументы Возвращает
server.backupNow изменение Установка владелец установки нет {ok, path}
server.listBackups чтение Установка владелец установки нет {backups: [...]}
server.deleteBackup изменение Установка владелец установки name {ok}
workspace.export чтение Рабочее пространство admin нет {ok, path}
workspace.import изменение Рабочее пространство owner source_path {ok, workspace_id}
workspace.delete изменение Установка* owner id строка реестра помечена удалённой
  • workspace.delete не имеет области действия, потому что строка, которую он помечает, живёт в глобальном реестре; его обработчик проверяет членство вызывающего в указанном рабочем пространстве и требует owner.

path в каждом ответе — это путь на хосте сервера.

Сначала самые новые, отсортированные по имени каталога (это метка времени, поэтому порядок сохраняется даже для снимка, манифест которого не удалось прочитать).

{
"backups": [
{
"path": "/…/backups/2026-07-28T09-12-33-000Z",
"name": "2026-07-28T09-12-33-000Z",
"created_at": "2026-07-28T09:12:33.000Z",
"bytes": 481203712,
"complete": true,
"workspaces": [
{
"workspace_id": "w_9f2c…",
"path": "/…/backups/2026-07-28T09-12-33-000Z/w_9f2c…/workspace.db",
"bytes": 190840832
}
],
"skipped_workspace_ids": []
}
]
}

created_at опускается, когда манифест не удалось прочитать. bytes верхнего уровня — это реальный размер всего каталога на диске, а не сумма из самого манифеста: вопрос, который задаёт оператор, удаляющий лишние снимки, — сколько занимает каталог, а не сколько резервная копия собиралась записать.

Каждый workspaces[].path — это ровно то, что workspace.import принимает как source_path. Это сделано намеренно: «восстановить это рабочее пространство из этого снимка» и есть операция импорта, поэтому они не могут разойтись в разном обращении с одним и тем же файлом.

Прежде чем что-либо будет заменено, файл-кандидат открывается только для чтения через недолговечное необработанное соединение SQLite, и из него читается строка workspace_meta.

Условие Результат
Не читаемая база данных SQLite или отсутствие workspace_meta Отказано. Ничего не затрагивается
Записанный идентификатор рабочего пространства ≠ целевого Разрешено, записывается в журнал. Так рабочее пространство дублируют или восстанавливают под новым идентификатором
Записанный идентификатор установки ≠ этой установки Разрешено, записывается в журнал. Его сопряжённые устройства и идентификаторы пользователей принадлежат той установке и здесь не разрешатся
Недопустимый идентификатор рабочего пространства или отсутствующий файл Отказано

При принятии база данных целевого рабочего пространства закрывается и удаляется из менеджера до того, как поверх неё скопируют файл (открытое соединение Drift удерживает файл и его -wal), затем открывается заново, чтобы beforeOpen переустановил триггеры FTS и синхронизации, а индексы FTS перестраиваются: таблицы содержимого импортированного файла заполнены, но его индекс может быть устаревшим.

Каждая операция выше оперирует путями на стороне сервера, а это исчерпывающий ответ только тогда, когда сервер — ваша собственная машина. Эти три маршрута переносят байты по той же подписанной PSK полосе, которой пользуются прокси медиа и хранилище изображений. Вызывающий подписывает целевую строку предварительно разделяемым ключом своего устройства и передаёт подпись как s.

Маршрут Метод Параметры запроса Подписанная цель Требуется
/backup/workspace GET w, d, s backup-workspace:<workspaceId> Администратор рабочего пространства
/backup/snapshot GET n, d, s backup-snapshot:<name> Владелец установки
/backup/restore POST w, d, s backup-restore:<workspaceId> Владелец рабочего пространства

w — идентификатор рабочего пространства, n — имя каталога снимка, d — идентификатор вызывающего устройства, s — подпись. n сопоставляется со списком резервных копий, а не присоединяется к корню резервных копий, поэтому маршрут нельзя навести на каталог, который список не показал бы.

Статус Причина
400 Отсутствует обязательный параметр запроса или тело загрузки пусто
403 Неизвестное или отозванное устройство, неверная подпись или у вызывающего нет нужной роли
404 На этом хосте нет порта резервного копирования или указанный снимок либо файл рабочего пространства не существует
405 /backup/restore вызван с методом, отличным от POST
413 Тело загрузки превышает 8 ГиБ по объявленному content-length или по фактически прочитанным байтам
500 Экспорт или архивация завершились ошибкой на стороне сервера

Оба скачивания отвечают Cache-Control: no-store и Accept-Ranges: none. Каждый запрос создаёт свежую копию и удаляет её после передачи потоком, поэтому кэшированный ответ или ответ с докачкой склеил бы байты из двух разных экспортов в один файл, который выглядит валидным и таковым не является.

/backup/snapshot возвращает <name>.zip, где записи заданы относительно корня снимка, поэтому распаковка воспроизводит manifest.json + global.db + <workspaceId>/workspace.db. Записи пишутся в отсортированном порядке, поэтому два архива одного и того же снимка — это один и тот же архив.

/backup/restore пишет тело потоком прямо в промежуточный файл, а не буферизует его, ограничивает его до и во время чтения и удаляет промежуточный файл на любом пути выхода, включая отказ.

Что Значение
Снимки <dataDir>/backups/<timestamp>/
Запланированные резервные копии рабочих пространств <dataDir>/backups/workspace-backups/<workspaceId>/<timestamp>/workspace.db
Экспорты рабочих пространств <dataDir>/backups/exports/<workspaceId>-<timestamp>.db
Промежуточные файлы передачи <dataDir>/backups/transfer/ — рабочая область, которую очищает маршрут, записывающий в неё
Имя архива снимка <snapshot directory name>.zip
Потолок загрузки 8 ГиБ на POST /backup/restore
Срок хранения Снимки установки: удаление вручную. Резервные копии рабочих пространств: недельный конвейер, по умолчанию 30 дней

Каталоги exports/, transfer/ и workspace-backups/ не являются снимками установки и исключены из server.listBackups. Только у последнего каталога есть автоматическое удаление по сроку хранения; удаление снимка установки требует явного действия владельца установки.