Почему на сервере разрывается соединение с базой данных?

2026-06-18 00:47:53 [ERROR] ❌ Ошибка открытия БД: unable to open database file <br/> 2026-06-18 00:47:53 [ERROR] Ошибка в цикле: unable to open database file <br/> Traceback (most recent call last): <br/> File "/root/Bot/bot.py", line 3508, in run <br/> File "/root/Bot/bot.py", line 3132, in clean_old_signals <br/> File "/root/Bot/bot.py", line 198, in _get_connection <br/> sqlite3.OperationalError: unable to open database file <br/> <br/> Бот мониторит рынок и, обращаясь к БД, рассылает данные. Через некоторое время он теряет подключение к БД и появляется приведённая выше ошибка; затем подключение восстанавливается. В чём может быть причина этой проблемы и как её исправить?
  • 18 июня 2026 г. 9:02
Ответы на вопрос 2
Коротко — ошибка sqlite3.OperationalError: "unable to open database file" означает, что в момент обращения к файлу БД ОС/файловая система не позволила открыть файл. Разрыв и последующее восстановление указывает на временную проблему в системе (правами, доступностью файла, монтированием, исчерпанием дескрипторов и т.п.), а не на «слет» самого sqlite как такового. Возможные причины и шаги диагностики/исправления:

Возможные причины
- Неправильный путь или относительный путь: рабочая директория процесса меняется, файл не находится по указанному относительному пути.  
- Права доступа/владелец: процесс не имеет прав читать/писать файл или директорию.  
- Файловая система стала «недоступной» на время: диск отмонтирован/перемонтирован, смонтирован как read‑only (kernel remount), или файл находится на NFS/SMB, где блокировки не работают корректно.  
- Недостаток дискового пространства или инодов (df -h, df -i).  
- Лимит открытых файлов (ulimit -n) или утечка дескрипторов: процесс исчерпал fd и не может открыть новый файл.  
- Конкуренция/блокировки: большой параллелизм (много процессов/потоков) и sqlite не справляется с одновременными записями; синхронные блокировки приводят к ошибкам.  
- Бэкапы/логика ротации: скрипт/backup/логротейт перемещает или блокирует файл в момент обращения.  
- SELinux/AppArmor/антивирус: политики запретили доступ временами.  
- Файловая система временная (tmpfs) или очищается cron’ом (например /tmp).  
- Повреждение файла/файловой системы или OOM/kernel remount read‑only — тогда FS может становиться недоступной на некоторое время.

Диагностика (что проверить прямо сейчас)
- Проверить свободное место и иноды:
  - df -h /path/to/db
  - df -i /path/to/db
- Проверить права и владельца:
  - ls -l /path/to/db
  - ls -ld /path/to  (директория)
- Проверить как смонтирован диск:
  - mount | grep "$(dirname /path/to/db)"
  - или findmnt /path/to/db
  - если NFS/SMB — вероятная проблема блокировок.
- Проверить логи ядра на ошибки диска/ремонта:
  - dmesg | tail -n 50
  - journalctl -k -n 200
- Проверить логи systemd/syslog на remount/read-only, OOM и т.п.
- Проверить лимиты и открытые файлы:
  - sudo ls -l /proc/$(pidof python)/fd | wc -l
  - cat /proc/$(pidof python)/limits  (или ulimit -n)
  - lsof | grep /path/to/db
- Посмотреть, не перемещают ли файл/директорию бэкап/логрутейты/cron:
  - grep -R "/path/to/db" /etc/cron* /etc/logrotate.d  и т.п.
- Если в контейнере/Docker — проверить mounts/volumes и логи контейнера.
- Проверить SELinux:
  - sestatus  или journalctl | grep AVC

Краткие быстрые исправления (быстро применить)
- Использовать абсолютный путь к файлу БД в коде (без относительных путей).  
- Убедиться, что файл и папка имеют корректного владельца/права (пользователь, от которого запускается бот, должен иметь rwx на директорию и rw на файл).  
- Если проблема — на NFS/SMB, перенести SQLite-файл на локальный диск (ext4) или использовать СУБД клиент‑сервер (Postgres/MySQL).  
- Увеличить timeout при подключении sqlite: sqlite3.connect(path, timeout=30) — это заставит ждать при блокировках, вместо мгновенной ошибки.  
- Включить WAL-режим для лучшей работы с параллельным чтением: PRAGMA journal_mode=WAL; но на NFS WAL не рекомендован.  
- Добавить повторные попытки подключения с экспоненциальным бэкофом в коде (retry при OperationalError).  
- Закрывать соединения корректно и переиспользовать соединение вместо многократного открытия/закрытия (connection pooling в пределах процесса).

Архитектурные/долгосрочные решения
- Если это многопроцессное/высоконагруженное приложение с частыми записями — перейти на клиент‑серверную СУБД (Postgres/MySQL). SQLite хорошо для встраиваемых/низконапряжённых сценариев, но не для высокого параллелизма.  
- Если хотите оставить SQLite: держать одну «writer» задачи (через очередь) и позволять остальным только читать; или использовать единую библиотеку/модуль, координирующий доступ.  
- Настроить мониторинг диска/инодов и лимитов fd, чтобы заранее видеть проблему.

Пример мелкой доработки в Python (повтор попытки + абсолютный путь + timeout)
- Использовать абсолютный путь:
  - db = sqlite3.connect("/var/lib/mybot/mydb.sqlite", timeout=30, check_same_thread=False)
- Пример retry:
  - for i in range(5):
      try:
          conn = sqlite3.connect(db_path, timeout=30)
          break
      except sqlite3.OperationalError as e:
          time.sleep(2 ** i)
  - if conn is None: лог / аварийное завершение

Что делать дальше / если хотите — присылайте
- Вывод результата команд: df -h, df -i, ls -l /path/to/db, mount | grep /path/to, dmesg | tail, ulimit -n или /proc/<pid>/limits, а также информацию о том, запускается ли бот в контейнере, на NFS, или есть ли множественные процесс/потоки, и я помогу конкретнее.

Если коротко: сначала проверьте права, диск/иноды, монтирование (особенно NFS) и лимиты дескрипторов; чаще всего в таких случаях причина — файл на сетевом/эпhemeral хранилище или исчерпание ресурсов/прав.
Скорее диск на aeza иногда забивается — <code>df -h</code> при следующей ошибке сразу глянь. SQLite не может создать journal/WAL файл при 0 свободных байт, отсюда "unable to open" вместо "database is locked". Если диск ок — проверь утечку fd: бот должен закрывать соединения через <code>connection.close()</code> или контекстный менеджер, иначе лимит исчерпывается.
Похожие вопросы