Supongamos que tengo un modelo Event
. Quiero enviar una notificación (correo electrónico, push, lo que sea) a todos los usuarios invitados una vez que haya transcurrido el evento. Algo en la línea de:
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")
Ahora, por supuesto, la parte crucial es invocar onEventElapsed
cuando sea timezone.now() >= event.end
. Tenga en cuenta que end
podrían estar a meses de la fecha actual.
He pensado en dos formas básicas de hacer esto:
Usar un
cron
trabajo periódico (digamos, cada cinco minutos más o menos) que verifica si ha transcurrido algún evento en los últimos cinco minutos y ejecuta mi método.Utilice
celery
y programeonEventElapsed
utilizando eleta
parámetro que se ejecutará en el futuro (dentro delsave
método de modelos ).
Considerando la opción 1, podría ser una posible solución django-celery-beat
. Sin embargo, parece un poco extraño ejecutar una tarea en un intervalo fijo para enviar notificaciones. Además, se me ocurrió un problema (potencial) que (probablemente) resultaría en una solución no tan elegante:
- ¿Verifica cada cinco minutos los eventos que han transcurrido en los últimos cinco minutos? parece inestable, tal vez algunos eventos se pierdan (¿u otros reciben sus notificaciones enviadas dos veces?) Solución alternativa potencial: agregue un campo booleano al modelo que se establece
True
una vez que se han enviado las notificaciones.
Por otra parte, la opción 2 también tiene sus problemas:
- Cuide manualmente la situación cuando se mueve una fecha / hora de inicio / finalización de un evento. Cuando se usa
celery
, uno tendría que almacenartaskID
(easy, ofc) y revocar la tarea una vez que las fechas hayan cambiado y emitir una nueva tarea. Pero he leído que el apio tiene problemas (específicos de diseño) cuando se trata de tareas que se ejecutan en el futuro: Open Issue en github . Me doy cuenta de cómo sucede esto y por qué es todo menos trivial de resolver.
Ahora, he encontrado algunas bibliotecas que podrían resolver mi problema:
- celery_longterm_scheduler (¿Pero esto significa que no puedo usar el apio como lo hubiera hecho antes, debido a la diferente clase de Scheduler? Esto también se relaciona con el posible uso de
django-celery-beat
... Usando cualquiera de los dos marcos, ¿aún es posible poner trabajos en cola? ¿son solo un poco más largos pero no faltan meses?) - django-apscheduler , usos
apscheduler
. Sin embargo, no pude encontrar ninguna información sobre cómo manejaría las tareas que se ejecutan en el futuro lejano.
¿Hay un defecto fundemantal con la forma en que me estoy acercando a esto? Estoy contento por cualquier entrada que pueda tener.
Aviso: Sé que es probable que esto se base en alguna opinión, sin embargo, tal vez hay algo muy básico que me he perdido, independientemente de lo que algunos puedan considerar feo o elegante.
fuente
Respuestas:
Estamos haciendo algo así en la empresa para la que trabajo, y la solución es bastante simple.
Tenga un ritmo de cron / apio que se ejecuta cada hora para verificar si es necesario enviar alguna notificación. Luego envíe esas notificaciones y márquelas como hechas. De esta manera, incluso si su tiempo de notificación se adelanta años, aún se enviará. Usar ETA NO es el camino a seguir durante un tiempo de espera muy largo, su caché / amqp podría perder los datos.
Puede reducir su intervalo según sus necesidades, pero asegúrese de que no se superpongan.
Si una hora es una gran diferencia horaria, entonces lo que puede hacer es ejecutar un programador cada hora. La lógica sería algo como
Usar esa metodología te llevaría a los dos mejores mundos (eta y beat)
fuente