Erreur de délai d'expiration du travailleur Gunicorn

182

J'ai configuré gunicorn avec 3 ouvriers, 30 connexions ouvrières et en utilisant la classe ouvrière eventlet. Il est configuré derrière Nginx. Après toutes les quelques demandes, je vois cela dans les journaux.

[ERROR] gunicorn.error: WORKER TIMEOUT (pid:23475)
None
[INFO] gunicorn.error: Booting worker with pid: 23514

Pourquoi cela arrive-t-il? Comment puis-je comprendre ce qui ne va pas?

Merci

John
la source
2
Vous avez pu résoudre le problème? Veuillez partager vos pensées car je suis également resté fidèle à cela. Gunicorn==19.3.1etgevent==1.0.1
Black_Rider
2
J'ai trouvé la solution pour cela. Augmentation du délai d'expiration à une valeur très élevée, puis j'ai pu voir la trace de la pile
Black_Rider

Réponses:

156

Nous avons eu le même problème avec Django + nginx + gunicorn. À partir de la documentation de Gunicorn, nous avons configuré le délai d'attente gracieux qui ne faisait pratiquement aucune différence.

Après quelques tests, nous avons trouvé la solution, le paramètre à configurer est: timeout (And not graceful timeout). Cela fonctionne comme une horloge.

Alors faites:

1) ouvrez le fichier de configuration de gunicorn

2) réglez le TIMEOUT sur ce dont vous avez besoin - la valeur est en secondes

NUM_WORKERS=3
TIMEOUT=120

exec gunicorn ${DJANGO_WSGI_MODULE}:application \
--name $NAME \
--workers $NUM_WORKERS \
--timeout $TIMEOUT \
--log-level=debug \
--bind=127.0.0.1:9000 \
--pid=$PIDFILE
Amit Talmor
la source
9
Merci c'est la bonne réponse. Et puis, afin d'économiser des ressources avec de nombreuses connexions simultanées:, pip install geventpuis worker_class geventdans votre fichier de configuration ou -k geventsur la ligne de commande.
little_birdie
2
Je suis en cours d'exécution avec le superviseur, alors je l' ai ajouté à conf.d / app.conf :command=/opt/env_vars/run_with_env.sh /path/to/environment_variables /path/to/gunicorn --timeout 200 --workers 3 --bind unix:/path/to/socket server.wsgi:application
lukik
31

Sur Google Cloud, ajoutez simplement --timeout 90au point d'entrée dansapp.yaml

entrypoint: gunicorn -b :$PORT main:app --timeout 90
Apoorv Agarwal
la source
21

Exécutez Gunicorn avec --log-level=DEBUG.

Il devrait vous donner une trace de la pile d'application.

gwik
la source
41
Ce n'est pas mon cas.
Joe
16
c'est maintenant--log-level debug
psychok7
4
J'adorerais avoir un stracktrace, mais aucun d'entre eux ne fonctionne ici, en utilisant gunicorn 19.4.5. Des éléments de débogage sont affichés, donc je suppose que le drapeau a été reconnu, mais pas stacktrace à l'expiration du délai.
orzel
6

Vous devez utiliser une autre classe de type de travailleur un async comme un gevent ou tornade voir cela pour plus d' explications: Première explantion:

Vous pouvez également installer Eventlet ou Gevent si vous pensez que le code de votre application devra peut-être s'arrêter pendant de longues périodes pendant le traitement de la demande.

Deuxième :

Les nœuds de calcul synchrones par défaut supposent que votre application est liée aux ressources en termes de CPU et de bande passante réseau. En général, cela signifie que votre application ne doit rien faire qui prend un laps de temps indéfini. Par exemple, une demande sur Internet répond à ces critères. À un moment donné, le réseau externe échouera de telle sorte que les clients s'empileront sur vos serveurs.

Dseed
la source
Comment utiliserais-je réellement une classe de travailleurs si différente?
Frederick Nord
6

J'ai eu un problème très similaire, j'ai également essayé d'utiliser "runserver" pour voir si je pouvais trouver quelque chose mais tout ce que j'avais était un message Killed

J'ai donc pensé que cela pouvait être un problème de ressources, et je suis allé de l'avant pour donner plus de RAM à l'instance, et cela a fonctionné.

James Lin
la source
1
Je voyais ce problème avec même avec gevent et le délai d'expiration correctement défini, le problème était de mémoire
insuffisante
6

WORKER TIMEOUTsignifie que votre application ne peut pas répondre à la demande dans un délai défini. Vous pouvez définir cela à l'aide des paramètres de délai d'expiration de gunicorn . Certaines applications ont besoin de plus de temps pour répondre qu'une autre.

Une autre chose qui peut affecter cela est le choix du type de travailleur

Les nœuds de calcul synchrones par défaut supposent que votre application est liée aux ressources en termes de CPU et de bande passante réseau. En général, cela signifie que votre application ne doit rien faire qui prend un laps de temps indéfini. Une demande à Internet est un exemple de quelque chose qui prend un laps de temps indéfini. À un moment donné, le réseau externe échouera de telle sorte que les clients s'empileront sur vos serveurs. Ainsi, en ce sens, toute application Web qui envoie des requêtes sortantes aux API bénéficiera d'un worker asynchrone.

Lorsque j'ai eu le même problème que le vôtre (j'essayais de déployer mon application à l'aide de Docker Swarm), j'ai essayé d'augmenter le délai d'expiration et d'utiliser un autre type de classe de travail. Mais tout a échoué.

Et puis j'ai soudainement réalisé que je limitais ma ressource trop faible pour le service à l'intérieur de mon fichier de composition. C'est la chose qui a ralenti l'application dans mon cas

deploy:
  replicas: 5
  resources:
    limits:
      cpus: "0.1"
      memory: 50M
  restart_policy:
    condition: on-failure

Je vous suggère donc de vérifier ce qui ralentit votre application en premier lieu

hashlash
la source
4

Ce point final prend-il trop de temps?

Peut-être que vous utilisez flask sans support assynchrone, donc chaque requête bloquera l'appel. Pour créer une prise en charge asynchrone sans complication, ajoutez le geventworker.

Avec gevent, un nouvel appel créera un nouveau fil de discussion et votre application pourra recevoir plus de demandes

pip install gevent
gunicon .... --worker-class gevent
Ramon Medeiros
la source
1
tweak simple .. a sauvé ma journée!
penduDev
3

J'ai le même problème dans Docker.

Dans Docker, je garde le LightGBMmodèle entraîné + les Flaskdemandes de service. En tant que serveur HTTP, j'ai utilisé gunicorn 19.9.0. Lorsque j'exécute mon code localement sur mon ordinateur portable Mac, tout fonctionnait parfaitement, mais lorsque j'exécutais l'application dans Docker, mes demandes POST JSON se figeaient pendant un certain temps, le gunicornworker échouait avec [CRITICAL] WORKER TIMEOUTexception.

J'ai essayé des tonnes d'approches différentes, mais la seule qui a résolu mon problème était d'ajouter worker_class=gthread.

Voici ma configuration complète:

import multiprocessing

workers = multiprocessing.cpu_count() * 2 + 1
accesslog = "-" # STDOUT
access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(q)s" "%(D)s"'
bind = "0.0.0.0:5000"
keepalive = 120
timeout = 120
worker_class = "gthread"
threads = 3
Artem Zaika
la source
a voté pour certaines de vos autres réponses, mais celle-ci ne suffit pas: P
Achala Dissanayake
1

timeout est un paramètre clé de ce problème.

mais ça ne me convient pas.

J'ai trouvé qu'il n'y avait pas d'erreur de temporisation de gunicorn lorsque je définissais workers = 1.

quand je regarde mon code, j'ai trouvé une connexion socket (socket.send & socket.recv) dans le serveur init.

socket.recv bloquera mon code et c'est pourquoi il expirera toujours lorsque les workers> 1

espère donner des idées aux personnes qui ont des problèmes avec moi

Mao
la source
1

Cela a fonctionné pour moi:

gunicorn app:app -b :8080 --timeout 120 --workers=3 --threads=3 --worker-connections=1000

Si vous avez eventletajouté:

--worker-class=eventlet

Si vous avez geventajouté:

--worker-class=gevent
Skerrepy
la source
0

Pour moi, la solution était d'ajouter --timeout 90à mon point d'entrée, mais cela ne fonctionnait pas car j'avais DEUX points d'entrée définis, un dans app.yaml et un autre dans mon Dockerfile. J'ai supprimé le point d'entrée inutilisé et ajouté --timeout 90l'autre.

PV
la source