Есть ли способ запустить отдельный рабочий процесс цикла, который ссылается на модели приложения Django? - PullRequest
0 голосов
/ 11 июля 2020

У меня есть веб-приложение, которое отслеживает добавленные пользователями сайты на предмет любых изменений. Для этого мне нужен какой-то отдельный фоновый поток / процесс, который постоянно просматривает список сайтов, проверяет их по одному и отправляет электронные письма всем пользователям, которые следят за сайтом, который изменяется. В настоящее время я использую поток, который инициализирую в конце моего файла urls.py. Это отлично работает с сервером разработки Django, но он начинает ломаться, когда я развертываю его на Heroku с помощью Gunicorn. Как только есть несколько подключений, запускается несколько копий рабочего потока, поскольку Gunicorn запускает больше рабочих потоков для обработки одновременных подключений (по крайней мере, это то, что я считаю причиной появления дополнительных потоков). Это приводит к отправке дублирующих писем, по одному из каждого потока.

Сейчас я пытаюсь найти другое средство для создания этого рабочего потока / процесса. Я видел похожий запрос здесь , но когда я попробовал опубликованное решение, я не смог сослаться на модели из моего приложения Django и получил это сообщение об ошибке, когда я попытался сделать это:

django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.

Я также пробовал использовать django-background-tasks, который часто рекомендуется как простое решение для подобных проблем. Однако он не подходит для циклических, непрерывных процессов. То же самое касается сельдерея и других подобных средств. Я просто ищу способ запустить отдельный рабочий Dyno, который непрерывно работает в фоновом режиме, без очереди или чего-то подобного, и может использовать модели из моего приложения Django для создания QuerySets, которые можно повторять. Как лучше всего сделать что-то подобное? Пожалуйста, дайте мне знать, если вам понадобится дополнительная информация.

1 Ответ

1 голос
/ 11 июля 2020

Вы можете попробовать отредактировать код так, чтобы части, которые обрабатывают электронную почту, не были бы так встроены в модель django, так что и модель django, и это вторичное приложение взаимодействуют со стандартом python class / module / object / et c, вместо того, чтобы пытаться привить часть django, которая вам нужна в другом месте.

В качестве альтернативы вы можете попробовать использовать что-то вроде threading.Lock если ваше приложение фактически использует потоки внутри одного интерпретатора, чтобы предотвратить отправку нескольких сообщений. Существует также multiprocessing.Lock , который может работать, если потоковый не работает.

Другой вариант - сделать так, чтобы каждое запрошенное изменение имело уникальное значение, желательно что-то исходя из содержания самих изменений. IE, если у вас есть что-то вроде:

def check_send_email(email_addr, website_url, text_that_changed):
    database.query('INSERT INTO website_updates VALUES %s, %s', (website_url, text_that_changed,))

    if (database.check_result()):  # update was not already present in database
        send_email(email_addr)

check_send_email('email@example.com', 'website.com', '<div id="watched-div">')

, очевидно, вам нужно взаимодействовать с некоторыми более конкретными инструментами, но общая идея выше заключается в том, что при поступлении запросов вы не отправляете несколько писем напрасно. Конечно, найти значение, которое вы всегда можете сгенерировать точно такое же, при заданном c изменении, но оно также будет уникальным каждый раз, что может оказаться затруднительным.

...