J'écris une application dans Flask, qui fonctionne très bien sauf qu'elle WSGI
est synchrone et bloquante. J'ai une tâche en particulier qui fait appel à une API tierce et cette tâche peut prendre plusieurs minutes. Je voudrais faire cet appel (c'est en fait une série d'appels) et le laisser fonctionner. tandis que le contrôle est retourné à Flask.
Ma vue ressemble à:
@app.route('/render/<id>', methods=['POST'])
def render_script(id=None):
...
data = json.loads(request.data)
text_list = data.get('text_list')
final_file = audio_class.render_audio(data=text_list)
# do stuff
return Response(
mimetype='application/json',
status=200
)
Maintenant, ce que je veux faire, c'est avoir la ligne
final_file = audio_class.render_audio()
run et fournissez un rappel à exécuter lorsque la méthode retourne, tandis que Flask peut continuer à traiter les requêtes. C'est la seule tâche dont j'ai besoin que Flask s'exécute de manière asynchrone, et j'aimerais avoir des conseils sur la meilleure façon de l'implémenter.
J'ai regardé Twisted et Klein, mais je ne suis pas sûr qu'ils soient exagérés, car peut-être que Threading suffirait. Ou peut-être que le céleri est un bon choix pour cela?
la source
Réponses:
J'utiliserais Celery pour gérer la tâche asynchrone pour vous. Vous devrez installer un courtier pour servir de file d'attente de tâches (RabbitMQ et Redis sont recommandés).
app.py
:Exécutez votre application Flask et démarrez un autre processus pour exécuter votre céleri.
Je ferais également référence à la rédaction de Miguel Gringberg pour un guide plus détaillé sur l'utilisation du céleri avec Flask.
la source
Le filetage est une autre solution possible. Bien que la solution basée sur Celery soit meilleure pour les applications à grande échelle, si vous ne vous attendez pas à trop de trafic sur le point final en question, le threading est une alternative viable.
Cette solution est basée sur la présentation PyCon 2016 Flask at Scale de Miguel Grinberg , en particulier la diapositive 41 de son diaporama. Son code est également disponible sur github pour ceux qui s'intéressent à la source originale.
Du point de vue de l'utilisateur, le code fonctionne comme suit:
Pour convertir un appel d'API en tâche d'arrière-plan, ajoutez simplement le décorateur @async_api.
Voici un exemple complet:
la source
Vous pouvez également essayer d'utiliser
multiprocessing.Process
avecdaemon=True
; laprocess.start()
méthode ne se bloque pas et vous pouvez renvoyer une réponse / un statut immédiatement à l'appelant pendant que votre fonction coûteuse s'exécute en arrière-plan.J'ai rencontré un problème similaire en travaillant avec le framework Falcon et en utilisant le
daemon
processus aidé.Vous devez effectuer les opérations suivantes:
Vous devriez obtenir une réponse immédiatement et, après 10 secondes, vous devriez voir un message imprimé dans la console.
REMARQUE: gardez à l'esprit que les
daemonic
processus ne sont pas autorisés à générer des processus enfants.la source
/render/<id>
endpoint attend quelque chose à la suite demy_func()
?my_func
envoyer une réponse / des pulsations à un autre point de terminaison par exemple. Ou vous pouvez établir et partager une file d'attente de messages à travers laquelle vous pouvez communiquer avecmy_func