При длительном выполнении задач 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()
Обычно задача может выполняться примерно следующим образом:
- Получение всей информации, необходимой для обработки фактической задачи, например, получение объекта файлов из базы данных или т.п.
- Обработать данные, например, конвертировать видео, что может занять несколько часов.
- Обновление данных в базе данных после того, как видео было преобразовано.
На этапе 3 вы, скорее всего, потерпите неудачу, так как соединение с базой данных не работает. Поэтому сразу после того, как видео будет сконвертировано и вы захотите обновить материал в базе данных, просто закройте все старые соединения с базой данных следующим образом:
...
close_old_connections()
try:
Files.objects.filter(pk=files_obj).update(
### Update some fileds here.
)
...
Вы также можете сказать, что в целом это хорошая практика - закрывать старые соединения (close_old_connections()) если вы можете ожидать, что действие будет выполняться дольше, где все происходит в одной функции, как в задаче celery.
"Здоровья"