Пользователи, заказы или сессии обнулились после перезапуска или обновления бота на Bothost. Файл базы при этом «создаётся заново» без ошибки. Ниже почему так происходит с SQLite и куда писать файл, чтобы он пережил деплой.
Для людей и ИИ. Каноническая страница: https://bothost.ru/docs/sqlite-data-lost · Markdown: https://bothost.ru/docs/sqlite-data-lost.md · Индекс: https://bothost.ru/llms.txt
Отвечает на запросы: SQLite database disappeared, bot loses data after restart, database reset after deploy, bot.db empty, data lost on reboot, /app/data.
Как устроена папка и примеры создания таблиц: хранение базы данных.
Что на Bothost сохраняется
Между пересборками сохраняется каталог/app/data. Он подключён отдельным томом. Платформа задаёт переменную DATA_DIR=/app/data.
Файл в другом месте живёт в слое контейнера или в каталоге, который при новом деплое заменяется кодом из Git:
/app/bot.db,./bot.db,database.sqliteрядом со скриптом;/tmp/...;- путь внутри репозитория, который приходит из коммита;
- база
:memory:.
/app/data при этом остаётся, всё остальное пропадает. Пустая база выглядит как пропажа: SQLite не сообщает об ошибке, а создаёт новый файл.
Проверка в панели: откройте файловый менеджер бота и найдите базу именно в папке data. Если после сообщений пользователей файла там нет, процесс пишет мимо тома.
SQLite database disappeared
Относительный путь
sqlite3.connect("bot.db")/app/bot.db, а том смонтирован в /app/data. После деплоя в /app снова лежит код из репозитория, старого bot.db там нет, библиотека создаёт пустой.
Пишите в каталог данных:
import os
import sqlite3
from pathlib import Path
data_dir = Path(os.environ.get("DATA_DIR", "/app/data"))
data_dir.mkdir(parents=True, exist_ok=True)
db_path = data_dir / "bot.db"
conn = sqlite3.connect(db_path)
conn.execute(
"CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)"
)
conn.commit()connect("bot.db") или connect("/tmp/bot.db") заводит другую, пустую базу, и кажется, что данные «то есть, то нет».
Задайте путь одной переменной в панели, если так удобнее читать код: DATABASE_PATH=/app/data/bot.db.
База в Git затирает живые данные
Файлbot.db закоммичен в репозиторий. При обновлении код из Git копируется в приложение, и вместе с ним приезжает старая или пустая база из коммита. Папку data в Git не кладут. Добавьте в .gitignore:
data/
*.db
*.sqlite
*.sqlite3/app/data. Если база уже была в корне репозитория, перенесите её один раз через файловый менеджер панели в data, поправьте путь в коде и уберите файл из коммита, иначе следующее обновление вернёт старую копию.
:memory: и новый файл на каждый процесс
sqlite3.connect(":memory:") существует, пока живёт этот процесс. Рестарт контейнера начинает с пустой базы. То же самое делает код, который при каждом старте удаляет файл и создаёт таблицы заново без проверки. CREATE TABLE IF NOT EXISTS таблицу сохраняет. DROP TABLE и os.remove(db_path) при каждом запуске данные стирают, даже если путь правильный.
bot loses data after restart
Файл в/app/data на месте, а последней записи нет.
Не было commit. execute без commit() держит изменение в транзакции. Процесс убили рестартом, транзакция откатилась. Фиксируйте изменения, которые нельзя потерять:
conn.execute("INSERT INTO users (name) VALUES (?)", (name,))
conn.commit()bot.db-wal и bot.db-shm. Если скопировали в другое место только bot.db, последние записи остаются в -wal. Для работы на томе копировать ничего не нужно: все три файла и так в /app/data. В резервную копию забирайте каталог целиком, либо перед копированием выполните checkpoint.
Рестарт случился в середине записи. Короткая транзакция и commit() на каждое законченное действие уменьшают потерю до последней незафиксированной операции. Отдельный сервер MySQL или PostgreSQL имеет смысл, когда базы много и писателей несколько. Сам файл SQLite на томе /app/data для одного процесса бота как раз рассчитан на рестарты контейнера.
Права на каталог образ выставляет при сборке. Если в логе attempt to write a readonly database или unable to open database file, процесс не может создать файл в выбранном пути. Верните путь на /app/data/... и задеплойте снова. Разбор через терминал панели: SQLite в терминале.
Как понять, что путь верный
- В логе старта напечатайте абсолютный путь:
print(db_path). - Строка должна начинаться с
/app/data/. - После сообщения боту файл виден в файловом менеджере в папке
dataи его размер больше нуля. - Сделайте обновление из Git или залейте новый архив и откройте ту же базу. Старые строки на месте.
/app/bot.db или bot.db, следующий деплой базу обнулит, даже если прямо сейчас после кнопки «перезапуск» данные ещё видны.
См. также
Файл в/app/data есть, а записей нет? Пришлите в поддержку строку пути из лога и момент, после которого данные пропали: @bothostru.