Załóżmy, że mam model Event
. Chcę wysłać powiadomienie (e-mail, push, cokolwiek) do wszystkich zaproszonych użytkowników po zakończeniu wydarzenia. Coś w stylu:
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")
Teraz oczywiście najważniejszą częścią jest wywoływanie onEventElapsed
za każdym razem timezone.now() >= event.end
. Pamiętaj, że end
może upłynąć kilka miesięcy od bieżącej daty.
Pomyślałem o dwóch podstawowych sposobach:
Użyj okresowego
cron
zadania (powiedzmy co około pięć minut), które sprawdza, czy jakieś zdarzenia minęły w ciągu ostatnich pięciu minut i wykonuje moją metodę.Użyj
celery
i zaplanuj,onEventElapsed
używająceta
parametru do uruchomienia w przyszłości (w ramachsave
metody modeli ).
Biorąc pod uwagę opcję 1, potencjalnym rozwiązaniem może być django-celery-beat
. Jednak wydaje się nieco dziwne uruchamianie zadania w ustalonych odstępach czasu w celu wysyłania powiadomień. Ponadto wpadłem na (potencjalny) problem, który (prawdopodobnie) spowodowałby nie tak eleganckie rozwiązanie:
- Czy sprawdzać co pięć minut zdarzenia, które upłynęły w ciągu ostatnich pięciu minut? wydaje się chwiejne, może niektóre wydarzenia zostały pominięte (lub inne otrzymały dwa powiadomienia wysyłane dwukrotnie?). Potencjalne obejście: dodaj pole boolowskie do modelu, który jest ustawiony na
True
po wysłaniu powiadomień.
Z drugiej strony, opcja 2 ma również swoje problemy:
- Ręcznie zajmij się sytuacją, w której przenoszona jest data / godzina rozpoczęcia zdarzenia. Podczas korzystania
celery
należy zapisaćtaskID
(łatwe, ofc) i odwołać zadanie po zmianie dat i wydać nowe zadanie. Ale czytałem, że seler ma problemy (specyficzne dla projektu) podczas wykonywania zadań, które będą uruchamiane w przyszłości: Open Issue on github . Zdaję sobie sprawę z tego, jak to się dzieje i dlaczego rozwiązanie tego problemu jest trywialne.
Teraz natknąłem się na biblioteki, które potencjalnie mogłyby rozwiązać mój problem:
- celery_longterm_scheduler (Ale czy to oznacza, że nie mogę używać selera, tak jak wcześniej, ze względu na inną klasę Scheduler? To także wiąże się z możliwym użyciem
django-celery-beat
... Przy użyciu dowolnego z dwóch frameworków, czy nadal można kolejkować zadania (że są trochę dłużej, ale nie za kilka miesięcy?) - django-apscheduler , używa
apscheduler
. Nie udało mi się jednak znaleźć żadnych informacji o tym, jak poradzi sobie z zadaniami, które są uruchamiane w dalekiej przyszłości.
Czy jest jakiś poważny błąd w sposobie, w jaki do tego podchodzę? Cieszę się z wszelkich informacji, które możesz mieć.
Uwaga: Wiem, że prawdopodobnie jest to oparte na niektórych opiniach, jednak może brakuje mi bardzo podstawowej rzeczy, niezależnie od tego, co niektórzy mogą uznać za brzydką lub elegancką.
źródło
Odpowiedzi:
Robimy coś takiego w firmie, w której pracuję, a rozwiązanie jest dość proste.
Uderzaj w cron / seler, który jest uruchamiany co godzinę, aby sprawdzić, czy należy wysłać jakieś powiadomienie. Następnie wyślij te powiadomienia i oznacz je jako gotowe. W ten sposób, nawet jeśli czas powiadomienia upłynie o wiele lat, nadal będzie wysyłany. Korzystanie z ETA NIE jest sposobem na bardzo długi czas oczekiwania, pamięć podręczna / amqp może utracić dane.
Możesz skrócić interwał w zależności od potrzeb, ale upewnij się, że się nie pokrywają.
Jeśli jedna godzina to zbyt duża różnica czasu, co możesz zrobić, uruchom harmonogram co godzinę. Logika byłaby czymś takim
Dzięki tej metodologii uzyskasz oba najlepsze światy (eta i beat)
źródło