Estoy usando el programador de tareas django + celery para ejecutar una tarea programada para una vez al mes. Pero solo quiero que esta tarea se ejecute solo durante unos pocos meses, por ejemplo, 3 meses o 6 meses o 9 meses.

¿Cómo puedo evitar que el trabajador ejecute más tareas y luego se reinicie cada vez que se llama a la tarea?

Esta es mi tarea

@task(name="add_profit")
def count():
    portfolios = Portfolio.objects.filter(status='ACTIVE')
    if portfolios.exists():
        for portfolio in portfolios:
            user = portfolio.user
            #calculates portfolio profit
            amount = portfolio.amount * 0.1
            if portfolio.duration == '3 Months':
                PortfolioProfit.objects.create(user=user, amount=amount)
                user.useraccount.account_balance += amount
                user.useraccount.save()

Y aquí está mi horario de tareas de apio

app.conf.beat_schedule = {
    # Executes 1st day of every Month.
    'every-minute': {
        'task': 'add_profit',
        # crontab can be changes to change Schedule
        # http://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html
        'schedule': crontab(0, 0, day_of_month = 1),
    },
}


0
George Tammy 9 oct. 2019 a las 19:20

3 respuestas

La mejor respuesta

Haciendo una nueva respuesta. Quiero mantener el anterior para el registro, ya que podría ayudar a otras personas que tienen un problema diferente. Para su pregunta, creo que solo tiene que llamar a la tarea de apio todos los meses sin condiciones.

Creo que sería más fácil si cambia los datos almacenados en la base de datos de tal manera que pueda identificar las carteras activas, que almacene la fecha de la primera vez y una fecha para la última vez que desea agregar automáticamente un valor.

Ahora la tarea mensual de apio identificará a los usuarios para los cuales first_date <= today <= last_date y agregará el valor si la condición es verdadera.

0
gelonida 10 oct. 2019 a las 08:16

Okay. Muchas gracias @gelonida por tu aporte. He podido lograr mi objetivo.

Creé una entrada de la base de datos de la fecha de vencimiento (3 meses, 6 meses, etc., dependiendo de la selección del usuario), que se calcula utilizando la fecha de creación de la cartera y en algún momento en el futuro de la siguiente manera:

portfolio.expiry_date = timezone.now() + timedelta(days = 93) # for 3months

Entonces en mi tarea hice esto

from django.utils import timezone


@task(name="add_profit")
def count():
    portfolios = Portfolio.objects.filter(status='ACTIVE')
    current_datetime = timezone.now()
    if portfolios.exists():
        for portfolio in portfolios:
            if current_datetime > portfolio.expiry_date:
                portfolio.status = 'COMPLETED'
                portfolio.save()
                return
            else:
                user = portfolio.user
                amount = portfolio.amount * 0.1
                PortfolioProfit.objects.create(user=user, amount=amount)
                user.useraccount.account_balance += amount
                user.useraccount.save()

Esto funcionó perfectamente para mí.

0
George Tammy 10 oct. 2019 a las 14:40

Opción 1: comienza la tarea todos los meses con una entrada crontab de apio y dentro de la tarea agrega una prueba: si la fecha actual no está dentro de un cierto rango, simplemente abandona el procesamiento.

Esto tiene una ligera sobrecarga, pero una vista aérea una vez al mes debería ser aceptable.

@task(name="add_profit")
def count():
    today = datetime.datetime.now()
    if today > datetime.datetime(2020,1, 1):
        return
    # the remaining part of your task follows here

Opción 2: ejecuta una vez (con o sin un bucle for) un pequeño fragmento de código, que programa las tareas para los meses en cuestión.

http://docs.celeryproject.org/en/latest/userguide/calling.html#eta-and-countdown

En el ejemplo a continuación, solo muestro la idea con la programación de una tarea para los próximos tres días:

today = datetime.utcnow()

for delta in range(1, 4):
    task.apply_async(args=[arg1, arg2, ...), eta=today + timedelta(days=delta))

Aquí la tarea se ejecutará exactamente con la frecuencia que desee.

Sin embargo, si migra el servidor a una ubicación diferente, si restablece rabbitmq (o el intermediario que tenga), las tareas que se programarán se perderán / desaparecerán

0
gelonida 9 oct. 2019 a las 17:30
58308382