Gunicorn: TIEMPO DE MUERTE CRÍTICO PARA EL TRABAJADOR al ejecutar la aplicación Flask

Creado en 5 jun. 2018  ·  82Comentarios  ·  Fuente: benoitc/gunicorn

Parece que ya ha habido varios informes relacionados con el error [CRITICAL] WORKER TIMEOUT pero sigue apareciendo. Aquí está mi problema.

Estoy ejecutando esta aplicación Flask hello world.

from flask import Flask
application = Flask(__name__)

@application.route('/')
def hello_world():
    return 'Hello, World!'

El comando gunicorn es este:

gunicorn -b 0.0.0.0:5000 --log-level=debug hello

Y esta es la salida de la consola:

[2018-06-05 14:56:21 +0200] [11229] [INFO] Starting gunicorn 19.8.1
[2018-06-05 14:56:21 +0200] [11229] [DEBUG] Arbiter booted
[2018-06-05 14:56:21 +0200] [11229] [INFO] Listening at: http://0.0.0.0:5000 (11229)
[2018-06-05 14:56:21 +0200] [11229] [INFO] Using worker: sync
[2018-06-05 14:56:21 +0200] [11232] [INFO] Booting worker with pid: 11232
[2018-06-05 14:56:21 +0200] [11229] [DEBUG] 1 workers
[2018-06-05 14:56:32 +0200] [11232] [DEBUG] GET /
[2018-06-05 14:56:57 +0200] [11232] [DEBUG] Closing connection. 
[2018-06-05 14:57:16 +0200] [11232] [DEBUG] GET /
[2018-06-05 14:57:47 +0200] [11229] [CRITICAL] WORKER TIMEOUT (pid:11232)
[2018-06-05 14:57:47 +0200] [11232] [INFO] Worker exiting (pid: 11232)
[2018-06-05 14:57:47 +0200] [11324] [INFO] Booting worker with pid: 11324

¿Puede explicar claramente por qué aparece el error y si se espera en este ejemplo? ¿Cómo lo soluciono o si es un comportamiento esperado por qué error crítico entonces?

Investigation unconfirmed

Comentario más útil

Usar gunicorn con gevent no solucionó el error.

Todos 82 comentarios

No se espera el error, pero no hay nada en su ejemplo que muestre por qué sucede. Cuéntenos más sobre su entorno.

  • ¿Qué cliente se utiliza para conectarse a Gunicorn?
  • ¿Qué proxy inverso, si lo hay, se usa para conectarse a Gunicorn?

Cuéntenos más sobre su entorno.

  • ¿Qué cliente se utiliza para conectarse a Gunicorn?
    => Acabo de enviar una solicitud desde Chromium: http: // localhost : 5000 /
  • ¿Qué proxy inverso, si lo hay, se usa para conectarse a Gunicorn?
    => Sin proxy, solo Gunicorn + Frasco

Acabo de reproducir el problema en una configuración completamente nueva, aquí están los pasos:

mkdir gunicorn
cd gunicorn/
pipenv --python 3.6
pipenv install flask
pipenv install gunicorn
vim hello.py
pipenv shell
gunicorn -b 0.0.0.0:5000 --log-level=debug hello

El hello.py es exactamente la misma aplicación de Flask que publiqué en el informe inicial.
A continuación se muestra el registro completo.

~$ gunicorn -b 0.0.0.0:5000 --log-level=debug hello
[2018-06-06 09:16:21 +0200] [19829] [DEBUG] Current configuration:
  config: None
  bind: ['0.0.0.0:5000']
  backlog: 2048
  workers: 1
  worker_class: sync
  threads: 1
  worker_connections: 1000
  max_requests: 0
  max_requests_jitter: 0
  timeout: 30
  graceful_timeout: 30
  keepalive: 2
  limit_request_line: 4094
  limit_request_fields: 100
  limit_request_field_size: 8190
  reload: False
  reload_engine: auto
  reload_extra_files: []
  spew: False
  check_config: False
  preload_app: False
  sendfile: None
  reuse_port: False
  chdir: /home/dima/work/gunicorn
  daemon: False
  raw_env: []
  pidfile: None
  worker_tmp_dir: None
  user: 1000
  group: 985
  umask: 0
  initgroups: False
  tmp_upload_dir: None
  secure_scheme_headers: {'X-FORWARDED-PROTOCOL': 'ssl', 'X-FORWARDED-PROTO': 'https', 'X-FORWARDED-SSL': 'on'}
  forwarded_allow_ips: ['127.0.0.1']
  accesslog: None
  disable_redirect_access_to_syslog: False
  access_log_format: %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"
  errorlog: -
  loglevel: debug
  capture_output: False
  logger_class: gunicorn.glogging.Logger
  logconfig: None
  logconfig_dict: {}
  syslog_addr: udp://localhost:514
  syslog: False
  syslog_prefix: None
  syslog_facility: user
  enable_stdio_inheritance: False
  statsd_host: None
  statsd_prefix: 
  proc_name: None
  default_proc_name: hello
  pythonpath: None
  paste: None
  on_starting: <function OnStarting.on_starting at 0x7f9757112d08>
  on_reload: <function OnReload.on_reload at 0x7f9757112e18>
  when_ready: <function WhenReady.when_ready at 0x7f9757112f28>
  pre_fork: <function Prefork.pre_fork at 0x7f9756c230d0>
  post_fork: <function Postfork.post_fork at 0x7f9756c231e0>
  post_worker_init: <function PostWorkerInit.post_worker_init at 0x7f9756c232f0>
  worker_int: <function WorkerInt.worker_int at 0x7f9756c23400>
  worker_abort: <function WorkerAbort.worker_abort at 0x7f9756c23510>
  pre_exec: <function PreExec.pre_exec at 0x7f9756c23620>
  pre_request: <function PreRequest.pre_request at 0x7f9756c23730>
  post_request: <function PostRequest.post_request at 0x7f9756c237b8>
  child_exit: <function ChildExit.child_exit at 0x7f9756c238c8>
  worker_exit: <function WorkerExit.worker_exit at 0x7f9756c239d8>
  nworkers_changed: <function NumWorkersChanged.nworkers_changed at 0x7f9756c23ae8>
  on_exit: <function OnExit.on_exit at 0x7f9756c23bf8>
  proxy_protocol: False
  proxy_allow_ips: ['127.0.0.1']
  keyfile: None
  certfile: None
  ssl_version: 2
  cert_reqs: 0
  ca_certs: None
  suppress_ragged_eofs: True
  do_handshake_on_connect: False
  ciphers: TLSv1
  raw_paste_global_conf: []
[2018-06-06 09:16:21 +0200] [19829] [INFO] Starting gunicorn 19.8.1
[2018-06-06 09:16:21 +0200] [19829] [DEBUG] Arbiter booted
[2018-06-06 09:16:21 +0200] [19829] [INFO] Listening at: http://0.0.0.0:5000 (19829)
[2018-06-06 09:16:21 +0200] [19829] [INFO] Using worker: sync
[2018-06-06 09:16:21 +0200] [19832] [INFO] Booting worker with pid: 19832
[2018-06-06 09:16:22 +0200] [19829] [DEBUG] 1 workers
[2018-06-06 09:16:48 +0200] [19832] [DEBUG] GET /
[2018-06-06 09:17:19 +0200] [19829] [CRITICAL] WORKER TIMEOUT (pid:19832)
[2018-06-06 09:17:19 +0200] [19832] [INFO] Worker exiting (pid: 19832)
[2018-06-06 09:17:19 +0200] [19872] [INFO] Booting worker with pid: 19872
^C[2018-06-06 09:17:26 +0200] [19829] [INFO] Handling signal: int
[2018-06-06 09:17:26 +0200] [19872] [INFO] Worker exiting (pid: 19872)
[2018-06-06 09:17:26 +0200] [19829] [INFO] Shutting down: Master
~$ pip list
Package      Version
------------ -------
click        6.7    
Flask        1.0.2  
gunicorn     19.8.1 
itsdangerous 0.24   
Jinja2       2.10   
MarkupSafe   1.0    
pip          10.0.1 
setuptools   39.2.0 
Werkzeug     0.14.1 
wheel        0.31.1

@bigunyak Creo que se debe al tiempo de espera predeterminado, su trabajador ha estado en silencio durante 30 segundos. http://docs.gunicorn.org/en/stable/settings.html#timeout

De su registro,

[2018-06-05 14:57:16 +0200] [11232] [DEBUG] GET /
[2018-06-05 14:57:47 +0200] [11229] [CRITICAL] WORKER TIMEOUT (pid:11232)
[2018-06-06 09:16:48 +0200] [19832] [DEBUG] GET /
[2018-06-06 09:17:19 +0200] [19829] [CRITICAL] WORKER TIMEOUT (pid:19832)

Veo lo mismo: los trabajadores se agotan incluso cuando no atienden solicitudes, con el trabajador de sincronización.
En ese sentido, el registro de nivel crítico es bastante confuso.

Intente usar Gevent worker podría resolver esto.

En ese sentido, el registro de nivel crítico es bastante confuso.

Exactamente, esa era mi pregunta original: si es un comportamiento esperado, ¿por qué entonces un error crítico?
También sería bueno obtener algunos antecedentes sobre por qué los trabajadores deben reiniciarse, tal vez esto podría agregarse al documento de Diseño .

También veo esto (reproducido usando examples/test.py con gunicorn test:app -b localhost:9595 --log-level=debug --timeout=5 ) y estoy de acuerdo en que el nivel crítico es un poco confuso. Estaría bien cambiarlo al nivel de depuración. @benoitc @tilgovi ¿qué opinas?

Creo que el nivel de información podría ser un poco mejor.

Tuve lo mismo con MSYS2 en Win10 pero finalmente pude resolverlo.

en notificar () de ... \ gunicorn \ trabajadores \ workertmp.py, originalmente se usa os.fchmod. Pero no funciona en MSYS. En lugar de os.fchmod, usé os.utime. Se sigue el código. Creo que podría funcionar para todas las plataformas.

    def notify(self):
        try:
            self.spinner = (self.spinner + 1) % 2
            os.fchmod(self._tmp.fileno(), self.spinner)
            if PLATFORM.startswith('MSYS') :
                os.utime(self._tmp.fileno(), None)
        except AttributeError:
            # python < 2.6
            self._tmp.truncate(0)
            os.write(self._tmp.fileno(), b"X")

@berkerpeksag No esperaría que el trabajador salga porque no ocurren solicitudes. Este error solo debería ocurrir si el trabajador se ha mantenido ocupado durante un tiempo> hasta el tiempo de espera. Entonces el error es crítico. Imo deberíamos mejorar la documentación para proporcionar más casos de uso y respuestas a tales errores.

Si el error sigue ocurriendo cuando el trabajador no está ocupado, entonces está sucediendo algo más y probablemente tengamos un error.

[EDITAR]
El mismo error para mí.
Con Django 1.10 / gunicorn 19.6.0 / Python 2.7.15 en python2.7-alpine en Debian 8.8 y stock kernel 3.16, todo estaba funcionando bien.
Después de actualizar a Django 1.11 y gunicorn 19.8.1, los trabajadores siguen fallando al arrancar con [CRITICAL WORKER TIMEOUT].
La degradación de gunicorn a 19.6.0 no soluciona el problema.
Actualizamos el kernel del host a 4.9.0 (estaba programado) y los trabajadores arrancaron con éxito sin errores.
Pero:

  • usamos 4 trabajadores
  • después de exactamente 4 llamadas a la aplicación Django, las próximas llamadas expirarán, mostrando [CRITICAL WORKER TIMEOUT] en los registros
  • el comando linux top muestra 4 procesos gunicorn atascados con un consumo de CPU bastante alto.

Vamos a probar gunicorn gevent para ver si podemos volver a poner nuestra aplicación en línea.

Usar gunicorn con gevent no solucionó el error.

alguna actualización sobre este tema?

Parece que @neocolor identificó un error real en MSYS. Podría merecer un tema aparte.

@bigunyak ¿

Para @Tberdy : ¿qué sucede si intenta configurar --worker-tmp-dir en algún lugar fuera del sistema de archivos tmpfs? Me pregunto si tal vez alpine o docker o la combinación interfiere de alguna manera con la forma en que los trabajadores notifican al árbitro.

Consulte también el n.º 1388 para conocer los problemas de tmpfs relacionados con Docker.

Tengo este problema.

Yo también tengo este problema, la sincronización de gunicorn funcionaba perfectamente bien hasta la noche pasada, pero comenzó a informar, el tiempo de espera de los trabajadores [CRÍTICO] al usar gevent parece resolver mi problema, pero realmente me gustaría saber por qué sucedió esto.

@ timoj58 @cjmash ¿ puede proporcionar más detalles sobre el problema? ¿Cómo está ejecutando gunicorn (en una máquina virtual ?, opciones ...), qué sistema de archivos, SO? Cualquier cosa que pueda ayudar a reproducir sería muy útil :)

@benoitc Estoy ejecutando gunicorn para iniciar mi proyecto Django en kubernetes, mis argumentos gunicorn son --bind = $ port --workers = 7 --timeout = 1200 --log-level = debug --access-logfile - error-logfile - "

los errores que obtengo de los registros

`` `E [2018-08-09 21:47:56 +0000] [13] [INFO] Trabajador de arranque con pid: 13

E [2018-08-09 21:47:56 +0000] [14] [INFO] Trabajador de arranque con pid: 14

E [2018-08-09 21:47:56 +0000] [12] [INFO] Trabajador de arranque con pid: 12

E [2018-08-09 21:47:56 +0000] [1] [DEBUG] 7 trabajadores

E [2018-08-09 21:47:56 +0000] [11] [INFO] Trabajador de arranque con pid: 11

E [2018-08-09 21:47:55 +0000] [10] [INFO] Trabajador de arranque con pid: 10

E [2018-08-09 21:47:55 +0000] [9] [INFO] Trabajador de arranque con pid: 9

E [2018-08-09 21:47:55 +0000] [8] [INFO] Trabajador de arranque con pid: 8

E [2018-08-09 21:47:55 +0000] [1] [INFO] Usando trabajador: sincronización

E [2018-08-09 21:47:55 +0000] [1] [INFO] Escuchando en: http://0.0.0.0 : 4040 (1)

E [2018-08-09 21:47:55 +0000] [1] [DEBUG] Arbitro arrancado

E [2018-08-09 21:47:55 +0000] [1] [INFO] Arranque de gunicorn 19.7.1

E raw_paste_global_conf: []

Cifrados E: TLSv1

E do_handshake_on_connect: Falso

E suppress_ragged_eofs: Verdadero

E ca_certs: Ninguno

E cert_reqs: 0

E ssl_version: 2

E certfile: Ninguno

Archivo de claves E: Ninguno

E proxy_allow_ips: ['127.0.0.1']

E proxy_protocol: Falso

E on_exit:

E ntrabajadores_cambiados:

E trabajador_salida:

E child_exit:

E post_request:

E pre_request:

E pre_exec:

E worker_abort:

E trabajador_int:

E post_worker_init:

E post_fork:

E pre_horquilla:

E when_ready:

E on_reload:

E on_starting:

Pasta E: Ninguna

E pythonpath: Ninguno

E nombre_proc_predeterminado: art.wsgi

E proc_name: Ninguno

E statsd_prefix:

E statsd_host: Ninguno

E enable_stdio_inheritance: Falso

E syslog_facility: usuario

E syslog_prefix: Ninguno

E syslog: falso

E syslog_addr: udp: // localhost : 514

E logconfig: Ninguno

E logger_class: gunicorn.glogging.Logger

E capture_output: Falso

E loglevel: depuración

E registro de errores: -

E access_log_format:% (h) s% (l) s% (u) s% (t) s "% (r) s"% (s) s% (b) s "% (f) s" "% ( como"

Registro de acceso E: -

E reenviados_allow_ips: ['127.0.0.1']

E secure_scheme_headers: {'X-FORWARDED-PROTOCOLO': 'ssl', 'X-FORWARDED-PROTO': 'https', 'X-FORWARDED-SSL': 'on'}

E tmp_upload_dir: Ninguno

E initgroups: Falso

Máscara electrónica: 0

Grupo E: 0

Usuario E: 0

E worker_tmp_dir: Ninguno

E pidfile: Ninguno

E raw_env: []

E demonio: falso

E chdir: / usr / src / app

E sendfile: Ninguno

E preload_app: Falso

E check_config: Falso

E vomitar: falso

E reload_engine: auto

Recarga E: Falso

E limit_request_field_size: 8190

E limit_request_fields: 100

E limit_request_line: 4094

E keepalive: 2

E graceful_timeout: 30

Tiempo de espera E: 1200

E max_requests_jitter: 0

E max_requests: 0

E conexiones_de_trabajador: 1000

Hilos E: 1

E worker_class: sincronización

Trabajadores E: 7

Cartera E: 2048

Enlace E: ['0.0.0.0:4040']

E config: Ninguno

E [2018-08-09 21:47:55 +0000] [1] [DEBUG] Configuración actual:

I No hay migraciones para aplicar.

Ejecutando migraciones:

Aplico todas las migraciones: admin, auth, contenttypes, core, dashboard, jet, oauth2_provider, sesiones

I Operaciones a realizar:

E [2018-08-09 21:47:20 +0000] [13] [INFO] Trabajador saliendo (pid: 13)

E os.path.dirname (os.path.dirname (__ file__)), '.env'))

E /usr/src/app/art/wsgi.py:19: UserWarning: No lee /usr/src/app/.env - no existe.

E [2018-08-09 21:47:00 +0000] [21] [INFO] Trabajador de arranque con pid: 21

E [2018-08-09 21:47:00 +0000] [1] [INFO] Señal de manejo: término

E [2018-08-09 21:46:35 +0000] [12] [INFO] Trabajador de arranque con pid: 12

E [2018-08-09 21:46:34 +0000] [13] [INFO] Trabajador de arranque con pid: 13

E [2018-08-09 21:46:34 +0000] [11] [INFO] Trabajador de arranque con pid: 11

E [2018-08-09 21:46:34 +0000] [1] [DEBUG] 7 trabajadores

E [2018-08-09 21:46:34 +0000] [10] [INFO] Trabajador de arranque con pid: 10

E [2018-08-09 21:46:34 +0000] [9] [INFO] Trabajador de arranque con pid: 9

E [2018-08-09 21:46:34 +0000] [8] [INFO] Trabajador de arranque con pid: 8

E [2018-08-09 21:46:34 +0000] [7] [INFO] Trabajador de arranque con pid: 7

E [2018-08-09 21:46:34 +0000] [1] [INFO] Usando trabajador: sincronización

E [2018-08-09 21:46:34 +0000] [1] [INFO] Escuchando en: http://0.0.0.0 : 4040 (1)

E [2018-08-09 21:46:34 +0000] [1] [DEBUG] Arbitro arrancado

E [2018-08-09 21:46:34 +0000] [1] [INFO] Arranque de gunicorn 19.7.1

E raw_paste_global_conf: []

Cifrados E: TLSv1

E do_handshake_on_connect: Falso

E suppress_ragged_eofs: Verdadero

E ca_certs: Ninguno

E cert_reqs: 0

E ssl_version: 2

E certfile: Ninguno

Archivo de claves E: Ninguno

E proxy_allow_ips: ['127.0.0.1']

E proxy_protocol: Falso

E on_exit:

E ntrabajadores_cambiados:

E trabajador_salida:

E child_exit:

E post_request:

E pre_request:

E pre_exec:

E worker_abort:

E trabajador_int:

E post_worker_init:

E post_fork:

E pre_horquilla:

E when_ready:

E on_reload:

E on_starting:

Pasta E: Ninguna

E pythonpath: Ninguno

E nombre_proc_predeterminado: art.wsgi

E proc_name: Ninguno

E statsd_prefix:

E statsd_host: Ninguno

E enable_stdio_inheritance: Falso

E syslog_facility: usuario

E syslog_prefix: Ninguno

E syslog: falso

E syslog_addr: udp: // localhost : 514

E logconfig: Ninguno

E logger_class: gunicorn.glogging.Logger

E capture_output: Falso

E loglevel: depuración

E registro de errores: -

E access_log_format:% (h) s% (l) s% (u) s% (t) s "% (r) s"% (s) s% (b) s "% (f) s" "% ( como"

Registro de acceso E: -

E reenviados_allow_ips: ['127.0.0.1']

E secure_scheme_headers: {'X-FORWARDED-PROTOCOLO': 'ssl', 'X-FORWARDED-PROTO': 'https', 'X-FORWARDED-SSL': 'on'}

E tmp_upload_dir: Ninguno

E initgroups: Falso

Máscara electrónica: 0

Grupo E: 0

Usuario E: 0

E worker_tmp_dir: Ninguno

E pidfile: Ninguno

E raw_env: []

E demonio: falso

E chdir: / usr / src / app

E sendfile: Ninguno

E preload_app: Falso

E check_config: Falso

E vomitar: falso

E reload_engine: auto

Recarga E: Falso

E limit_request_field_size: 8190

E limit_request_fields: 100

E limit_request_line: 4094

E keepalive: 2

E graceful_timeout: 30

Tiempo de espera E: 1200

E max_requests_jitter: 0

E max_requests: 0

E conexiones_de_trabajador: 1000

Hilos E: 1

E worker_class: sincronización

Trabajadores E: 7

Cartera E: 2048

Enlace E: ['0.0.0.0:4040']

E config: Ninguno

E [2018-08-09 21:46:34 +0000] [1] [DEBUG] Configuración actual:

''

Esta vez luché un poco para reproducir el problema, pero todavía está allí en la última versión 19.9.0 de gunicorn.
Los pasos para reproducirlo son exactamente los mismos que describí en esta publicación .
Mi sistema es Arch Linux x86_64 GNU / Linux (kernel 4.17.2-1-ARCH), Python 3.6.5
Aquí hay un rastro de registro nuevo.

~$ gunicorn -b 0.0.0.0:5000 --log-level=debug hello
[2018-08-10 09:48:40 +0200] [23114] [DEBUG] Current configuration:
  config: None
  bind: ['0.0.0.0:5000']
  backlog: 2048
  workers: 1
  worker_class: sync
  threads: 1
  worker_connections: 1000
  max_requests: 0
  max_requests_jitter: 0
  timeout: 30
  graceful_timeout: 30
  keepalive: 2
  limit_request_line: 4094
  limit_request_fields: 100
  limit_request_field_size: 8190
  reload: False
  reload_engine: auto
  reload_extra_files: []
  spew: False
  check_config: False
  preload_app: False
  sendfile: None
  reuse_port: False
  chdir: /home/dima/lerning/python/modules/gunicorn
  daemon: False
  raw_env: []
  pidfile: None
  worker_tmp_dir: None
  user: 1000
  group: 985
  umask: 0
  initgroups: False
  tmp_upload_dir: None
  secure_scheme_headers: {'X-FORWARDED-PROTOCOL': 'ssl', 'X-FORWARDED-PROTO': 'https', 'X-FORWARDED-SSL': 'on'}
  forwarded_allow_ips: ['127.0.0.1']
  accesslog: None
  disable_redirect_access_to_syslog: False
  access_log_format: %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"
  errorlog: -
  loglevel: debug
  capture_output: False
  logger_class: gunicorn.glogging.Logger
  logconfig: None
  logconfig_dict: {}
  syslog_addr: udp://localhost:514
  syslog: False
  syslog_prefix: None
  syslog_facility: user
  enable_stdio_inheritance: False
  statsd_host: None
  statsd_prefix: 
  proc_name: None
  default_proc_name: hello
  pythonpath: None
  paste: None
  on_starting: <function OnStarting.on_starting at 0x7f5f8b9dad08>
  on_reload: <function OnReload.on_reload at 0x7f5f8b9dae18>
  when_ready: <function WhenReady.when_ready at 0x7f5f8b9daf28>
  pre_fork: <function Prefork.pre_fork at 0x7f5f8b4ec0d0>
  post_fork: <function Postfork.post_fork at 0x7f5f8b4ec1e0>
  post_worker_init: <function PostWorkerInit.post_worker_init at 0x7f5f8b4ec2f0>
  worker_int: <function WorkerInt.worker_int at 0x7f5f8b4ec400>
  worker_abort: <function WorkerAbort.worker_abort at 0x7f5f8b4ec510>
  pre_exec: <function PreExec.pre_exec at 0x7f5f8b4ec620>
  pre_request: <function PreRequest.pre_request at 0x7f5f8b4ec730>
  post_request: <function PostRequest.post_request at 0x7f5f8b4ec7b8>
  child_exit: <function ChildExit.child_exit at 0x7f5f8b4ec8c8>
  worker_exit: <function WorkerExit.worker_exit at 0x7f5f8b4ec9d8>
  nworkers_changed: <function NumWorkersChanged.nworkers_changed at 0x7f5f8b4ecae8>
  on_exit: <function OnExit.on_exit at 0x7f5f8b4ecbf8>
  proxy_protocol: False
  proxy_allow_ips: ['127.0.0.1']
  keyfile: None
  certfile: None
  ssl_version: 2
  cert_reqs: 0
  ca_certs: None
  suppress_ragged_eofs: True
  do_handshake_on_connect: False
  ciphers: TLSv1
  raw_paste_global_conf: []
[2018-08-10 09:48:40 +0200] [23114] [INFO] Starting gunicorn 19.9.0
[2018-08-10 09:48:40 +0200] [23114] [DEBUG] Arbiter booted
[2018-08-10 09:48:40 +0200] [23114] [INFO] Listening at: http://0.0.0.0:5000 (23114)
[2018-08-10 09:48:40 +0200] [23114] [INFO] Using worker: sync
[2018-08-10 09:48:40 +0200] [23117] [INFO] Booting worker with pid: 23117
[2018-08-10 09:48:40 +0200] [23114] [DEBUG] 1 workers
[2018-08-10 09:48:45 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:48:54 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:49:00 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:49:18 +0200] [23117] [DEBUG] Closing connection. 
[2018-08-10 09:49:18 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:49:23 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:49:37 +0200] [23117] [DEBUG] Closing connection. 
[2018-08-10 09:49:37 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:49:50 +0200] [23117] [DEBUG] Closing connection. 
[2018-08-10 09:51:11 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:51:13 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:51:43 +0200] [23114] [CRITICAL] WORKER TIMEOUT (pid:23117)
[2018-08-10 09:51:43 +0200] [23117] [INFO] Worker exiting (pid: 23117)
[2018-08-10 09:51:44 +0200] [23229] [INFO] Booting worker with pid: 23229

Como antes, para probarlo, solo estaba presionando http://0.0.0.0 : 5000 / en Chromium.
A continuación se muestra el contenido de Pipfile y Pipfile.lock para que pueda ver el entorno exacto.

  • Pipfile
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
flask = "*"
gunicorn = "*"

[dev-packages]

[requires]
python_version = "3.6"
  • Pipfile.lock
{
    "_meta": {
        "hash": {
            "sha256": "81cb5d5f0b11719d8d9c5ec9cc683fdcf959c652fda256d5552a82d0f459a99c"
        },
        "pipfile-spec": 6,
        "requires": {
            "python_version": "3.6"
        },
        "sources": [
            {
                "name": "pypi",
                "url": "https://pypi.org/simple",
                "verify_ssl": true
            }
        ]
    },
    "default": {
        "click": {
            "hashes": [
                "sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d",
                "sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b"
            ],
            "version": "==6.7"
        },
        "flask": {
            "hashes": [
                "sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48",
                "sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05"
            ],
            "index": "pypi",
            "version": "==1.0.2"
        },
        "gunicorn": {
            "hashes": [
                "sha256:aa8e0b40b4157b36a5df5e599f45c9c76d6af43845ba3b3b0efe2c70473c2471",
                "sha256:fa2662097c66f920f53f70621c6c58ca4a3c4d3434205e608e121b5b3b71f4f3"
            ],
            "index": "pypi",
            "version": "==19.9.0"
        },
        "itsdangerous": {
            "hashes": [
                "sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519"
            ],
            "version": "==0.24"
        },
        "jinja2": {
            "hashes": [
                "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
                "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
            ],
            "version": "==2.10"
        },
        "markupsafe": {
            "hashes": [
                "sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665"
            ],
            "version": "==1.0"
        },
        "werkzeug": {
            "hashes": [
                "sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c",
                "sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b"
            ],
            "version": "==0.14.1"
        }
    },
    "develop": {}
}

Solo para su información, también veo este error con mucha frecuencia con:

nohup gunicorn -w 8 --access-logfile = - --bind 127.0.0.1:5000 wsgi &

Solo tengo un wsgi.py que tiene

from chart_api import application
if __name__ == "__main__":
    application.run()

Avísame si hay algo que quieras que pruebe / experimente o si hay detalles específicos en los registros que quieras que revise. Estoy ejecutando flask en una VM de GCP.

lo siento por la respuesta tardía. Lo estoy ejecutando como

gunicorn --log-file = / home / ubuntu / log / gunicorn.log predictor_ api: app -b localhost: 5000 &

Usé la configuración de gevent, etc., pero cambié mi diseño de lo que necesitaba esto para solucionar el problema, de ahí la configuración básica anterior (que también falló, pero esto es de esperar dado que no hay gevent)

Python versión 3.6
env: aws tensorflow_p36 optimizado (ubuntu)
nginx está sentado frente a gunicorn, que está ejecutando una aplicación de matraz.

matraz versión 1.0.2
nginx versión 1.10.3
gunicorn versión 19.9.0

También cambié los tiempos de espera de nginx en caso de que esto pudiera haberlo causado.

Frente al mismo problema con el servidor gunicorn

# gunicorn Applicat ionServer: app -b 0.0.0.0:6001 -w 8 --threads 4 --backlog 2048 \
# --timeout 120 --graceful-timeout 60 --access-logfile logs / access.log \

--error-logfile logs / error.log --log-level = info

Matraz == 0.12.1
gunicorn == 19.7.1

cuando inicio el servidor con el comando anterior, mi sistema se congeló durante un tiempo y los pids de los trabajadores continúan arrancando, aunque mantuve el tiempo de espera de 120 segundos y el servidor no acepta una solicitud única.

¿Alguna actualización sobre este tema? Tengo el mismo problema

[CRÍTICO] TIEMPO MUERTO DEL TRABAJADOR

¿Se pregunta si alguien ha reproducido esto con éxito en una imagen de Docker?

También veo esto al intentar implementar el trabajador ddtrace-run de datadog en una aplicación existente que comienza con gunicorn -k gevent --threads 4.

Gracioso rastro de una salida del sistema que nunca había visto antes también ...
[2018-11-07 11:11:50 +0000] [15987] [INFO] Booting worker with pid: 15987 [2018-11-07 11:11:50 +0000] [15977] [DEBUG] 1 workers [2018-11-07 11:12:20 +0000] [15977] [CRITICAL] WORKER TIMEOUT (pid:15987) Exception SystemExit: 1 in <bound method LibevLoop._loop_will_run of <cassandra.io.libevreactor.LibevLoop object at 0x7f3cb66d4a50>> ignored

Puedo resolver este problema haciendo coincidir el número de trabajadores y el número de subprocesos.

Había configurado workers = (2 * cpu_count) + 1 y no configuré hilos.

Una vez que cambié threads = workers , todo comenzó a funcionar bien. Por si acaso, si esto ayuda a alguien.

asi es como luce ahora

def run(host='0.0.0.0', port=8080, workers=1 + (multiprocessing.cpu_count() * 2)):
    """Run the app with Gunicorn."""

    if app.debug:
        app.run(host, int(port), use_reloader=False)
    else:
        gunicorn = WSGIApplication()
        gunicorn.load_wsgiapp = lambda: app
        gunicorn.cfg.set('bind', '%s:%s' % (host, port))
        gunicorn.cfg.set('workers', workers)
        gunicorn.cfg.set('threads', workers)
        gunicorn.cfg.set('pidfile', None)
        gunicorn.cfg.set('worker_class', 'sync')
        gunicorn.cfg.set('keepalive', 10)
        gunicorn.cfg.set('accesslog', '-')
        gunicorn.cfg.set('errorlog', '-')
        gunicorn.cfg.set('reload', True)
        gunicorn.chdir()
        gunicorn.run()

Encontré este problema al ejecutar Django con un único contenedor Docker en AWS Elastic Beanstalk. Resolví el problema arreglando mis grupos de seguridad para asegurarme de que mi instancia EC2 pudiera comunicarse con mi instancia RDS. Reconozco que esta puede no ser la solución para el 99% de las personas en este tema, pero dejo esta nota para ayudar a otros a evitar perder horas cayendo por este agujero de conejo.

En mi caso, el problema se resolvió realizando systemctl daemon-reload .
En pocas palabras, sabía del tiempo de espera predeterminado de 30 segundos, pero no pude cambiarlo hasta que pensé que, por supuesto, tenía que volver a cargar el demonio systemd para aplicar los cambios al servicio.

@bigunyak @benoitc @tilgovi
Después de una larga búsqueda en Google y algo de experimentación, creo que la causa raíz de este problema es el "servicio de preconexión / predicción" de Chrome (que está habilitado de forma predeterminada tanto en Chrome como en Chromium).

@jeiting hizo un buen escrito sobre este problema
https://hackernoon.com/chrome-preconnect-breaks-singly-threaded-servers-95944be16400
Alguna lectura adicional:
https://github.com/corydolphin/flask-cors/issues/147
https://github.com/pallets/flask/issues/2169

TLDR
En algunos casos, Chrome / Chromium se abre y mantiene una (s) conexión (es) TCP "vacía" (es decir, predice que pronto buscará otro recurso). Si las conexiones TCP "vacías" llegan a su servidor gunicorn primero, cualquier solicitud "real" posterior de Chrome puede quedarse atascada detrás de la solicitud "vacía" hasta que los trabajadores que manejan la solicitud "vacía" expiren. Es más probable que esto suceda si solo está ejecutando un único trabajador de sincronización en gunicorn. Pero como descubrieron mis experimentos, puede suceder incluso si está ejecutando varios trabajadores de sincronización.

Mi entorno

  • Mi sistema operativo nativo es Ubuntu 17
  • Tengo una API de descanso que se ejecuta en un contenedor de ventana acoplable local. Líneas relevantes del Dockefile
FROM ubuntu:18.04
...
RUN pip3 install Flask==1.0.2
RUN pip3 install gunicorn==19.9.0
RUN pip3 install flask-cors==3.0.6
......
  • Tengo 3 navegadores instalados: Firefox 61.0.1, Chromium 67.0.3396.99, Chrome 70.0.3538.102
  • Tengo una aplicación de reacción que se sirve desde un contenedor de ventana acoplable diferente en un puerto diferente
  • La aplicación de reacción hace solicitudes CORS AJAX a mi API (son solicitudes CORS porque el javascript se sirve en un puerto localhost mientras envía llamadas API a otro puerto localhost)
  • La solicitud que siempre se "bloquea" en mis experimentos es una solicitud CORS OPTIONS (activada por el navegador para solicitar permiso y luego realizar una solicitud POST). Parece lógico que un navegador intente hacer conexiones predictivas con la llamada OPTIONS porque probablemente seguirá con una llamada POST.

Experimento 1
Configuración de Gunicorn: 1 trabajador de sincronización (tiempo de espera predeterminado de 30 segundos)

Firefox: en casi todas las cargas de la página de reacción, la solicitud CORS OPTIONS se bloquea durante 5 segundos y luego se realiza correctamente.
Chromium: ¡En CADA carga de la página de reacción, la solicitud de OPCIONES CORS se bloquea durante 1,5 minutos! y luego tiene éxito.
Chromium (servicio de predicción deshabilitado): todo se carga bien
Chrome: todo se carga bien

Experimento 2
Configuración de Gunicorn: 4 trabajadores de sincronización (tiempo de espera predeterminado de 30 segundos)

Firefox: todo se carga bien
Chromium: en cada carga de la tercera página de reacción, la solicitud CORS OPTIONS se bloquea durante 30 segundos y luego se realiza correctamente.
Chromium (servicio de predicción deshabilitado): todo se carga bien
Chrome: todo se carga bien

Experimento 3
Configuración de Gunicorn: 8 trabajadores de sincronización (tiempo de espera predeterminado de 30 segundos)

Firefox: todo se carga bien
Chromium: todo se carga bien
Chrome: todo se carga bien

Experimento 4
Ejecute el servidor de desarrollo de flask con threaded=True

Firefox: todo se carga bien
Chromium: todo se carga bien
Chrome: todo se carga bien

Resumen del experimento

  • Firefox parece tener también un servicio de predicción, pero parece más elegante. (Experimento 1)
  • Chromium parece el más agresivo en la creación de conexiones de "predicción". Parece que inicia hasta 3 o 4 conexiones de "predicción" durante una solicitud de OPCIONES (Experimentos 1 y 2).
  • Sorprendentemente, aunque Chrome también tiene habilitado el servicio de predicción, no causó ningún problema en ninguno de los experimentos (tal vez el orden o la cantidad de conexiones de "predicción" sea diferente de Chromium)

Solución
En producción: la solución más fácil es poner nginx frente a gunicorn. Si desea comprender por qué nginx resuelve este problema, aquí hay un buen artículo que lo explica: https://www.brianstorti.com/the-role-of-a-reverse-proxy-to-protect-your-application-against -clientes-lentos /

En dev: La solución más fácil es ejecutar el servidor de desarrollo de flask con threaded=True . O puede deshabilitar el servicio de predicción en Chrome / Chromium.

mejoras de depuración de gunicorn
Para ayudar a depurar un problema como este en el futuro, creo que es una buena idea agregar declaraciones de registro de depuración junto a las llamadas select() y accept() en el trabajador de sincronización.
https://github.com/benoitc/gunicorn/blob/e974f30517261b2bc95cfb2017a8688f367c8bf3/gunicorn/workers/sync.py#L26
https://github.com/benoitc/gunicorn/blob/e974f30517261b2bc95cfb2017a8688f367c8bf3/gunicorn/workers/sync.py#L34
Esto mostraría que un trabajador ha aceptado una nueva conexión TCP, pero no está recibiendo ningún dato.

@asnisarenko super redacción, gracias. # 1929 es otro caso inusual de un cliente lento que produce un síntoma similar en el servidor de un solo subproceso; en ese caso, el protocolo de enlace TLS a un puerto que no es TLS parece un cliente de escritura lenta, ya que no envía encabezados sensibles rápidamente .

Puede ser Gunicorn, ya que los trabajadores de sincronización de un solo subproceso van a necesitar un nuevo ajuste, una caída de cliente agresiva para los clientes que no envían al menos una primera línea de encabezado de solicitud, si no todos los encabezados, dentro de un tiempo razonable.

Si esto sucede en su aplicación, puede agregar algún código de diagnóstico temporal:

def trace_on_abort():
    import signal
    import traceback

    def print_trace(sig, frame):
        print(''.join(traceback.format_stack(frame)))

    signal.signal(signal.SIGABRT, print_trace)

Con suerte, esto debería revelar dónde se cuelga su aplicación.

Por ejemplo, de alguna manera me las arreglé para import flask antes de gevent.monkey.patch_all() y así el app._before_request_lock mi Frasco terminó siendo un bloqueo no gevent (es decir, sin parchear threading.Lock ). En tal caso, dos solicitudes en sucesión cercana en el inicio de la aplicación harían que se cuelgue (la segunda solicitud bloquearía todo el hilo). Pero este fue mi error, y el tuyo puede diferir.

@asnisarenko No estoy seguro de por qué estás experimentando un bloqueo. Absolutamente _no_ necesita un trabajador por conexión, ya que cada trabajador puede manejar cooperativamente miles de conexiones (siempre que el código de manejo no monopolice la CPU / bloquee todo el hilo). Específicamente, si el navegador detiene la solicitud, simplemente significa que cuando gunicorn read() s del socket, bloqueará un greenlet, pero como read debería ser parcheado, cederá a los otros greenlets.

@ikonst
Este problema habla de ejecutar gunicorn con la configuración predeterminada. La clase de trabajador predeterminada es sync http://docs.gunicorn.org/en/stable/settings.html#worker -class

sync trabajadores de

No sé qué me causó esto, pero cambiar del tipo de trabajador predeterminado sync a eventlet resolvió el problema:

CMD pipenv run gunicorn webapp -b 0.0.0.0:8080 -k eventlet

Buena suerte.

Tal vez esto solo me ayude a mí, pero como me tomó 7 horas depurar este problema de mi lado (una aplicación Flask / Gunicorn ejecutándose en Docker en EC2), si puedo ahorrarle este dolor de cabeza a algunas personas, es una pequeña victoria.

El límite de memoria del contenedor era demasiado bajo.

Si tengo pérdidas de memoria en el futuro, intentaré poner un límite de memoria más alto, pero por ahora, ningún límite será suficiente.

Gracias

def trace_on_abort():
    import signal
    import traceback

    def print_trace(sig, frame):
        print(''.join(traceback.format_stack(frame)))

    signal.signal(signal.SIGABRT, print_trace)

Me ayudas demasiado. EHU)))

¿A dónde va este método trace_on_abort() ? ¿En el archivo de código de la aplicación? ¿Necesita una anotación?

@ mattg-vbt agregue esto al comienzo de su aplicación cuando necesite depurar y elimínelo una vez que haya terminado de depurar

@ikonst Agregué esto a mi aplicación, pero no veo que se golpee. Obtengo el tiempo de espera del trabajador, pero este método no se activa.

@ mattg-vbt ¿puedes intentar hacer kill -ABRT $pid para ver que se llama a la función print_trace ? (la idea es que obtendrá SIGABRT de werkzeug cuando su trabajador agote el tiempo de espera, pero primero verifiquemos que se haya llamado)

@asnisarenko para los menos inteligentes entre nosotros, ¿cómo podría actualizar el archivo de proceso?

web gunicorn app:app -k gevent --worker-connections 1000 ?

@SumNeuron
Si está utilizando trabajadores de gevent (en lugar de trabajadores de sincronización), no debería estar abordando este problema. Entonces, el comando que publicaste parece estar bien.

Recibo este problema con los trabajadores de gevent solo después de la inicialización, lo cual es un poco molesto porque estoy procesando algunas tareas antes de iniciar mi aplicación. Pero estoy estableciendo un tiempo de espera alto por ahora.
He publicado un repositorio de prueba reproducible aquí: https://github.com/zamponotiropita/test-gunicorn-worker-timeout -> test_0 falla, test_1 y test_2 pasan

@zamponotiropita ¿Estás intentando hacer esto por trabajador o por aplicación antes de la bifurcación?

@ikonst , compruebe el archivo de ejecución run.sh , es por trabajador. El problema no surgió con la precarga, pero tuve problemas para conectarme a la base de datos durante la precarga, ya que el objeto de la aplicación (y con él junto la conexión de la base de datos) se copia y pasa los procesos al bifurcar -> mi base de datos no podía manejar conexiones idénticas de maestro y trabajadores, y no pude encontrar una solución

Tengo un problema similar. Estoy tratando de generar una gran cantidad de datos sobre la marcha con Flask usando
este método, y falla porque el trabajador agota el tiempo de espera después de que expire lo que se estableció en --timeout . Un ejemplo mínimo para reproducir:

test_gunicorn_timeout.py

import flask
from time import sleep


app = flask.Flask(__name__)


@app.route('/')
def gunicorn_timeout():
    def generator():
        for _ in range(10):
            yield b'Yet another line...'
            sleep(2)
    return flask.Response(generator(), mimetype='text/plain')

Luego ejecute gunicorn --timeout 10 test_gunicorn_timeout:app y cuando solicite localhost:8000 después de 10 segundos obtendrá un
[CRITICAL] WORKER TIMEOUT .

También intenté ejecutar con -k gevent y -k eventlet y nada cambió.

Estoy en Windows 10 Pro. Con Docker compose
gunicorn app -b 0.0.0.0:8000 -k gevent
Funcionó para mí instalando gevent en mi contenedor de Python
Cómo instalar gevent

Luego ejecute gunicorn --timeout 10 test_gunicorn_timeout:app y cuando solicite localhost:8000 después de 10 segundos obtendrá un
[CRITICAL] WORKER TIMEOUT .

También intenté ejecutar con -k gevent y -k eventlet y no cambió nada.

@ltskv

¿Ha encontrado una solución al problema [CRÍTICO] DE TIEMPO MUERTO DEL TRABAJADOR?

Tengo un problema similar con un punto final de transmisión de matraces que estoy tratando de implementar en heroku (que usa gunicorn). Allí, se supone que la interfaz del proxy mantiene viva la conexión siempre que se envíen algunos datos en 30 segundos, pero parece que Gunicorn simplemente mata el proceso si no ha finalizado en 30 segundos a pesar de que todavía se está ejecutando y produciendo datos.

La documentación de gunicorn no me resulta del todo clara en este punto. Para --timeout dice que Workers silent for more than this many seconds are killed and restarted. Pero parece que los trabajadores mueren después de 30 segundos a pesar de que todavía producen datos?

La documentación de gunicorn no me resulta del todo clara en este punto. Para --timeout, dice que los trabajadores en silencio durante más de este número de segundos se eliminan y se reinician. ¿Pero parece que los trabajadores mueren después de 30 segundos a pesar de que todavía producen datos?

@ kurt-hectic que la documentación debería mejorarse. Por silencioso, entendemos silencioso desde la perspectiva del proceso arbitral, que se comunica con los trabajadores a través de un archivo temporal. Si el trabajador está ocupado enviando datos, no actualiza ese archivo. Desde la perspectiva del árbitro, al trabajador le faltan latidos.

Ver también # 1974.

El uso de cualquier trabajador que no sea el predeterminado, el trabajador síncrono debería mitigar el problema con la transmisión de cuerpos grandes, porque los otros trabajadores controlarán el archivo temporal incluso cuando estén manejando solicitudes.

@ kurt-hectic Volví a verificar la opción -k gevent e inserté sleep(0) entre las iteraciones del generador y realmente funcionó para mí (no estoy seguro de por qué no funcionó en ese momento Aunque publiqué la pregunta).

--tiempo de espera = 5

Ésta es la causa más común de este problema.

Espero que mi solución pueda ayudarte. Me encontré con este problema crítico de tiempo de espera del trabajador hace unos días y probé algunas soluciones. Ahora funciona bien.

Aquí están mi comprensión y soluciones:

  1. Prueba la precarga en gunicorn

No inicia los trabajadores porque necesita más tiempo para cargar el paquete, como el backend de tensorflow, para iniciar el servicio. Entonces, cuando experimente un tiempo de inicio lento de la aplicación, intente habilitar la opción de precarga en gunicorn (consulte https://devcenter.heroku.com/articles/python-gunicorn#advanced-configuration).

gunicorn hello: aplicación --precarga

  1. Intenta aumentar el tiempo de espera para gunicorn

El tiempo de espera predeterminado es de 30 segundos. Si su aplicación realmente necesita mucho tiempo para finalizar una API, aumente el tiempo de espera.

gunicorn hello: app --timeout 10

Sin embargo, desde mi perspectiva, no tiene sentido si una API necesita más de 1 minuto para terminar. Si es así, intente hacer algún progreso en su código.

  1. Si está utilizando k8s, también puede establecer un timeoutSeconds para su contenedor / imagen en yaml.

Hoy me enfrenté al mismo problema. En mi caso, la api tardó aproximadamente un minuto en calcular los datos y devolverlos al cliente, lo que resultó en errores CRITICAL WORKER TIMEOUT. Lo resolví aumentando la marca de tiempo de espera para gunicorn a más de un minuto; funcionó, no vi que el problema volviera. Espero que esto ayude. Estoy usando uvicorn.workers.UvicornWorker.

Arreglé esto agregando trabajadores adicionales a gnuicorn:

web: gunicorn --workers=3 BlocAPI:app --log-file -

No tengo idea de por qué.

¿Quizás tuviste un punto muerto? ¿Tu aplicación se hace solicitudes a sí misma?

El domingo, 5 de enero de 2020, 10:52 alpinechicken, [email protected] escribió:

Arreglé esto agregando trabajadores adicionales a gnuicorn:

web: gunicorn --workers = 3 BlocAPI: app --log-file -

No tengo idea de por qué.

-
Estás recibiendo esto porque comentaste.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/benoitc/gunicorn/issues/1801?email_source=notifications&email_token=AAAEQJVQRCW3C63EZJWIN5DQ4G3WTA5CNFSM4FDLD5PKYY3PNVWWK3TUL52HS4DFVDVREXHG43V
o darse de baja
https://github.com/notifications/unsubscribe-auth/AAAEQJXZM4NLK56DZMFSZALQ4G3WTANCNFSM4FDLD5PA
.

Sí, una ruta llama a otra, ¿es eso malo?

Significa que necesita al menos dos trabajadores; de lo contrario, su servidor
punto muerto. La solicitud esperará hasta que el servidor responda a la segunda
solicitud (que estaría en cola).

Obtienes una solicitud simultánea por trabajador.

El lunes 6 de enero de 2020 a las 02:45 alpinechicken, [email protected] escribió:

Sí, una ruta llama a otra, ¿es eso malo?

-
Estás recibiendo esto porque comentaste.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/benoitc/gunicorn/issues/1801?email_source=notifications&email_token=AAAEQJSFEFBBI6AMZJCM4C3Q4KLOJA5CNFSM4FDLD5PKYY3PNVWWK3TUL52HS4DFVREXWEXG43WZVMV300 ,
o darse de baja
https://github.com/notifications/unsubscribe-auth/AAAEQJXTCPOFIZJU5PUPOODQ4KLOJANCNFSM4FDLD5PA
.

Ah, eso tiene sentido. ¡Gracias!

El martes, 7 de enero de 2020 a las 6:23 a.m., bobf [email protected] escribió:

Significa que necesita al menos dos trabajadores; de lo contrario, su servidor
punto muerto. La solicitud esperará hasta que el servidor responda a la segunda
solicitud (que estaría en cola).

Obtienes una solicitud simultánea por trabajador.

El lunes 6 de enero de 2020 a las 02:45 alpinechicken, [email protected] escribió:

Sí, una ruta llama a otra, ¿es eso malo?

-
Estás recibiendo esto porque comentaste.
Responda a este correo electrónico directamente, véalo en GitHub
<
https://github.com/benoitc/gunicorn/issues/1801?email_source=notifications&email_token=AAAEQJSFEFBBI6AMZJCM4C3Q4KLOJA5CNFSM4FDLD5PKYY3PNVWWK3TUL52HS4DFVREXWEXWI5VMVDMVDFVREXWJWI5MV
,
o darse de baja
<
https://github.com/notifications/unsubscribe-auth/AAAEQJXTCPOFIZJU5PUPOODQ4KLOJANCNFSM4FDLD5PA

.

-
Estás recibiendo esto porque comentaste.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/benoitc/gunicorn/issues/1801?email_source=notifications&email_token=AAH2WRPVPVO2EJ53BKQW5B3Q4OHLRA5CNFSM4FDLD5PKYY3PNVWWK3TUL52HS4DFVBIGWJWK3TUL52HS4DFVDVREXWG43V ,
o darse de baja
https://github.com/notifications/unsubscribe-auth/AAH2WRM2LLIB4O6OHCU5UG3Q4OHLRANCNFSM4FDLD5PA
.

clase_trabajador ',' sincronización ')

Puedo resolver este problema haciendo coincidir el número de trabajadores y el número de subprocesos.

Había configurado workers = (2 * cpu_count) + 1 y no configuré hilos.

Una vez que cambié threads = workers , todo comenzó a funcionar bien. Por si acaso, si esto ayuda a alguien.

asi es como luce ahora

def run(host='0.0.0.0', port=8080, workers=1 + (multiprocessing.cpu_count() * 2)):
    """Run the app with Gunicorn."""

    if app.debug:
        app.run(host, int(port), use_reloader=False)
    else:
        gunicorn = WSGIApplication()
        gunicorn.load_wsgiapp = lambda: app
        gunicorn.cfg.set('bind', '%s:%s' % (host, port))
        gunicorn.cfg.set('workers', workers)
        gunicorn.cfg.set('threads', workers)
        gunicorn.cfg.set('pidfile', None)
        gunicorn.cfg.set('worker_class', 'sync')
        gunicorn.cfg.set('keepalive', 10)
        gunicorn.cfg.set('accesslog', '-')
        gunicorn.cfg.set('errorlog', '-')
        gunicorn.cfg.set('reload', True)
        gunicorn.chdir()
        gunicorn.run()

Según el documento de gunicorn, cambia la clase trabajadora de sync a gthread si se menciona más de un hilo.
PD:-
Si intenta usar el tipo de trabajador de sincronización y establece la configuración de subprocesos en más de 1, se usará el tipo de trabajador gthread en su lugar.

Mi caso:

Entorno: Ubuntu18.04 + gunicorn + nginx + flask

pip instalar gunicorn [gevent] en mi entorno virtual

Cambiar gunicorn -b localhost:8000 -w 4 web:app a gunicorn -b localhost:8000 -k gevent web:app

Funciona.

Gracias a todos los aquí presentes que han hecho tanto para ayudarse mutuamente a resolver sus problemas. Continúe publicando sobre este problema si le parece apropiado.

Sin embargo, estoy cerrando este problema porque no creo que haya ningún error en Gunicorn aquí y no creo que haya ninguna acción que tomar, aunque con mucho gusto ayudaré a revisar los RP que intentan agregar documentación para esto de alguna manera o mejorar mensajes de registro.

Por favor, no malinterpretes mi intención. Si sospecha de un error en Gunicorn y desea seguir discutiendo, hágalo. Preferiblemente, abra un nuevo ticket con una aplicación de ejemplo que reproduzca su problema. Sin embargo, en este punto, hay demasiados problemas, resoluciones y conversaciones diferentes en este número para que sea muy legible.

Si ejecuta Gunicorn sin un proxy inverso de almacenamiento en búfer frente a él, _obtendrá_ tiempos de espera con el trabajador de sincronización predeterminado por cualquier número de razones. Los más comunes son:

  • Clientes lentos
  • Conexiones de preconexión / captación previa que los navegadores y proxies dejan abiertas
  • Respuestas largas debido a llamar a API externas o hacer mucho trabajo vinculado a la CPU

Puede cambiar a tipos de trabajador asíncronos o subprocesados, o puede poner Gunicorn detrás de un proxy inverso de almacenamiento en búfer. Si sabe que sus tiempos de espera se deben a que su propio código hace llamadas lentas a API externas o realiza un trabajo significativo que espera, puede aumentar la opción --timeout .

Significa que necesita al menos dos trabajadores, de lo contrario su servidor se bloqueará. La solicitud esperará hasta que el servidor responda a la segunda solicitud (que estaría en cola). Obtienes una solicitud simultánea por trabajador.
...
El lun, 6 de enero de 2020, 02:45 alpinechicken, @ . * > escribió: Sí, una ruta llama a otra, ¿es eso malo?

¿Es este el caso cuando se llama a la función 'redireccionar' como valor de retorno para una ruta?

¿Es este el caso cuando se llama a la función 'redireccionar' como valor de retorno para una ruta?

No. Un redireccionamiento de matraz responde con un redireccionamiento HTTP y el trabajador es libre de aceptar una nueva solicitud. El cliente realiza otra solicitud cuando ve esta respuesta y siempre que un trabajador esté listo recibirá esta solicitud.

Arreglé esto agregando trabajadores adicionales a gnuicorn:

web: gunicorn --workers=3 BlocAPI:app --log-file -

No tengo idea de por qué.

¿Está esto relacionado con el comentario de @anilpai anterior donde estableció workers=1 + (multiprocessing.cpu_count() * 2) ..?

Tuve un problema similar a este. Resulta que tuve un error en mi punto de entrada a la aplicación. De la depuración, parecía que esencialmente estaba lanzando una aplicación de matraz de gunicorn, cuyos trabajadores luego ingresan en un bucle de conexión infinito que se agota cada 30 segundos.

Estoy seguro de que esto no afecta a todos los usuarios anteriores, pero puede afectar a algunos.

En mi archivo module/wsgi.py que estoy ejecutando con gunicorn module.wsgi tenía -

application = my_create_app_function()
application.run(host="0.0.0.0")

Mientras que debería haber tenido ...

application = my_create_app_function()
if __name__ == "__main__":
     application.run(host="0.0.0.0")

Básicamente, no querrás llamar a application.run() cuando uses gunicorn. El __name__ debajo de gunicorn no será "__main__" , pero lo estará en Flask, por lo que aún puede depurar localmente.

No pude encontrar una referencia a esto en los documentos de gunicorn, pero podría imaginar que se trata de un caso de error común, por lo que tal vez sea necesaria alguna advertencia.

Esto todavía está ocurriendo. Agregar --preload a la llamada de Gunicorn solucionó el problema.

¿Este error aún no se ha solucionado? Estoy observando este comportamiento exacto.

Gunicorn comienza así en systemd:

[Service]
PIDFile = /run/gunicorn.pid
WorkingDirectory = /home/pi/pyTest
ExecStart=/usr/local/bin/gunicorn  app:app  -b 0.0.0.0:80 --pid /run/gunicorn.pid
RuntimeDirectory=/home/pi/pyTest
Restart=always
KillSignal=SIGQUIT
Type=notify
StandardError=syslog
NotifyAccess=all
User=root
Group=root
ExecReload = /bin/kill -s HUP $MAINPID
ExecStop = /bin/kill -s TERM $MAINPID
ExecStopPost = /bin/rm -rf /run/gunicorn
PrivateTmp = true

El proceso de trabajo se agota y se reinicia constantemente:

Jul 10 15:19:20 raspberryVM gunicorn[10941]: [2020-07-10 15:19:20 -0700] [10941] [CRITICAL] WORKER TIMEOUT (pid:10944)
Jul 10 15:19:20 raspberryVM gunicorn[10941]: [2020-07-10 15:19:20 -0700] [10944] [INFO] Worker exiting (pid: 10944)
Jul 10 15:20:15 raspberryVM gunicorn[10941]: [2020-07-10 15:20:15 -0700] [10985] [INFO] Booting worker with pid: 10985

app.py es una aplicación trival Flask.

¿Este problema está cerrado como No solucionar?

Yo también estaba teniendo el mismo problema

Pero después de la depuración, puedo encontrar que mientras gunicorn inicia la aplicación Django, una de las dependencias tardaba más del tiempo esperado (en mi caso, la conexión de base de datos externa), lo que hace que el trabajador gunicron agote el tiempo de espera.

Cuando resolví el problema de conexión, el problema del tiempo de espera también se resolvió ...

Este no sería mi caso. Probé con el tipo de aplicación "Hello, World", sin dependencias. Así que todavía estoy desconcertado por esto, pero parece que no es posible tener Gunicorn con un hilo de larga duración. El proceso de trabajo se reinicia y, por lo tanto, mata el subproceso de larga ejecución.

@leonbrag
Es probable que esto NO sea un error de gunicorn. Vea mi elogio arriba en el hilo. Es un efecto secundario de los navegadores que envían conexiones TCP "previstas" vacías y ejecutan gunicorn con solo unos pocos trabajadores de sincronización sin protección contra conexiones TCP vacías.

¿Existe una arquitectura / diseño de referencia que muestre una forma adecuada de configurar la aplicación de matraz Gunicorn con un hilo de trabajo largo (permanente)?

Si esto no es un error, entonces parece un artefacto o una limitación de la arquitectura / diseño de Gunicorn.

¿Por qué el trabajador de sincronización no se ejecuta para siempre y acepta conexiones de clientes? Dicho trabajador cerrará el socket según sea necesario, pero continuará ejecutándose sin salir (y, por lo tanto, el hilo de trabajo continuará ejecutándose).

@leonbrag
Debe ser más específico sobre el problema que está tratando de resolver.

El problema discutido en este hilo ocurre en el entorno de desarrollo y la solución más fácil es agregar más trabajadores de sincronización o usar trabajadores con hilos.

Si desea evitar este problema en la configuración de producción, puede usar gevent workers o puede poner un nginx enfrente de gunicorn.
Algunas PaaS ya colocan un nginx frente a su contenedor docker, por lo que no tiene que preocuparse por eso. Nuevamente, la solución depende del contexto y los detalles.

Esta es una buena lectura.
https://www.brianstorti.com/the-role-of-a-reverse-proxy-to-protect-your-application-against-slow-clients/

puede consultar la página de diseño de la documentación. Los trabajadores asíncronos es uno
forma de ejecutar tareas largas.

El sábado 8 de agosto de 2020 a las 18:00, leonbrag [email protected] escribió:

¿Existe una arquitectura / diseño de referencia que muestre una forma adecuada de configurar
¿Aplicación de matraz Gunicorn con hilo de trabajo largo (permanente)?

Si esto no es un error, entonces parece un artefacto o una limitación del
Arquitectura / diseño Gunicorn.

¿Por qué el trabajador de sincronización no se ejecuta para siempre y acepta conexiones de clientes? Semejante
El trabajador cerrará el socket según sea necesario, pero continuará ejecutándose sin salir
(y por lo tanto, el hilo de trabajo continúa ejecutándose).

-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/benoitc/gunicorn/issues/1801#issuecomment-670944797 ,
o darse de baja
https://github.com/notifications/unsubscribe-auth/AAADRIWRQGIP3R5PMVJ5ENTR7VZA3ANCNFSM4FDLD5PA
.

>

Enviado desde mi móvil

web: gunicorn --workers = 3 aplicación: aplicación --timeout 200 --log-file -

Arreglé mi problema aumentando el tiempo de espera

Consulte también el n.º 1388 para conocer los problemas de tmpfs relacionados con Docker.

Oh, muchas gracias Randall, olvidé agregar --worker-tmp-dir /dev/shm a los argumentos de gunicorn cuando estaba ejecutando gunicorn en Docker.

Por cierto, ¿64 Mb serán suficientes para el caché de gunicorn?

aplicación gunicorn
O
aplicación gunicorn

Funcionó para mí ... Prefiero el tiempo fuera uno.

Extraño, agregué --worker-tmp-dir /dev/shm pero sigo recibiendo:

[2020-11-27 21:01:42 +0000] [1] [CRITICAL] WORKER TIMEOUT (pid:17)

Para asegurarme de que /dev/shm sea ​​ramfs, lo comparé:

image

Los parámetros son los siguientes:

    command: /bin/bash -c "cd /code/ && pipenv run gunicorn --worker-tmp-dir /dev/shm conf.wsgi:application --bind 0.0.0.0:8022 --workers 5 --worker-connections=1000"

PD: estoy usando PyPy

El tiempo de espera de

@ivictbor gracias por lmk. 1000 es para referencia. Sin embargo, la aplicación se puso en marcha una vez que se cargó. Funciona perfectamente bien.

También obtuve este problema de error y, después de varias veces, descubrí que el problema probablemente se debe a:

  1. Configuración de Nginx
  2. Gunicorn / Uwsgi

Si implementa su aplicación en la nube como GAE, eso no mostrará ningún error.
puede intentar sacar a la superficie el error utilizando esta solución de caso: https://stackoverflow.com/questions/38012797/google-app-engine-502-bad-gateway-with-nodejs

Si se levanta 502 puerta de enlace incorrecta;
probablemente tendrá 2 posibilidades:

  1. gunicorn no está corriendo
  2. gunicorn tiene tiempo de espera

sulotion completo explicado aquí: https://www.datadoghq.com/blog/nginx-502-bad-gateway-errors-gunicorn/

Espero que se pueda solucionar cualquier error en [CRITICAL] WORKER TIMEOUT

Añadiendo otra posibilidad para quienes encuentren este hilo ...

Esto también puede deberse a que la ventana acoplable impuso restricciones de recursos que son demasiado bajas para su aplicación web. Por ejemplo, tenía las siguientes limitaciones:

services:
  web_app:
    image: blah-blah
    deploy:
      resources:
        limits:
          cpus: "0.25"
          memory: 128M

y estos eran evidentemente demasiado bajos para gunicorn por lo que constantemente recibía el error [CRITICAL] WORKER TIMEOUT hasta que eliminé las restricciones.

Para gunicorn, estos recursos están perfectamente bien. Pero de hecho necesitas
avión para el número de trabajadores y los recursos necesarios para su
solicitud. 128M y 0.25cpu parecen realmente bajos para una aplicación web
escrito en Python ... en general, necesita al menos 1 núcleo / vcpu y
512 MB de RAM como mínimo.

El viernes 26 de marzo de 2021 a las 02:14, Colton Hicks @ . * > escribió:

Añadiendo otra posibilidad para quienes encuentren este hilo ...

Esto también puede deberse a que la ventana acoplable impuso restricciones de recursos que
son demasiado bajos para su aplicación web. Por ejemplo, tuve lo siguiente
restricciones:

servicios:
Aplicación Web:
imagen: bla-bla
desplegar:
recursos:
límites:
cpus: "0.25"
memoria: 128M

y estos eran evidentemente demasiado bajos para gunicorn, así que constantemente obtuve el [CRÍTICO]
Error de WORKER TIMEOUT hasta que eliminé las restricciones.

-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/benoitc/gunicorn/issues/1801#issuecomment-807855647 ,
o darse de baja
https://github.com/notifications/unsubscribe-auth/AAADRITPZB7BMA6QW7LFNVLTFPNV3ANCNFSM4FDLD5PA
.

>

Enviado desde mi móvil

--timeout = 1000 trabajado para mí. El problema era una máquina de GCP con pocos recursos de CPU. Funcionó bien en mi máquina local con el tiempo de espera predeterminado.

¿Fue útil esta página
0 / 5 - 0 calificaciones