Błąd przekroczenia limitu czasu pracownika Gunicorn

182

Skonfigurowałem gunicorn z 3 pracownikami 30 połączeniami pracowników i używam klasy robotników z eventlet. Jest skonfigurowany za Nginx. Po każdych kilku żądaniach widzę to w dziennikach.

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

Dlaczego to się dzieje? Jak mogę dowiedzieć się, co się dzieje?

dzięki

Jan
źródło
2
Udało Ci się rozwiązać problem? Proszę podzielcie się swoimi przemyśleniami, ponieważ ja też się z tym utknąłem. Gunicorn==19.3.1igevent==1.0.1
Black_Rider
2
Znalazłem na to rozwiązanie. Wydłużono limit czasu do bardzo dużej wartości, a następnie mogłem zobaczyć ślad stosu
Black_Rider

Odpowiedzi:

156

Mieliśmy ten sam problem, używając Django + nginx + gunicorn. Z dokumentacji Gunicorn skonfigurowaliśmy bezpieczny limit czasu, który prawie nie robił różnicy.

Po kilku testach znaleźliśmy rozwiązanie, parametr do skonfigurowania to: timeout (a nie wdzięczny limit czasu). Działa jak zegar.

Więc zrób:

1) otwórz plik konfiguracyjny gunicorn

2) ustaw TIMEOUT na to, czego potrzebujesz - wartość jest w sekundach

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
źródło
9
Dzięki, to dobra odpowiedź. A potem, aby zaoszczędzić zasoby przy wielu równoczesnych połączeniach:, pip install geventnastępnie worker_class geventw pliku konfiguracyjnym lub -k geventw wierszu poleceń.
little_birdie
2
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
Biegam
31

W Google Cloud Po prostu dodaj --timeout 90do punktu wejścia wapp.yaml

entrypoint: gunicorn -b :$PORT main:app --timeout 90
Apoorv Agarwal
źródło
21

Uruchom Gunicorn z --log-level=DEBUG.

Powinien dać ci ślad stosu aplikacji.

gwik
źródło
41
W moim przypadku tak nie jest.
Joe
16
jest teraz--log-level debug
psychok7
4
Chciałbym dostać stracktrace, ale żaden z nich nie działa tutaj, używając Gunicorn 19.4.5. Wyświetlane są elementy debugowania, więc przypuszczam, że flaga została rozpoznana, ale nie śledzenie stosu po przekroczeniu limitu czasu.
orzeł
6

Musisz użyć innej klasy typu pracownika, asynchronicznej, takiej jak gevent lub tornado. Zobacz to, aby uzyskać więcej wyjaśnień: Pierwsze wyjaśnienie:

Możesz również zainstalować Eventlet lub Gevent, jeśli spodziewasz się, że kod aplikacji może wymagać wstrzymania na dłuższy czas podczas przetwarzania żądania

Drugi :

Domyślni pracownicy synchroniczni zakładają, że aplikacja jest związana z zasobami pod względem procesora i przepustowości sieci. Ogólnie oznacza to, że Twoja aplikacja nie powinna robić niczego, co zabiera nieokreśloną ilość czasu. Na przykład żądanie wysłane do internetu spełnia te kryteria. W pewnym momencie sieć zewnętrzna ulegnie awarii w taki sposób, że klienci będą gromadzić się na serwerach.

Dseed
źródło
Jak właściwie miałbym wykorzystać tak odmienną klasę robotniczą?
Frederick Nord,
6

Miałem bardzo podobny problem, próbowałem też użyć „runerver”, aby sprawdzić, czy mogę cokolwiek znaleźć, ale jedyne co miałem to wiadomość Killed

Pomyślałem więc, że może to być problem z zasobami i postanowiłem dać instancji więcej pamięci RAM i zadziałało.

James Lin
źródło
1
Widziałem ten problem nawet z geventem i poprawnie ustawionym limitem czasu, problemem był brak pamięci
bcattle
6

WORKER TIMEOUToznacza, że ​​aplikacja nie może odpowiedzieć na żądanie w określonym czasie. Możesz to ustawić za pomocą ustawień limitu czasu Gunicorn . Niektóre aplikacje potrzebują więcej czasu na odpowiedź niż inne.

Inną rzeczą, która może mieć na to wpływ, jest wybór typu pracownika

Domyślni pracownicy synchroniczni zakładają, że aplikacja jest ograniczona zasobami pod względem procesora i przepustowości sieci. Ogólnie oznacza to, że Twoja aplikacja nie powinna robić niczego, co zabiera nieokreśloną ilość czasu. Przykładem czegoś, co zajmuje nieokreśloną ilość czasu, jest żądanie do Internetu. W pewnym momencie sieć zewnętrzna ulegnie awarii w taki sposób, że klienci będą gromadzić się na serwerach. W tym sensie każda aplikacja internetowa, która wysyła żądania wychodzące do interfejsów API, będzie korzystała z asynchronicznego procesu roboczego.

Kiedy napotkałem ten sam problem co twój (próbowałem wdrożyć moją aplikację przy użyciu Docker Swarm), próbowałem zwiększyć limit czasu i użyć innego typu klasy roboczej. Ale wszystko zawiodło.

A potem nagle zdałem sobie sprawę, że ograniczam zasoby zbyt niskie dla usługi w moim pliku tworzenia. To właśnie spowolniło aplikację w moim przypadku

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

Proponuję więc najpierw sprawdzić, co spowalnia Twoją aplikację

hashlash
źródło
4

Czy ten punkt końcowy zajmuje zbyt dużo czasu?

Może używasz flask bez wsparcia asynchronicznego, więc każde żądanie będzie blokować połączenie. Aby utworzyć obsługę asynchroniczną bez utrudniania, dodaj geventpracownika.

Dzięki gevent nowe połączenie spowoduje pojawienie się nowego wątku, a Twoja aplikacja będzie mogła otrzymywać więcej żądań

pip install gevent
gunicon .... --worker-class gevent
Ramon Medeiros
źródło
1
prosta korekta ... uratowała mi dzień!
penduDev
3

Mam ten sam problem w Dockerze.

W Dockerze utrzymuję wytrenowany LightGBMmodel + Flaskobsługę żądań. Jako serwer HTTP użyłem gunicorn 19.9.0. Kiedy uruchamiam kod lokalnie na moim laptopie Mac, wszystko działało idealnie, ale kiedy uruchomiłem aplikację w Dockerze, moje żądania POST JSON zawieszały się przez jakiś czas, a następnie gunicornpracownik nie działał z [CRITICAL] WORKER TIMEOUTwyjątkiem.

Wypróbowałem mnóstwo różnych podejść, ale jedynym rozwiązaniem mojego problemu było dodanie worker_class=gthread.

Oto moja pełna konfiguracja:

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
źródło
Głosowałeś za niektórymi Twoimi innymi odpowiedziami, ale ta jedna nie wystarczy: P
Achala Dissanayake
1

Limit czasu jest kluczowym parametrem tego problemu.

jednak nie jest to dla mnie odpowiednie.

stwierdziłem, że nie ma błędu przekroczenia limitu czasu Gunicorn, gdy ustawiam workers = 1.

kiedy patrzę na mój kod, znalazłem połączenie gniazda (socket.send i socket.recv) w inicjalizacji serwera.

socket.recv zablokuje mój kod i dlatego zawsze przekroczy limit czasu, gdy workery> 1

Mam nadzieję, że przekażę kilka pomysłów osobom, które mają ze mną jakiś problem

Mao
źródło
1

To zadziałało dla mnie:

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

Jeśli eventletdodałeś:

--worker-class=eventlet

Jeśli geventdodałeś:

--worker-class=gevent
Skerrepy
źródło
0

Dla mnie rozwiązaniem było dodanie --timeout 90do mojego punktu wejścia, ale nie działało, ponieważ miałem zdefiniowane DWA punkty wejścia, jeden w app.yaml, a drugi w moim pliku Dockerfile. Usunąłem nieużywany punkt wejścia i dodałem --timeout 90w drugim.

PV
źródło