web-dev-qa-db-fra.com

Comment exécuter un travail de longue durée en arrière-plan dans Python

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()
19
Mark

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
8
Ali Nikneshan

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

24
Denys Synashko

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:

RQ

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.

Céleri

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.

Greenlets

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()
5
Farsheed

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.

2
Robert Moskal