Предположим, у меня есть модель Event
. Я хочу отправить уведомление (электронная почта, push, что угодно) всем приглашенным пользователям после того, как событие прошло. Что-то вроде:
class Event(models.Model):
start = models.DateTimeField(...)
end = models.DateTimeField(...)
invited = models.ManyToManyField(model=User)
def onEventElapsed(self):
for user in self.invited:
my_notification_backend.sendMessage(target=user, message="Event has elapsed")
Теперь, конечно, важная часть - это вызывать onEventElapsed
всякий раз, когда timezone.now() >= event.end
. Имейте в виду, end
могут быть месяцы от текущей даты.
Я думал о двух основных способах сделать это:
Используйте периодическое
cron
задание (скажем, каждые пять минут или около того), которое проверяет, произошли ли какие-либо события за последние пять минут, и выполняет мой метод.Используйте
celery
и запланируйте,onEventElapsed
используяeta
параметр для запуска в будущем (в рамкахsave
метода моделей ).
Учитывая вариант 1, потенциальное решение может быть django-celery-beat
. Тем не менее, кажется немного странным запускать задачу с фиксированным интервалом для отправки уведомлений. Кроме того, я пришел к (потенциальной) проблеме, которая (вероятно) приведет к не очень элегантному решению:
- Проверять каждые пять минут на события, которые произошли в предыдущие пять минут? кажется шатким, может быть, некоторые события пропущены (или другие получают свои уведомления дважды?). Потенциальная работа: добавьте логическое поле в модель, для которого задано значение
True
после отправки уведомлений.
Опять же, вариант 2 также имеет свои проблемы:
- Вручную позаботьтесь о ситуации, когда время начала / окончания события перемещено. При использовании
celery
нужно было бы сохранитьtaskID
(easy, ofc) и отозвать задачу, как только даты изменились, и выпустить новую задачу. Но я читал, что у сельдерея есть (специфичные для дизайна) проблемы при работе с задачами, которые будут выполняться в будущем: Открытая проблема на github . Я понимаю, как это происходит и почему это все, но тривиально, чтобы решить.
Теперь я столкнулся с некоторыми библиотеками, которые потенциально могут решить мою проблему:
- celery_longterm_scheduler (Но значит ли это, что я не могу использовать celery, как раньше, из-за другого класса Scheduler? Это также связано с возможным использованием
django-celery-beat
... При использовании любой из двух структур все еще можно ставить в очередь задания (что только немного дольше, но не через несколько месяцев?) - Джанго-Апшедулер , использует
apscheduler
. Тем не менее, я не смог найти никакой информации о том, как он будет обрабатывать задачи, которые выполняются в далеком будущем.
Есть ли какой-то фундаментальный недостаток в том, как я к этому подхожу? Я рад за любой вклад, который вы могли бы иметь.
Обратите внимание: я знаю, что, скорее всего, это будет основано на некотором мнении, но, может быть, есть одна очень простая вещь, которую я пропустил, независимо от того, что некоторые могут считать уродливыми или изящными.
источник
Ответы:
Мы делаем что-то подобное в компании, в которой я работаю, и решение довольно простое.
Имейте ритм cron / сельдерея, который запускается каждый час, чтобы проверить, нужно ли отправлять какие-либо уведомления. Затем отправьте эти уведомления и отметьте их как выполненные. Таким образом, даже если ваше уведомление будет на несколько лет вперед, оно все равно будет отправлено. Использование ETA НЕ является подходом для очень долгого времени ожидания, ваш кеш / amqp может потерять данные.
Вы можете уменьшить интервал в зависимости от ваших потребностей, но убедитесь, что они не перекрываются.
Если один час слишком большой из-за разницы во времени, то вы можете запускать планировщик каждый час. Логика была бы что-то вроде
Использование этой методологии даст вам оба лучших мира (eta и beat)
источник