Estamos usando fastapi-utils para tener una tarea programada en segundo plano. Verificamos los 5 segundos si hay nuevos datos disponibles en la base de datos, si es así, los procesamos (toma hasta 5 minutos)
Durante este tiempo, la rutina debe estar bloqueada para que solo se active una vez.
Notamos que nuestros datos a veces se procesan 3 veces, asumimos que el programador continúa ejecutándose, aunque la función se haya activado.
Por lo tanto, intentamos eludirlo con la variable IsRunningQuery
.
Probamos una solución con un ciclo while True sin @repeat_every
para que se ejecute una vez al inicio, pero Azure Webapps no permite ejecutarlo.
@app.on_event("startup") @repeat_every(wait_first=True,seconds=int(10)) def scheduled_task() -> None: global IsRunningQuery global LastCheck if IsRunningQuery == False: IsRunningQuery = True gunicorn_logger.info("status='checkforleads'") OurProccessingClass.processDataBaseData() # can take up 5 minutes LastCheck=Utils.datetime() IsRunningQuery = False
Esta variante funciona en nuestro entorno DEV, pero no en Azure
@app.on_event("startup") async def scheduled_task() -> None: while True: gunicorn_logger.info("status='checkforleads'") OurProccessingClass.processDataBaseData() # can take up 5 minutes time.sleep(int(os.environ["CRM_SLEEP"]))
Para realizar esta tarea, necesita algún sistema de bloqueo, pero que sea adecuado para su entorno.
Por ejemplo, cuando se ejecuta solo un único trabajador, con un solo ciclo asíncrono, sería ideal un Lock
simple de las primitivas de sincronización asíncrona...
Pero si desea introducir más trabajadores, el estado del bloqueo no se sincronizará entre las instancias. Si sus trabajadores se generan en el mismo sistema, puede usar un bloqueo del sistema de archivos (por ejemplo, el del módulo fnctl
), pero nuevamente, ya no funcionará si introduce más instancias de servidor.
El siguiente paso puede ser introducir un bloqueo a nivel de base de datos, o cualquier otro sistema externo que sea capaz de gestionar un bloqueo o entregar alguna tarea a un solo destinatario, pero esto se complicará mucho muy rápidamente.
Por eso, hay sistemas como celery que te permitirán programar tareas y el sistema se encargará de evitar, si es posible, que esta tarea se ejecute varias veces (ten en cuenta que esto no siempre es posible, ya que el ejecutor puede, por ejemplo, terminar la tarea). pero nunca actualice el estado de la tarea debido a algún error fatal o cualquier otra interrupción, como pérdida de energía. Es por eso que ese tipo de sistemas pueden garantizar que la tarea se ejecutará al menos una vez o que se ejecutará como máximo una vez, pero nunca garantizará ambos, solo hará lo mejor para maximizar las posibilidades del otro).
Parece que debería considerar un proceso de trabajo separado que ejecute esta costosa llamada a la base de datos. Esto puede ser un simple script de Python que llama periódicamente a su función dB.
Usted menciona que está usando Azure Web Stack, esto es lo que encontré en los documentos/ https://docs.microsoft.com/en-us/azure-stack/operator/azure-stack-app-service-add-worker- roles?view=azs-2108&tabs=az
Buena suerte, háganos saber dónde llegó a esto :)