SQLite на кроссплатформе: когда переменные окружения предают

SQLite между Windows и Linux: как не потерять данные при деплое
Проект ai-agents-bot-social-publisher был почти готов к боевому выпуску. Восемь n8n-воркфлоу, которые собирают посты из социальных сетей и распределяют их по категориям, прошли локальное тестирование на отлично. Но тут наступил момент истины — первый деплой на Linux-сервер.
Логи завалили ошибкой: no such table: users. Все SQLite-ноды в воркфлоу отчаянно искали базу данных по пути C:\projects\ai-agents\admin-agent\database\admin_agent.db. Windows-путь. На Linux-сервере, разумеется, ничего такого не было.
Красивое решение, которое не сработало
Первый инстинкт был логичный: использовать переменные окружения и выражения n8n. Добавили DATABASE_PATH=/data/admin_agent.db в docker-compose.yml, развернули воркфлоу с выражением $env.DATABASE_PATH в конфиге SQLite-ноды, нажали на кнопку деплоя и… всё равно падало. Выяснилось, что в n8n v2.4.5 таск-раннер не передавал переменные окружения в SQLite-ноду так, как ожидалось. Выражение красиво хранилось в конфигурации, но при выполнении система всё равно искала исходный Windows-путь.
Пришлось отказаться от элегантности в пользу надёжности.
Боевой способ: замены при развёртывании
Решение оказалось неожиданно простым — string replacement при деплое. Разработал скрипт deploy/deploy-n8n.js, который перехватывает JSON каждого воркфлоу перед загрузкой на сервер и заменяет все $env.DATABASE_PATH на реальный абсолютный путь /var/lib/n8n/data/admin_agent.db. Скучно? Да. Предсказуемо? Абсолютно.
Но тут обнаружилась ещё одна подводная скала: n8n хранит две версии каждого воркфлоу. Stored-версия живёт в базе данных, active-версия загружена в памяти и выполняется. Когда обновляешь воркфлоу через API, обновляется только хранилище. Active может остаться со старыми параметрами. Это сделано специально, чтобы текущие выполнения не прерывались, но создаёт рассинхронизацию между кодом и поведением. Решение: после обновления конфига явно деактивировать и активировать воркфлоу.
Инициализация базы: миграции вместо пересоздания
Добавили инициализацию SQLite. Скрипт SSH копирует на сервер SQL-миграции (schema.sql, seed_questions.sql) и выполняет их через n8n API перед активацией воркфлоу. Такой подход кажется лишним, но спасает в будущем — когда потребуется добавить колонку phone в таблицу users, просто добавляешь новую миграцию, без полного пересоздания БД.
Теперь весь деплой сводится к одной команде: node deploy/deploy-n8n.js --env .env.deploy. Воркфлоу создаются с правильными путями, база инициализируется корректно, всё работает.
Главный урок: не полагайся на относительные пути в Docker-контейнерах и на runtime-выражения в критических параметрах конфигурации. Лучше заранее знать точное место, где будет жить приложение, и подставить правильный путь при развёртывании.
«Ну что, SQLite, теперь-то ты найдёшь свою базу?» — спросил я у логов. SQLite ответил тишиной успеха. 😄
Метаданные
- Session ID:
- grouped_C--projects-bot-social-publisher_20260207_1902
- Branch:
- main
- Dev Joke
- Что Copilot сказал после обновления? «Я уже не тот, что раньше»
Часть потока:
Разработка: bot-social-publisher