J'ai un service Web qui exécute des travaux de longue durée (de l'ordre de plusieurs heures). Je développe cela en utilisant Flask, Gunicorn et nginx.
Ce que je pense faire, c'est d'avoir la route qui prend beaucoup de temps à terminer, appeler une fonction qui crée un thread. La fonction renverra ensuite un guide vers l'itinéraire et l'itinéraire renverra une URL (à l'aide du guide) que l'utilisateur pourra utiliser pour vérifier la progression. Je fais du thread un démon (thread.daemon = True) afin que le thread se termine si mon code d'appel se termine (de manière inattendue).
Est-ce la bonne approche à utiliser? Cela fonctionne, mais cela ne signifie pas qu'il est correct.
my_thread = threading.Thread(target=self._run_audit, args=())
my_thread.daemon = True
my_thread.start()
L'approche la plus régulière pour gérer un tel problème est d'extraire l'action de l'application de base et de l'appeler à l'extérieur, en utilisant un système de gestionnaire de tâches comme Celery .
En utilisant this tutoriel, vous pouvez créer votre tâche et la déclencher à partir de votre application Web.
from flask import Flask
app = Flask(__name__)
app.config.update(
CELERY_BROKER_URL='redis://localhost:6379',
CELERY_RESULT_BACKEND='redis://localhost:6379'
)
celery = make_celery(app)
@celery.task()
def add_together(a, b):
return a + b
Ensuite, vous pouvez exécuter:
>>> result = add_together.delay(23, 42)
>>> result.wait()
65
N'oubliez pas que vous devez exécuter Worker séparément:
celery -A your_application worker
Le céleri et le RQ sont en sur-ingénierie pour tâche simple . Jetez un œil à ces documents - https://docs.python.org/3/library/concurrent.futures.html
Vérifiez également l'exemple, comment exécuter des travaux de longue durée en arrière-plan pour Flask app - https://stackoverflow.com/a/39008301/5569578
Eh bien, bien que votre approche ne soit pas incorrecte, fondamentalement, cela peut conduire votre programme à manquer de threads disponibles. Comme ALi mentionné, une approche générale consiste à utiliser des files d'attente de travaux comme RQ
ou Celery
. Cependant, vous n'avez pas besoin d'extraire des fonctions pour utiliser ces bibliothèques. Pour Flask, je vous recommande d'utiliser Flask-RQ . C'est simple de commencer:
pip install flask-rq
N'oubliez pas d'installer Redis avant de l'utiliser dans votre Flask app.
Et utilisez simplement @Job Decorator dans vos fonctions Flask:
from flask.ext.rq import job
@job
def process(i):
# Long stuff to process
process.delay(3)
Et enfin, vous avez besoin de rqworker
pour démarrer le travailleur:
rqworker
Vous pouvez voir RQ docs pour plus d'informations. RQ conçu pour des processus simples et de longue durée.
Le céleri est plus compliqué, possède une énorme liste de fonctionnalités et n'est pas recommandé si vous êtes nouveau dans les files d'attente de travaux et les méthodes de traitement réparties.
Les greenlets ont des interrupteurs. Vous permet de basculer entre les processus longs. Vous pouvez utiliser des greenlets pour exécuter des processus. L'avantage est que vous n'avez pas besoin de Redis et d'autres travailleurs, mais que vous devez reconcevoir vos fonctions pour qu'elles soient compatibles:
from greenlet import greenlet
def test1():
print 12
gr2.switch()
print 34
def test2():
print 56
gr1.switch()
print 78
gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()
Votre approche est correcte et fonctionnera totalement, mais pourquoi réinventer le travailleur en arrière-plan pour les applications Web python lorsqu'une solution largement acceptée existe, à savoir le céleri).
J'aurais besoin de voir beaucoup de tests avant de faire confiance à n'importe quel code maison pour une tâche aussi importante.
De plus, le céleri vous offre des fonctionnalités telles que la persistance des tâches et la possibilité de répartir les employés sur plusieurs machines.