Безопасность · OpenClaw

WAL агентской базы на Windows: как снять клин и не потерять Gateway

По размеру openclaw-agent.sqlite-wal и логам отличим залипший чекпойнт от просто большого WAL и соберём офлайн-команду wal_checkpoint(TRUNCATE).

· 4 мин чтения

Коротко

  • На Windows 2026.9.2/9.3 у одного агента openclaw-agent.sqlite-wal дорос до 2865 МБ, Gateway жив, но /healthz отвечает отказом соединения: старт висит на захвате SQLite-лока.
  • wal_autocheckpoint=1000 стоит по умолчанию, а чекпойнт не идёт. 97% WAL это повторные перезаписи тех же страниц.
  • Офлайн wal_checkpoint(TRUNCATE) снимает проблему за ~20 с, живой чекпойнт только подрезает пик, и WAL тут же растёт.
  • Поставьте размер *.sqlite-wal в мониторинг и держите наготове сценарий стоп-старта Gateway выше своего порога.

Сверено с документацией OpenClaw 2026.9.7, 2 октября 2026.

У одного агента на Windows-хосте файл openclaw-agent.sqlite-wal за дни вырос до 2865 МБ. После ручного офлайн-чекпойнта он упал до нуля и за два дня вернулся к 1477 МБ. Процесс Gateway при этом жив, но порт не биндится. /healthz отдаёт отказ соединения, а дельта лога за 25 секунд равна нулю байт.

Как отличить «большой» WAL от залипшего

97% WAL это повторные перезаписи одних и тех же страниц. Из 2865 МБ на «свежую» запись пришлось 72.5 МБ (2.5%). Из 1477 МБ пришлось 73.6 МБ (5%). Это сигнатура зависшего чекпойнта, а не настоящего объёма данных.

Картина pragma при этом нормальная: integrity_check = ok, wal_autocheckpoint = 1000, journal_mode = wal. Пока WAL измеряется гигабайтами, Gateway не биндит порт и старт висит на захвате SQLite-лока.

Диагностика за 30 секунд

Сначала найдите самый большой WAL по всем агентам. Сразу видно, у кого проблема.

Get-ChildItem $env:USERPROFILE\.openclaw\ -Recurse -Filter *.sqlite-wal -EA 0 |
  Sort Length -Desc | Select -First 5 |
  % { "{0} MB`t{1}" -f [math]::Round($_.Length/1MB,1), $_.FullName }

Запись больше нескольких сотен мегабайт это повод копать. Затем проверьте, жив ли процесс и отвечает ли порт. При зависшем чекпойнте процесс жив, но /healthz отдаёт exit 7 (отказ соединения), а дельта лог-файла за 25 секунд равна нулю байт.

Если порт не отвечает, а процесс на месте, смотрите в лог на subsystem=sqlite/transaction и Gateway restart timed out after 181s waiting for health checks. Это и есть «старт висит на захвате лока».

Офлайн wal_checkpoint(TRUNCATE) снимает клин

Попытки сделать wal_checkpoint(TRUNCATE) на живой базе дают busy=1, все кадры чекпойнтятся, но без сброса файла. Помогает только офлайн, со стопом Gateway, эксклюзивным доступом и бэкапом главной базы. WAL в бэкап не копируйте.

schtasks /Change /TN "OpenClaw Gateway" /DISABLE
Get-CimInstance Win32_Process -Filter "Name='node.exe'" |
  ? CommandLine -like "*openclaw*" | % { Stop-Process -Id $_.ProcessId -Force }
Start-Sleep 8

$db = "$env:USERPROFILE\.openclaw\agents\agent-a\agent\openclaw-agent.sqlite"
copy $db "$db.bak" -Force

& "C:\Program Files\nodejs\node.exe" -e "
const {DatabaseSync}=require('node:sqlite');
const d=new DatabaseSync(process.argv[1]);
console.log(JSON.stringify(d.prepare('PRAGMA integrity_check').get()));
console.log(JSON.stringify(d.prepare('PRAGMA wal_checkpoint(TRUNCATE)').get()));
d.close();" "$db"

DatabaseSync всасывает WAL при открытии, поэтому wal_checkpoint(TRUNCATE) часто возвращает busy:0, log:0, checkpointed:0 и выглядит как пустая операция. Судить надо по размеру: главный файл вырос, openclaw-agent.sqlite-wal ушёл в 0 МБ. Это известная ловушка при отладке. Затем верните Gateway обратно через Планировщик задач и проверьте /healthz.

Границы применимости

Симптом воспроизведён на Windows 2026.9.2/9.3 (Server, Node v24.18.0) и отдельно на 2026.8.2. Есть и второй сценарий: залипает state/openclaw.sqlite-wal (0 → 691 МБ за ~12 минут) на 2026.9.4. Там виноват не base64, а поток мелких записей под нагруженным event loop.

Что проверить у себя

  1. Найти самый большой WAL командой из раздела про диагностику. Запись больше нескольких сотен МБ уже повод действовать.
  2. Собрать набор для офлайн-чекпойнта: schtasks /Change /TN "OpenClaw Gateway" /DISABLE, остановка node.exe по CommandLine -like "*openclaw*", копия основной базы с расширением .bak, запуск node с PRAGMA wal_checkpoint(TRUNCATE) через node:sqlite DatabaseSync.
  3. Судить о результате по размеру файлов: главный openclaw-agent.sqlite вырос, openclaw-agent.sqlite-wal ушёл в 0 МБ. Возврат busy:0, log:0, checkpointed:0 при этом нормален, если WAL при открытии уже втянут.
  4. Завести сценарий-сторож: каждые 15 минут мерять *.sqlite-wal, выше 50 МБ пробовать живой wal_checkpoint(TRUNCATE), выше 200 МБ выполнять стоп Gateway, офлайн TRUNCATE, старт. Контрольное время обслуживания в репро: ~26 с от начала до конца.
  5. Следить за логом subsystem=sqlite/transaction с порогом thresholdMs=1000 и строкой тайм-аута рестарта по ожиданию health-проверок.
  6. Проверить настройки сессии: в session.maintenance были только maxDiskBytes: 500mb и highWaterBytes: 400mb без pruneAfter и maxEntries, поэтому данные не удалялись.
  7. Проверить, нет ли в transcript_events крупных toolResult от view_image. Это отдельный вектор роста (отдельный тикет #143973), который один способен перегнать wal_autocheckpoint.