BorisovAI
Все публикации
Новая функцияC--projects-bot-social-publisherClaude Code

SQLite между Windows и Linux: как не потерять данные при деплое

SQLite между Windows и Linux: как не потерять данные при деплое

Когда SQLite на Windows встречает Linux: история одного деплоя

Проект ai-agents-admin-agent был почти готов к запуску на сервере. Восемь n8n-воркфлоу, собирающих и обрабатывающих данные, уже прошли тестирование локально. На машине разработчика всё работало идеально. Но только до того момента, когда мы выложили их на Linux-сервер.

Первый боевой запуск воркфлоу завершился криком ошибки: no such table: users. Логи были красноречивы — все SQLite-ноды искали базу данных по пути C:\projects\ai-agents\admin-agent\database\admin_agent.db. Локальный Windows-путь. На сервере такого вообще не существовало.

Первый инстинкт: просто заменить пути

Звучит логично, но дьявол, как всегда, в деталях. Я начал рассматривать варианты.

Вариант первый — использовать относительный путь типа ./data/admin_agent.db. Звучит мобильно и красиво, но это ловушка для новичков. Относительный путь разрешается от текущей рабочей директории процесса n8n. А откуда запущен n8n? Из Docker-контейнера? Из systemd? Из скрипта? Результат абсолютно непредсказуем.

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

Я выбрал комбинированный подход.

Как мы это реализовали

Локально в docker-compose.yml добавил переменную окружения DATABASE_PATH=/data/admin_agent.db — чтобы разработка была удобной и воспроизводимой. Затем создал развёртывающий скрипт, который при деплое проходит по всем восьми воркфлоу и заменяет выражение $env.DATABASE_PATH на реальный абсолютный путь /var/lib/n8n/data/admin_agent.db.

Но первое время я попытался обойтись выражениями n8n. Логика казалась неубиваемой: задаёшь переменную в окружении, ссылаешься на неё в воркфлоу, всё просто. На практике выяснилось, что в n8n v2.4.5 таск-раннер не передавал переменные окружения в SQLite-ноду так, как ожидалось. Выражение хранилось в конфигурации, но при выполнении всё равно искал исходный Windows-путь.

Пришлось идти в лоб — строковые замены при деплое. Развёртывающий скрипт deploy/deploy-n8n.js перехватывает JSON каждого воркфлоу и подставляет правильный путь перед загрузкой.

Ещё одна подводная скала: n8n хранит две версии каждого воркфлоу — stored (в базе данных) и active (загруженная в памяти). Когда вы обновляете конфигурацию через API, обновляется только stored-версия. Active может остаться со старыми параметрами. Это сделано для того, чтобы текущие выполнения не прерывались, но создаёт рассинхронизацию между кодом и поведением. Решение: явная деактивация и активация воркфлоу после обновления.

Добавили в процесс и инициализацию БД: скрипт SSH копирует на сервер миграции (schema.sql, seed_questions.sql) и выполняет их через n8n API перед активацией воркфлоу. В будущем, когда потребуется изменить схему (например, добавить колонку phone в таблицу users), достаточно добавить миграцию — без пересоздания всей БД.

Итог

Теперь деплой сводится к одной команде: node deploy/deploy-n8n.js --env .env.deploy. Воркфлоу создаются с правильными путями, база инициализируется корректно, всё работает.

Главный урок: не полагайся на относительные пути в Docker-контейнерах и на runtime-выражения в критических параметрах. Лучше заранее знать, где именно будет жить твоё приложение, и подставить правильный путь при развёртывании. Это скучно, но предсказуемо.

GitHub — единственная технология, где «это работает на моей машине» считается достаточной документацией. 😄

Метаданные

Session ID:
grouped_C--projects-bot-social-publisher_20260207_1900
Branch:
main
Dev Joke
GitHub — единственная технология, где «это работает» считается документацией.

Оцените материал

0/1000