Traitement asynchrone avec LINE BOT: RQ (Redis Queue) en Python

J'ai créé LINE BOT, je vais donc le présenter. Le code source est sur github.

Ce que j'ai fait

C'est un LINE BOT qui vous avertit lorsque le temps entré (secondes) s'est écoulé. Ce n'est pas intéressant, mais c'était un bon sujet pour le traitement asynchrone. Ci-dessous, une capture d'écran de ce que j'ai créé, mais si vous tapez «180», vous serez averti après 180 secondes. Bien entendu, d'autres messages doivent être traités pendant ces 180 secondes.

s_timer3.PNG

Cependant, en raison des spécifications de l'API de LINE, les demandes des utilisateurs expirent dans les 180 secondes et ne peuvent pas être traitées. Ce serait bien si vous pouviez répondre avant l'expiration du délai en premier lieu, Lorsqu'une grande quantité de traitement intervient, un traitement lourd tel qu'un traitement d'image qui ne peut pas être effectué à temps, Quelque chose comme ce minuteur ne peut être traité qu'après avoir renvoyé la demande une fois.

Politique de base

Pour le moment, le serveur LINE BOT fonctionne sur heroku comme beaucoup d'autres le font. La communication SSL est essentielle pour LINE BOT, il est donc un peu gênant de se préparer soi-même, C'est parce que heroku est possible par défaut. C'est l'avantage du PaaS.

Je me suis référé à l'article suivant sur l'architecture de LINE BOT.

  1. Articles sur LINE BOT 1.1. Architecture de serveur LINE BOT sûre même si un grand nombre de messages arrivent

  2. Articles sur heroku 2.1 Worker Dynos, Background Jobs and Queueing 2.2 Background Tasks in Python with RQ

Les travailleurs d'arrière-plan pour le traitement asynchrone utilisent RQ selon 2.2. Vous avez besoin d'un serveur Redis pour utiliser RQ, mais heroku est facile car il vous suffit d'ajouter un module complémentaire appelé RedisToGo.

$ heroku addons:create redistogo

Lorsque vous effectuez LINE BOT avec RQ, si vous dessinez approximativement l'événement MessageEvent lorsqu'un message est reçu de l'utilisateur, la séquence sera comme indiqué dans la figure ci-dessous.

  1. Les demandes (ID de l'expéditeur, message, jeton de réponse) arrivent du serveur LINE vers le serveur BOT
  2. Répondre à un message au serveur de l'API LINE à l'aide du jeton de réponse (non requis)
  3. Enregistrez le travail pour le message dans RQ (Job Queue)
  4. Renvoyez 200 au serveur LINE
  5. Supprimez le travail de la file d'attente des travaux
  6. Traitez le travail
  7. Informez le serveur API LINE du résultat du travail

Ici, le message envoyé au serveur API LINE est affiché sur l'écran LINE de l'utilisateur. L'important est que le temps de 1 à 4 soit limité à la fois en termes de LINE et d'heroku. À propos, le jeton de réponse a également une date d'expiration. Si vous l'utilisez, utilisons-le rapidement. Et renvoyez immédiatement 200 au serveur LINE. Si vous connaissez l'ID de l'expéditeur, vous pouvez exécuter 5-7 à tout moment. (C'est un problème que la notification de résultat est trop tardive)

s_be5196d2-02cb-43d3-96f9-c5b8ca806f28.png

Dans ce LINE BOT, les trois processus suivants existent. Je ne pouvais pas créer de fil de minuterie pour chaque demande, j'ai donc décidé de gérer le minuteur avec Redis.

L'outil Timer n'apparaît pas dans la séquence ci-dessus, Etant donné que le worker RQ n'est exécuté que lorsque le travail est enregistré, la synchronisation du temporisateur est inconnue. Par conséquent, le travailleur du minuteur détecte si le minuteur a atteint l'heure définie et avertit le serveur API LINE.

mesures de restriction de cadre gratuit heroku

Code source de cette époque, mais cela ne fonctionnera pas avec le cadre libre d'heroku tel quel. J'ai spécifié un serveur Web et deux travailleurs en arrière-plan dans Procfile, En effet, vous ne pouvez définir que deux dynamomètres à la fois dans l'offre gratuite.

Procfile


web: gunicorn app:app
rq_worker: python rq_worker.py
timer_worker: python timer_worker.py
$ heroku ps:scale rq_worker=1 timer_worker=1
Scaling dynos... !
 !    Cannot run more than 2 Free size dynos.

Pour cette raison, malheureusement, j'ai pris la méthode de modification du même code source uniquement dans Procfile et de le déployer en tant que deux applications.

Procfile pour LINE BOT


web: gunicorn app:app
rq_worker: python rq_worker.py

Procfile pour la minuterie


timer_worker: python timer_worker.py

Dans ce cas, les deux applications doivent se connecter au même serveur Redis, vous devez donc définir la variable d'environnement du module complémentaire RedisToGo REDISTOGO_URL créée par une application sur la variable d'environnement de l'autre application.

prime

Le LINE BOT que j'ai créé cette fois ne traite pas beaucoup de données d'entrée, donc des erreurs autres que des nombres se produiront. s_timer2.PNG

Au fait, j'ai aussi fait un LINE BOT qui analyse morphologiquement l'entrée et fait un désordre (code source: github). s_kemo.PNG

Recommended Posts

Traitement asynchrone avec LINE BOT: RQ (Redis Queue) en Python
Traitement asynchrone à l'aide de Linebot dans la file d'attente des travaux
Traitement des requêtes en Python
Traitement asynchrone (threading) en python
Utilisation du mode Python dans le traitement
Exécutez LINE Bot implémenté en Python (Flask) "sans utiliser Heroku"
Implémenter le traitement du classement avec des liens en Python à l'aide de Redis Sorted Set
Développement de slack bot avec python en utilisant chat.postMessage
Implémentation du traitement asynchrone dans Django (Celery, Redis)
Traitement asynchrone en Python: référence inverse asyncio
Traitement de fichiers en Python
Traitement multithread en python
Créer un bot de collecte de données en Python à l'aide de Selenium
[Python] Utilisation de l'API Line [1ère création de Beauty Bot]
Traitement de texte UTF8 avec python
Fizzbuzz en Python (en une ligne)
Essayez LINE Notify avec Python
Pile et file d'attente en Python
Implémenter Redis Mutex en Python
Doublure de pipe Redis en Python
Collection de traitement d'image en Python
Traitement asynchrone du céleri dans Flask
Diffusion sur LINE en utilisant python
Traduit à l'aide de googletrans en Python
Traitement des arguments de ligne de commande (docopt Python)
Segfo python en une ligne
Programmation GUI en Python avec Appjar
[Python] Créez votre propre bot LINE
Précautions lors de l'utilisation de Pit avec Python
100 Language Processing Knock Chapitre 1 en Python
Essayez d'utiliser LevelDB avec Python (plyvel)
Voyons voir l'utilisation de l'entrée en python
Puissance totale en Python (en utilisant functools)
J'ai écrit la file d'attente en Python
Reconnaissance de caractères manuscrits à l'aide de KNN en Python
J'ai essayé la notification de ligne en Python
Essayez d'utiliser LeapMotion avec Python
[Introduction] Insérer des sauts de ligne dans Python 3
Implémenté en 1 minute! LINE Notify en Python
Recherche de priorité de profondeur à l'aide de la pile en Python
Lors de l'utilisation d'expressions régulières en Python
J'ai essayé le traitement asynchrone en utilisant asyncio
Créer un bot LINE avec Django
Création d'interface graphique en python avec tkinter 2
Fonctionnement de la souris à l'aide de l'API Windows en Python
Notes utilisant cChardet et python3-chardet dans Python 3.3.1.
Livre Ali en python: Auto-implémentation de la file d'attente prioritaire
CGI Server (1) édition python en une ligne
Essayez d'utiliser l'API Wunderlist en Python
Création d'interface graphique en python à l'aide de tkinter partie 1
Traitement d'exécution périodique lors de l'utilisation de tkinter [Python3]
[Python] Accélération du traitement à l'aide des outils de cache
Obtenir l'équilibre Suica en Python (en utilisant libpafe)
Pratique d'utilisation de ceci en Python (mauvais)
Hachez lentement les mots de passe en utilisant bcrypt en Python
Utilisation de venv dans un environnement Windows + Docker [Python]
Module d'implémentation de file d'attente et Python "deque"
Graphique à lignes pliées et ligne d'échelle en python
[FX] Hit oanda-API avec Python en utilisant Docker
Tweet à l'aide de l'API Twitter en Python
[Python] [Windows] Communication série en Python à l'aide de DLL