Как выполнять отложенные задачи на бекенде?

Почти в каждом вебсервисе, где есть регистрация пользователей и какое-либо их состояние такая задача существует. Например, "золотой" статус, premium статус. Пользователь платит деньги, его статус меняет, устанавливается дата окончания: через месяц, год. Вопрос в том, как увидеть, что время истекло и вернуть пользователя в обычное состояние. Я привел только пример, можно придумать и другие.
Так, сходу, могу придумать два решения:
  1. Написать отдельный демон, который раз в n времени проверяет список задач (или дату окончания золотого статуса из моего примера) и изменяет состояния
  2. То же самое, только в качестве демона cron

Как обычно такие задачи решаются? Какая-нибудь очередь задачь, типа Celery, подойдет?
  • Вопрос задан
  • 4157 просмотров
Пригласить эксперта
Ответы на вопрос 3
Альтернативный подход - вообще не хранить текущий статус пользователя. Вместо этого, хранить журнал изменений этого статуса и вычислять его текущее значение по требованию. Мне привычно рассуждать в терминах Django, на её ORM и будем ориентироваться. Пусть у вас есть своя собственная модель для пользователя - User в приложении my_auth. Пусть у него может быть два значения статуса: пустое (None) и premium - для тех, кто оплатил подписку на год. Журнал изменений статуса:

from django.db import models
from my_auth.models import User

class StatusEvent(models.Model):
    EVENT_TYPES = [
        ('subscription', 'User subscribed to premium')
    ]
    user = models.ForeignKey(User, related_name='events')
    time = models.DateTimeField(auto_now_add=True)
    type = models.CharField(max_length=16, choices=EVENT_TYPES)

    class Meta:
        ordering = '-time'


Функция вычисления статуса определена в модели User:

from datetime import datetime
from django.contrib.auth.models import User as DefaultUser

class User(DefaultUser):
    @property
    def status(self):
        event = self.events.filter(type='subscription').first()
        if event and datetime.now() - event.time < self.subscription_duration:
            return 'premium'


Здесь subscription_duration - длительность действия подписки, значение типа datetime.timedelta. Ну или relativedelta из dateutil можно использовать, оно удобней. Да, это влечёт постоянные проверки статуса, но не думаю, что это такая уж большая проблема в сравнении с тем, чтоб городить ещё один процесс крона или Celery, чрезмерно усложняя систему.
Ответ написан
Комментировать
WebSpider
@WebSpider
А cron чем не устраивает? По-моему самое адекватное решение в данной ситуации
Ответ написан
@LiguidCool
Честно говоря не знаю как делают "в лучших домах...", но я просто cron'ом делал wget php страницы, в которой был нужный код.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы