При длительном выполнении задач Celery возникает ошибка ConnectionResetError: [Errno 104] Соединение сброшено сверстником

В моем Django-приложении я использую Celery для обработки очень долго выполняющихся задач. Одна из этих задач должна в самом конце записать запись в базу данных, чтобы подтвердить, что процесс завершен. По какой-то причине, если задача выполняется очень долго (здесь речь идет о 4 часах или более). я получаю следующее:

ConnectionResetError: [Errno 104] Connection reset by peer

Это происходит, как только я запускаю операцию записи в базу данных в самом конце задачи, например:

 Files.objects.filter(pk=files_obj).update
 ... etc

Было бы интересно узнать, почему пир сбрасывает соединение (MariaDB в моем случае). Разве Django не управляет соединениями с базой данных для меня, используя пул соединений? Я также проверил свой конфиг Redis на стороне Django, где, на мой взгляд, только эти строки имеют значение:

BROKER_TRANSPORT_OPTIONS = {'visibility_timeout': 86400}  # 24 hrs.
CELERYD_TASK_TIME_LIMIT = 86400  # 24 Hrs.
CELERYD_TASK_SOFT_TIME_LIMIT = 86400  # 24 Hrs.

Не существует ли способа заставить функцию запускать новое соединение или что-то в этом роде? Мне кажется, что задача Celery сохраняет SQL-соединение живым до тех пор, пока выполняется задача. Но бэкенд БД не соблюдает это так долго.

Вот как я запускаю своего работника Celery:

celery -A App worker --pool=gevent --concurrency=4 --loglevel INFO --pidfile= --schedule=/home/$OS_USER/celery-schedule

Заранее спасибо.

Нашел решение, извините за поздний ответ. По сути, Django управляет SQL соединением с помощью пула соединений. Он делает это по умолчанию для вас. Это хорошо, но в моем случае это привело к тому, что соединение пула с базой данных разрывалось, вызывая ошибку "Connection reset by peer".

Чтобы решить эту проблему, нужно просто вызвать следующее:

close_old_connections()

Обычно задача может выполняться примерно следующим образом:

  1. Получение всей информации, необходимой для обработки фактической задачи, например, получение объекта файлов из базы данных или т.п.
  2. Обработать данные, например, конвертировать видео, что может занять несколько часов.
  3. Обновление данных в базе данных после того, как видео было преобразовано.

На этапе 3 вы, скорее всего, потерпите неудачу, так как соединение с базой данных не работает. Поэтому сразу после того, как видео будет сконвертировано и вы захотите обновить материал в базе данных, просто закройте все старые соединения с базой данных следующим образом:

...
close_old_connections()
try:
   Files.objects.filter(pk=files_obj).update(
       ### Update some fileds here.
   )
...

Вы также можете сказать, что в целом это хорошая практика - закрывать старые соединения (close_old_connections()) если вы можете ожидать, что действие будет выполняться дольше, где все происходит в одной функции, как в задаче celery.

"Здоровья"

Вернуться на верх