Gunicorn: TEMPO LIMITE CRÍTICO DO TRABALHADOR ao executar o aplicativo Flask

Criado em 5 jun. 2018  ·  82Comentários  ·  Fonte: benoitc/gunicorn

Parece que já houve vários relatórios relacionados ao erro [CRITICAL] WORKER TIMEOUT mas eles continuam aparecendo. Aqui está o meu problema.

Estou executando este aplicativo Flask hello world.

from flask import Flask
application = Flask(__name__)

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

O comando gunicorn é este:

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

E esta é a saída do console:

[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

Você pode explicar claramente por que recebo o erro e se ele é esperado neste exemplo? Como faço para corrigir isso ou se é um comportamento esperado, por que erro crítico então?

Investigation unconfirmed

Comentários muito úteis

Usar gunicorn com gevent não corrigiu o bug.

Todos 82 comentários

O erro não é esperado, mas não há nada em seu exemplo que mostre por que isso acontece. Conte-nos mais sobre seu ambiente.

  • Qual cliente é usado para se conectar ao Gunicorn?
  • Qual proxy reverso, se houver, é usado para se conectar ao Gunicorn?

Conte-nos mais sobre seu ambiente.

  • Qual cliente é usado para se conectar ao Gunicorn?
    => Acabei de enviar uma solicitação do Chromium: http: // localhost : 5000 /
  • Qual proxy reverso, se houver, é usado para se conectar ao Gunicorn?
    => Sem proxy, apenas Gunicorn + Flask

Acabei de reproduzir o problema em uma configuração completamente nova. Aqui estão as etapas:

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

O hello.py é exatamente o mesmo aplicativo Flask que postei no relatório inicial.
Abaixo está o log 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 Acho que é por causa do tempo limite padrão, seu trabalhador ficou em silêncio por 30s. http://docs.gunicorn.org/en/stable/settings.html#timeout

Do seu log,

[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)

Estou vendo a mesma coisa: os workers estão expirando, mesmo quando não atendem a solicitações, com o sync worker.
Nesse sentido, o log de nível crítico é bastante confuso.

Tente usar o trabalhador Gevent para resolver isso.

Nesse sentido, o log de nível crítico é bastante confuso.

Exatamente, essa era minha pergunta original: se é um comportamento esperado, por que erro crítico então?
Também seria bom obter algumas informações básicas sobre por que os trabalhadores precisam ser reiniciados; talvez isso pudesse ser adicionado ao documento de design .

Estou vendo isso também (reproduzido usando examples/test.py com gunicorn test:app -b localhost:9595 --log-level=debug --timeout=5 ) e concordo que o nível crítico é um pouco confuso. Eu ficaria bem em alterá-lo para o nível de depuração. @benoitc @tilgovi o que você acha?

Estou pensando que o nível de informação pode ser um pouco melhor.

Eu tive o mesmo com MSYS2 no Win10, mas finalmente consegui resolver.

em notificar () de ... \ gunicorn \ workers \ workertmp.py, os.fchmod é usado originalmente. Mas não funciona no MSYS. Em vez de os.fchmod, usei os.utime. O código é seguido. Acho que pode funcionar para todas as 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 Eu não esperaria que o trabalhador saia porque nenhuma solicitação aconteceu. Este erro só deve acontecer se o trabalhador tiver sido mantido ocupado por um tempo> até o tempo limite. Portanto, o erro é crítico. Imo, devemos melhorar a documentação para fornecer mais casos de uso e respostas a esses erros.

Se o erro ainda ocorrer quando o trabalhador não estiver ocupado, então há algo mais acontecendo e provavelmente temos um bug.

[EDITAR]
O mesmo bug para mim.
Com Django 1.10 / gunicorn 19.6.0 / Python 2.7.15 em python2.7-alpine no Debian 8.8 e kernel padrão 3.16, tudo estava funcionando bem.
Depois de atualizar para Django 1.11 e gunicorn 19.8.1, os trabalhadores continuam falhando na inicialização com [CRITICAL WORKER TIMEOUT].
O downgrade do gunicorn para 19.6.0 não resolve o problema.
Atualizamos o kernel do host para 4.9.0 (estava agendado) e os workers inicializaram com sucesso sem erros.
Mas:

  • nós usamos 4 trabalhadores
  • após exatamente 4 chamadas para o aplicativo Django, as próximas chamadas expirarão, mostrando [CRITICAL WORKER TIMEOUT] nos logs
  • o comando linux top mostra 4 processos gunicorn presos com um consumo de CPU muito alto.

Vamos experimentar o gunicorn gevent para ver se conseguimos colocar nosso aplicativo online novamente.

Usar gunicorn com gevent não corrigiu o bug.

alguma atualização sobre este problema?

Parece que @neocolor identificou um bug real no MSYS. Pode merecer um problema separado.

@bigunyak em qual plataforma você está rodando? Tentei reproduzir com o exemplo simples e não consigo seguir exatamente os passos descritos acima. Isso está de acordo com minha experiência em execução de vários aplicativos em produção em vários frameworks. O sistema de notificação do trabalhador não mudou recentemente, que eu saiba. Minha plataforma é Python 3.7 no MacOS 10.13.6, mas eu executo o Gunicorn em produção com trabalhos de sincronização para vários aplicativos no Python 2.7 e 3.6.5 e só vejo o tempo limite do trabalhador quando há solicitações legitimamente longas que bloqueiam os trabalhadores.

Para @Tberdy : o que acontece se você tentar definir --worker-tmp-dir em algum lugar fora do sistema de arquivos tmpfs? Só estou me perguntando se talvez alpine ou docker ou a combinação interfere de alguma forma na forma como os trabalhadores notificam o árbitro.

Consulte também # 1388 para problemas de tmpfs relacionados ao Docker.

eu tenho esse problema para.

Eu também tenho esse problema, a sincronização do gunicorn estava funcionando perfeitamente bem até ontem à noite, mas começou a relatar, o tempo limite dos workers [CRÍTICO] usando o gevent parece resolver meu problema, mas eu realmente gostaria de saber por que isso aconteceu.

@ timoj58 @cjmash você pode fornecer mais detalhes sobre o problema? Como você está executando o gunicorn (em uma vm ?, opções ...), qual sistema de arquivos, SO? Qualquer coisa que pudesse ajudar a reproduzir seria muito útil :)

@benoitc Estou executando o gunicorn para iniciar meu projeto Django no kubernetes, meus argumentos gunicorn são --bind = $ port --workers = 7 --timeout = 1200 --log-level = debug --access-logfile - error-logfile - "

os erros que recebo dos registros

`` `E [2018-08-09 21:47:56 +0000] [13] [INFO] Inicializando trabalhador com pid: 13

E [2018-08-09 21:47:56 +0000] [14] [INFO] Inicializando trabalhador com pid: 14

E [2018-08-09 21:47:56 +0000] [12] [INFO] Inicializando trabalhador com pid: 12

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

E [2018-08-09 21:47:56 +0000] [11] [INFO] Inicializando trabalhador com pid: 11

E [2018-08-09 21:47:55 +0000] [10] [INFO] Inicializando trabalhador com pid: 10

E [2018-08-09 21:47:55 +0000] [9] [INFO] Inicializando trabalhador com pid: 9

E [2018-08-09 21:47:55 +0000] [8] [INFO] Inicializando trabalhador com pid: 8

E [2018-08-09 21:47:55 +0000] [1] [INFO] Usando trabalhador: sincronizar

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

E [2018-08-09 21:47:55 +0000] [1] [DEBUG] Árbitro inicializado

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

E raw_paste_global_conf: []

E cifras: TLSv1

E do_handshake_on_connect: False

E suppress_ragged_eofs: Verdadeiro

E ca_certs: Nenhum

E cert_reqs: 0

E ssl_version: 2

E certfile: Nenhum

Arquivo-chave E: Nenhum

E proxy_allow_ips: ['127.0.0.1']

E proxy_protocol: False

E on_exit:

E nworkers_changed:

E worker_exit:

E child_exit:

E post_request:

E pre_request:

E pre_exec:

E worker_abort:

E worker_int:

E post_worker_init:

E post_fork:

E pre_fork:

E quando já:

E on_reload:

E on_starting:

E colar: Nenhum

E pythonpath: Nenhum

E default_proc_name: art.wsgi

E proc_name: Nenhum

E statsd_prefix:

E statsd_host: Nenhum

E enable_stdio_inheritance: False

E syslog_facility: usuário

E syslog_prefix: Nenhum

E syslog: False

E syslog_addr: udp: // localhost : 514

E logconfig: Nenhum

E logger_class: gunicorn.glogging.Logger

E capture_output: False

E loglevel: debug

E errorlog: -

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

E accesslog: -

E forwarded_allow_ips: ['127.0.0.1']

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

E tmp_upload_dir: Nenhum

E initgroups: False

E umask: 0

Grupo E: 0

E usuário: 0

E worker_tmp_dir: Nenhum

E pidfile: Nenhum

E raw_env: []

E daemon: False

E chdir: / usr / src / app

E sendfile: Nenhum

E preload_app: False

E check_config: False

E spew: False

E reload_engine: auto

E reload: False

E limit_request_field_size: 8190

E limit_request_fields: 100

E limit_request_line: 4094

E keepalive: 2

E graceful_timeout: 30

Tempo limite E: 1200

E max_requests_jitter: 0

E max_requests: 0

E trabalhador_conexões: 1000

E tópicos: 1

E worker_class: sync

Trabalhadores E: 7

E backlog: 2048

E bind: ['0.0.0.0:4040']

E config: Nenhum

E [2018-08-09 21:47:55 +0000] [1] [DEBUG] Configuração atual:

I Nenhuma migração para aplicar.

I Executando migrações:

Eu aplico todas as migrações: admin, auth, contenttypes, core, painel, jet, oauth2_provider, sessões

I Operações a realizar:

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

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

E /usr/src/app/art/wsgi.py:19: UserWarning: Não está lendo /usr/src/app/.env - não existe.

E [2018-08-09 21:47:00 +0000] [21] [INFO] Booting worker com pid: 21

E [2018-08-09 21:47:00 +0000] [1] [INFO] Sinal de manipulação: termo

E [2018-08-09 21:46:35 +0000] [12] [INFO] Inicializando trabalhador com pid: 12

E [2018-08-09 21:46:34 +0000] [13] [INFO] Inicializando trabalhador com pid: 13

E [2018-08-09 21:46:34 +0000] [11] [INFO] Inicializando trabalhador com pid: 11

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

E [2018-08-09 21:46:34 +0000] [10] [INFO] Inicializando trabalhador com pid: 10

E [2018-08-09 21:46:34 +0000] [9] [INFO] Inicializando trabalhador com pid: 9

E [2018-08-09 21:46:34 +0000] [8] [INFO] Inicializando trabalhador com pid: 8

E [2018-08-09 21:46:34 +0000] [7] [INFO] Inicializando trabalhador com pid: 7

E [2018-08-09 21:46:34 +0000] [1] [INFO] Usando trabalhador: sincronizar

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

E [2018-08-09 21:46:34 +0000] [1] [DEBUG] Árbitro inicializado

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

E raw_paste_global_conf: []

E cifras: TLSv1

E do_handshake_on_connect: False

E suppress_ragged_eofs: Verdadeiro

E ca_certs: Nenhum

E cert_reqs: 0

E ssl_version: 2

E certfile: Nenhum

Arquivo-chave E: Nenhum

E proxy_allow_ips: ['127.0.0.1']

E proxy_protocol: False

E on_exit:

E nworkers_changed:

E worker_exit:

E child_exit:

E post_request:

E pre_request:

E pre_exec:

E worker_abort:

E worker_int:

E post_worker_init:

E post_fork:

E pre_fork:

E quando já:

E on_reload:

E on_starting:

E colar: Nenhum

E pythonpath: Nenhum

E default_proc_name: art.wsgi

E proc_name: Nenhum

E statsd_prefix:

E statsd_host: Nenhum

E enable_stdio_inheritance: False

E syslog_facility: usuário

E syslog_prefix: Nenhum

E syslog: False

E syslog_addr: udp: // localhost : 514

E logconfig: Nenhum

E logger_class: gunicorn.glogging.Logger

E capture_output: False

E loglevel: debug

E errorlog: -

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

E accesslog: -

E forwarded_allow_ips: ['127.0.0.1']

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

E tmp_upload_dir: Nenhum

E initgroups: False

E umask: 0

Grupo E: 0

E usuário: 0

E worker_tmp_dir: Nenhum

E pidfile: Nenhum

E raw_env: []

E daemon: False

E chdir: / usr / src / app

E sendfile: Nenhum

E preload_app: False

E check_config: False

E spew: False

E reload_engine: auto

E reload: False

E limit_request_field_size: 8190

E limit_request_fields: 100

E limit_request_line: 4094

E keepalive: 2

E graceful_timeout: 30

Tempo limite E: 1200

E max_requests_jitter: 0

E max_requests: 0

E trabalhador_conexões: 1000

E tópicos: 1

E worker_class: sync

Trabalhadores E: 7

E backlog: 2048

E bind: ['0.0.0.0:4040']

E config: Nenhum

E [2018-08-09 21:46:34 +0000] [1] [DEBUG] Configuração atual:

`` `

Lutei um pouco para reproduzir o problema desta vez, mas ele ainda está lá na última versão do gunicorn 19.9.0.
As etapas para reproduzi-lo são exatamente as mesmas que descrevi neste post .
Meu sistema é Arch Linux x86_64 GNU / Linux (kernel 4.17.2-1-ARCH), Python 3.6.5
Aqui está um novo rastreamento de log.

~$ 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 testar, eu estava acessando http://0.0.0.0 : 5000 / no Chromium.
Abaixo está o conteúdo de Pipfile e Pipfile.lock para você ver o ambiente exato.

  • 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": {}
}

Apenas para sua informação, também estou vendo essa falha muito regularmente com:

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

Eu só tenho um wsgi.py que tem

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

Deixe-me saber se há algo que você deseja que eu tente / experimente ou se houver detalhes nos logs que você deseja que eu verifique. Estou executando o flask em uma VM do GCP.

desculpe pela resposta tardia. Estou executando como

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

Eu usei a configuração gevent etc, mas mudei meu projeto do que eu precisava para contornar o problema, portanto, a configuração básica acima (que também falhou, mas isso é esperado sem gevent)

Python versão 3.6
env: aws tensorflow_p36 otimizado (ubuntu)
nginx está sentado na frente do gunicorn, que está executando um aplicativo de frasco.

frasco versão 1.0.2
nginx versão 1.10.3
gunicorn versão 19.9.0

Eu mudei os tempos limite do nginx também, caso isso possa ter causado isso.

Enfrentando o mesmo problema com o 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

Frasco == 0.12.1
gunicorn == 19.7.1

quando inicio o servidor com o comando acima, meu sistema travou por algum tempo e os pids de trabalho continuam inicializando, embora eu tenha mantido o tempo limite de 120 segundos e o servidor não esteja aceitando uma única solicitação.

Alguma atualização sobre este problema? Eu tenho o mesmo problema

[CRÍTICO] TEMPO LIMITE DO TRABALHADOR

Quer saber se alguém conseguiu reproduzir isso em uma imagem do Docker?

Também vejo isso ao tentar implementar o trabalho ddtrace-run do datadog em um aplicativo existente começando com gunicorn -k gevent --threads 4.

Traço engraçado de um SystemExit que eu nunca vi antes também ...
[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

Consigo resolver esse problema combinando o número de trabalhadores e o número de threads.

Eu havia definido workers = (2 * cpu_count) + 1 e não defini tópicos.

Depois que mudei threads = workers , tudo começou a funcionar bem. Apenas no caso, se isso ajudar alguém.

É assim que parece agora

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()

Eu encontrei esse problema ao executar o Django com um único contêiner do Docker no AWS Elastic Beanstalk. Resolvi o problema corrigindo meus grupos de segurança para garantir que minha instância EC2 pudesse se comunicar com minha instância RDS. Eu reconheço que esta pode não ser a solução para 99% das pessoas neste problema, mas estou deixando esta nota para ajudar outras pessoas a evitar perder horas caindo nesta toca do coelho.

No meu caso, o problema foi resolvido executando systemctl daemon-reload .
Para encurtar a história, eu sabia do tempo limite padrão em 30 segundos, mas não consegui alterá-lo até que percebi que precisava recarregar o daemon systemd para aplicar as alterações ao serviço.

@bigunyak @benoitc @tilgovi
Depois de uma longa busca no Google e algumas experiências, acredito que a causa raiz desse problema é o "serviço de pré-conexão / previsão" do Chrome (que é habilitado por padrão no Chrome e no Chromium).

@jeiting fez uma boa redação sobre esse problema
https://hackernoon.com/chrome-preconnect-breaks-singly-threaded-servers-95944be16400
Algumas leituras adicionais:
https://github.com/corydolphin/flask-cors/issues/147
https://github.com/pallets/flask/issues/2169

TLDR
Em alguns casos, o Chrome / Chromium abre e mantém uma (s) conexão (ões) TCP "vazias" (ou seja, está prevendo que buscará outro recurso em breve). Se as conexões TCP "vazias" atingirem seu servidor gunicorn primeiro, qualquer solicitação "real" subsequente do chrome pode ficar presa na solicitação "vazia" até que o (s) trabalhador (es) que manipulam a solicitação "vazia" expire. É mais provável que isso aconteça se você estiver executando apenas um único trabalhador de sincronização no gunicorn. Mas, como meus experimentos descobriram, isso pode acontecer mesmo se você estiver executando vários trabalhos de sincronização.

Meu ambiente

  • Meu sistema operacional nativo é Ubuntu 17
  • Eu tenho uma API de descanso em execução em um contêiner docker local. Linhas relevantes do 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
......
  • Tenho 3 navegadores instalados: Firefox 61.0.1, Chromium 67.0.3396.99, Chrome 70.0.3538.102
  • Eu tenho um app react que é servido de um container docker diferente em uma porta diferente
  • O aplicativo react faz solicitações CORS AJAX para minha API (são solicitações CORS porque o javascript é servido em uma porta localhost enquanto envia chamadas de API para outra porta localhost)
  • A solicitação que sempre é "bloqueada" em meus experimentos é uma solicitação CORS OPTIONS (acionada pelo navegador para solicitar permissão para executar uma solicitação POST). Parece lógico que um navegador tentaria fazer conexões preditivas com a chamada OPTIONS porque provavelmente seguirá com uma chamada POST.

Experimento 1
Configuração do Gunicorn: 1 trabalhador de sincronização (tempo limite padrão de 30s)

Firefox: em quase todo carregamento de página de reação, a solicitação CORS OPTIONS é bloqueada por 5s e, em seguida, é bem-sucedida.
Chromium: em CADA carregamento de página de reação, a solicitação CORS OPTIONS é bloqueada por 1,5 minuto !!!! e então consegue.
Chromium (serviço de previsão desativado): tudo carrega bem
Chrome: carrega tudo bem

Experimento 2
Configuração do Gunicorn: 4 workers de sincronização (tempo limite padrão de 30s)

Firefox: carrega tudo bem
Chromium: em cada terceiro carregamento de página de reação, a solicitação CORS OPTIONS é bloqueada por 30s e, em seguida, é bem-sucedida.
Chromium (serviço de previsão desativado): tudo carrega bem
Chrome: carrega tudo bem

Experimento 3
Configuração do Gunicorn: 8 workers de sincronização (tempo limite padrão de 30s)

Firefox: carrega tudo bem
Chromium: tudo carrega bem
Chrome: carrega tudo bem

Experimento 4
Execute o servidor de desenvolvimento de flask com threaded=True

Firefox: carrega tudo bem
Chromium: tudo carrega bem
Chrome: carrega tudo bem

Resumo da Experiência

  • O Firefox parece também ter serviço de previsão, mas parece mais elegante. (Experimento 1)
  • O Chromium parece ser o mais agressivo na criação de conexões de "previsão". Parece lançar até 3-4 conexões de "previsão" durante uma solicitação OPTIONS (Experimentos 1 e 2)
  • Surpreendentemente, embora o Chrome também tenha o serviço de previsão ativado, ele não causou nenhum problema em nenhum dos experimentos (talvez a ordem ou o número de conexões de "previsão" seja diferente do Chromium)

Solução
Em produção: a solução mais fácil é colocar o nginx na frente do gunicorn. Se você quiser entender por que o nginx resolve esse problema, aqui está um bom artigo que explica isso: https://www.brianstorti.com/the-role-of-a-reverse-proxy-to-protect-your-application-against -slow-clients /

Em dev: a correção mais fácil é executar o servidor de desenvolvimento de flask com threaded=True . Ou você pode desativar o serviço de previsão no Chrome / Chromium.

melhorias de depuração do gunicorn
Para ajudar a depurar um problema como esse no futuro, acho uma boa ideia adicionar instruções de log de depuração ao lado das chamadas select() e accept() no trabalhador de sincronização.
https://github.com/benoitc/gunicorn/blob/e974f30517261b2bc95cfb2017a8688f367c8bf3/gunicorn/workers/sync.py#L26
https://github.com/benoitc/gunicorn/blob/e974f30517261b2bc95cfb2017a8688f367c8bf3/gunicorn/workers/sync.py#L34
Isso mostraria que um trabalhador aceitou uma nova conexão TCP, mas não está recebendo nenhum dado.

@asnisarenko super artigo, obrigado. # 1929 é outro caso incomum de um cliente lento que produz um sintoma semelhante no servidor de thread único - nesse caso, o handshake TLS para uma porta não TLS parece um cliente de gravação lenta, uma vez que falha em enviar cabeçalhos sensíveis rapidamente .

Pode ser o Gunicorn, pois os workers de sincronização de thread único vão precisar de algum novo ajuste, um cliente-drop agressivo para clientes que não conseguem enviar pelo menos uma primeira linha de cabeçalho de solicitação, se não todos os cabeçalhos, dentro de um tempo razoável.

Se isso acontecer em seu aplicativo, você pode adicionar algum código de diagnóstico temporário:

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)

Esperançosamente, isso deve revelar onde seu aplicativo trava.

Por exemplo, de alguma forma consegui import flask antes de gevent.monkey.patch_all() e então o app._before_request_lock meu Flask acabou sendo um bloqueio não gevent (ou seja, simplesmente não corrigido threading.Lock ). Nesse caso, duas solicitações em sucessão próxima na inicialização do aplicativo fariam com que ele travasse (a segunda solicitação bloquearia todo o encadeamento). Mas esse era o meu bug, e seu bug pode ser diferente.

@asnisarenko Não sei por que você está read() s do soquete, ele bloqueará um greenlet, mas como read deve ser corrigido, ele cederá a os outros greenlets.

@ikonst
Este problema está relacionado à execução do gunicorn com a configuração padrão. A classe de trabalho padrão é sync http://docs.gunicorn.org/en/stable/settings.html#worker -class

sync usam um modelo de pré-bifurcação e cada trabalhador processa uma conexão / solicitação TCP por vez.

Não sei o que causou isso para mim, mas mudar do tipo de trabalhador sync padrão para eventlet resolveu o problema:

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

Boa sorte.

Talvez isso vá ajudar apenas a mim, mas como demorei 7h para depurar esse problema do meu lado (um aplicativo Flask / Gunicorn rodando no Docker no EC2), se eu puder poupar essa dor de cabeça para algumas pessoas, é uma pequena vitória.

O limite de memória do contêiner era muito baixo.

Se eu tiver vazamentos de memória no futuro, tentarei colocar um limite de memória maior, mas por enquanto, nenhum limite será suficiente.

Obrigado

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)

Você me ajuda muito. EHU)))

Para onde vai esse método trace_on_abort() ? No arquivo de código do aplicativo? Precisa de uma anotação?

@ mattg-vbt adicione isso ao início de seu aplicativo quando precisar depurar e remova-o quando terminar de depurar

@ikonst Eu adicionei isso ao meu aplicativo, mas não vejo como acertar. Eu obtenho o tempo limite do trabalhador, mas este método não é atingido.

@ mattg-vbt você pode tentar fazer kill -ABRT $pid para ver a função print_trace sendo chamada? (a ideia é que você obterá SIGABRT de werkzeug quando seu trabalhador atingir o tempo limite, mas vamos primeiro verificar se ele é chamado)

@asnisarenko para os menos experientes entre nós, como então eu atualizaria o procfile?

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

@SumNeuron
Se você estiver usando gevent workers (em vez de sync workers), não deve ter esse problema. Portanto, o comando que você postou parece bom.

Estou tendo esse problema com os trabalhadores gevent apenas na inicialização, o que é um pouco irritante, pois estou processando algumas tarefas antes de iniciar meu aplicativo. Mas estou definindo um tempo limite alto por agora.
Publiquei um repositório de teste reproduzível aqui: https://github.com/zamponotiropita/test-gunicorn-worker-timeout -> test_0 falha, test_1 e test_2 passam

@zamponotiropita Você está tentando fazer isso por trabalhador ou por aplicativo antes da bifurcação?

@ikonst , verifique o arquivo de execução run.sh , é por trabalhador. O problema não surgiu com o pré-carregamento, mas tive problemas para conectar ao banco de dados durante o pré-carregamento, uma vez que o objeto do aplicativo (e junto com ele a conexão do banco de dados) foi copiado e passou pelos processos durante a bifurcação -> meu banco de dados não conseguiu lidar conexões idênticas de mestre e trabalhadores, e não consegui encontrar uma solução alternativa

Estou tendo um problema semelhante. Estou tentando gerar muitos dados dinamicamente com o Flask usando
este método, e ele falha porque o trabalhador atinge o tempo limite após o que foi definido em --timeout expirar. Um exemplo mínimo para reproduzir:

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')

Em seguida, execute gunicorn --timeout 10 test_gunicorn_timeout:app e ao solicitar localhost:8000 após 10 segundos você obtém um
[CRITICAL] WORKER TIMEOUT .

Também tentei correr com -k gevent e -k eventlet e nada mudou.

Estou no Windows 10 Pro. Com docker compose
gunicorn app -b 0.0.0.0:8000 -k gevent
Funcionou para mim instalando gevent em meu contêiner python
Como instalar o gevent

Em seguida, execute gunicorn --timeout 10 test_gunicorn_timeout:app e ao solicitar localhost:8000 após 10 segundos, você obterá um
[CRITICAL] WORKER TIMEOUT .

Também tentei correr com -k gevent e -k eventlet e nada mudou.

@ltskv

você encontrou uma solução para o problema [CRÍTICO] TEMPO LIMITE DO TRABALHADOR?

Eu tenho um problema semelhante com um ponto de extremidade de streaming de flask que estou tentando implantar no heroku (que usa gunicorn). Lá, o front-end do proxy deve manter a conexão ativa desde que alguns dados sejam enviados em 30 segundos, mas parece que o gunicorn simplesmente mata o processo se não terminar em 30 segundos, embora ainda esteja em execução e produzindo dados.

A documentação do gunicorn não é totalmente clara para mim neste ponto. Para --timeout, ele diz que Workers silent for more than this many seconds are killed and restarted. Mas parece que os trabalhadores são mortos após 30 segundos, embora ainda produzam dados?

A documentação do gunicorn não é totalmente clara para mim neste ponto. Para --timeout, diz que os Workers em silêncio por mais do que esses segundos são eliminados e reiniciados. Mas parece que os trabalhadores morrem após 30 segundos, embora ainda produzam dados?

@ kurt-hectic que a documentação deve ser melhorada. Por silêncio, queremos dizer silêncio na perspectiva do processo do árbitro, que se comunica com os trabalhadores por meio de um arquivo temporário. Se o trabalhador estiver ocupado enviando dados, ele não atualizará esse arquivo. Da perspectiva do árbitro, o trabalhador está perdendo os batimentos cardíacos.

Veja também # 1974.

Usando qualquer trabalho diferente do padrão, o trabalho síncrono deve mitigar o problema com streaming de grandes corpos, porque os outros trabalhadores irão pulsar o arquivo temporário mesmo quando estiverem lidando com solicitações.

@ kurt-hectic Verifiquei novamente a opção -k gevent e inseri sleep(0) entre as iterações do gerador e realmente funcionou para mim (não sei por que não funcionou no momento Eu postei a pergunta embora).

--timeout = 5

Essa é a causa mais comum desse problema.

Espero que minha solução possa ajudá-lo. Eu conheci esse problema crítico de tempo limite do trabalhador há alguns dias e tentei algumas soluções. Agora funciona bem.

Aqui estão meu entendimento e soluções:

  1. Experimente a pré-carga no gunicorn

Ele falha ao inicializar os trabalhadores porque precisa de mais tempo para carregar o pacote, como o back-end do tensorflow, para iniciar o serviço. Portanto, quando o tempo de inicialização do aplicativo é lento, tente habilitar a opção de pré-carregamento no gunicorn (consulte https://devcenter.heroku.com/articles/python-gunicorn#advanced-configuration).

gunicorn hello: app --preload

  1. Tente aumentar o tempo limite para gunicorn

O tempo limite padrão é 30s. Se seu aplicativo realmente precisa de muito tempo para finalizar uma API, aumente o tempo limite.

gunicorn hello: app --timeout 10

No entanto, da minha perspectiva, não faz sentido se uma API precisar de mais de 1 minuto para ser concluída. Nesse caso, tente fazer algum progresso em seu código.

  1. Se você estiver usando o k8s, também poderá definir um timeoutSeconds para o seu contêiner / imagem no yaml.

Eu enfrentei o mesmo problema hoje. No meu caso, a api demorava cerca de um minuto para calcular os dados e retornar ao cliente, o que resultava em erros CRITICAL WORKER TIMEOUT. Eu resolvi isso aumentando o sinalizador de tempo limite do gunicorn para mais de um minuto - funcionou, não vi o problema voltar. Espero que isto ajude. Estou usando o uvicorn.workers.UvicornWorker.

Corrigi isso adicionando trabalhadores extras ao gnuicorn:

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

Não faço ideia do porquê.

Talvez você tenha um impasse? Seu aplicativo faz solicitações a si mesmo?

No domingo, 5 de janeiro de 2020, 10:52 alpinechicken, [email protected] escreveu:

Corrigi isso adicionando trabalhadores extras ao gnuicorn:

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

Não faço ideia do porquê.

-
Você está recebendo isto porque comentou.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/benoitc/gunicorn/issues/1801?email_source=notifications&email_token=AAAEQJVQRCW3C63EZJWIN5DQ4G3WTA5CNFSM4FDLD5PKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEIDTZIA#issuecomment-570899616 ,
ou cancelar
https://github.com/notifications/unsubscribe-auth/AAAEQJXZM4NLK56DZMFSZALQ4G3WTANCNFSM4FDLD5PA
.

Sim, uma rota chama outra - isso é ruim?

Isso significa que você precisa de pelo menos dois funcionários, caso contrário, seu servidor irá
impasse. O pedido irá esperar até que o servidor responda ao segundo
solicitação (que seria enfileirada).

Você recebe uma solicitação simultânea por trabalhador.

Na segunda-feira, 6 de janeiro de 2020, 02:45 alpinechicken, [email protected] escreveu:

Sim, uma rota chama outra - isso é ruim?

-
Você está recebendo isto porque comentou.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/benoitc/gunicorn/issues/1801?email_source=notifications&email_token=AAAEQJSFEFBBI6AMZJCM4C3Q4KLOJA5CNFSM4FDLD5PKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEIEIEXI#issuecomment-570983005 ,
ou cancelar
https://github.com/notifications/unsubscribe-auth/AAAEQJXTCPOFIZJU5PUPOODQ4KLOJANCNFSM4FDLD5PA
.

Ah, isso faz sentido. Obrigado!

Na terça-feira, 7 de janeiro de 2020 às 6h23 bobf [email protected] escreveu:

Isso significa que você precisa de pelo menos dois funcionários, caso contrário, seu servidor irá
impasse. O pedido irá esperar até que o servidor responda ao segundo
solicitação (que seria enfileirada).

Você recebe uma solicitação simultânea por trabalhador.

Na segunda-feira, 6 de janeiro de 2020, 02:45 alpinechicken, [email protected] escreveu:

Sim, uma rota chama outra - isso é ruim?

-
Você está recebendo isto porque comentou.
Responda a este e-mail diretamente, visualize-o no GitHub
<
https://github.com/benoitc/gunicorn/issues/1801?email_source=notifications&email_token=AAAEQJSFEFBBI6AMZJCM4C3Q4KLOJA5CNFSM4FDLD5PKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEIEIEXI#issuecomment -570983005
,
ou cancelar
<
https://github.com/notifications/unsubscribe-auth/AAAEQJXTCPOFIZJU5PUPOODQ4KLOJANCNFSM4FDLD5PA

.

-
Você está recebendo isto porque comentou.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/benoitc/gunicorn/issues/1801?email_source=notifications&email_token=AAH2WRPVPVO2EJ53BKQW5B3Q4OHLRA5CNFSM4FDLD5PKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEIGVJ7Q#issuecomment-571299070 ,
ou cancelar
https://github.com/notifications/unsubscribe-auth/AAH2WRM2LLIB4O6OHCU5UG3Q4OHLRANCNFSM4FDLD5PA
.

worker_class ',' sync ')

Consigo resolver esse problema combinando o número de trabalhadores e o número de threads.

Eu havia definido workers = (2 * cpu_count) + 1 e não defini tópicos.

Depois que mudei threads = workers , tudo começou a funcionar bem. Apenas no caso, se isso ajudar alguém.

É assim que parece agora

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()

De acordo com o documento gunicorn, ele altera a classe de trabalho de sync para gthread se mais de um encadeamento for mencionado.
PS: -
Se você tentar usar o tipo de trabalho de sincronização e definir a configuração de threads para mais de 1, o tipo de trabalho gthread será usado.

O meu caso:

Ambiente: Ubuntu18.04 + gunicorn + nginx + flask

pip instalar gunicorn [gevent] em meu ambiente virtual

Altere gunicorn -b localhost:8000 -w 4 web:app para gunicorn -b localhost:8000 -k gevent web:app

Funciona.

Obrigado a todos aqui que têm feito tanto para ajudar uns aos outros a resolver seus problemas. Continue postando para este problema se parecer apropriado.

No entanto, estou encerrando este problema porque não acho que haja algum bug no Gunicorn aqui e não acho que haja qualquer ação a ser tomada, embora terei o prazer de ajudar a revisar PRs que tentam adicionar documentação para isso de alguma forma ou melhorar mensagens de log.

Por favor, não entenda mal minha intenção. Se você suspeitar de um bug no Gunicorn e quiser continuar discutindo, faça-o. De preferência, abra um novo tíquete com um aplicativo de exemplo que reproduza seu problema. No entanto, neste ponto, existem muitos problemas, resoluções e conversas diferentes nesta edição para que seja muito legível.

Se você executar o Gunicorn sem um proxy reverso de buffer na frente dele, _será_ obterá o tempo limite com o padrão, sincronize o trabalhador por vários motivos. Os mais comuns são:

  • Clientes lentos
  • Conexões de pré-conexão / pré-busca que são deixadas abertas por navegadores e proxies
  • Respostas longas devido à chamada de APIs externas ou à realização de muito trabalho vinculado à CPU

Você pode alternar para os tipos de trabalho assíncrono ou encadeado ou pode colocar o Gunicorn atrás de um proxy reverso de buffer. Se você sabe que seus tempos limite são devido ao seu próprio código fazer chamadas lentas para APIs externas ou realizar um trabalho significativo que você espera, pode aumentar a opção --timeout .

Isso significa que você precisa de pelo menos dois trabalhadores, caso contrário, seu servidor entrará em conflito. A solicitação aguardará até que o servidor responda à segunda solicitação (que seria enfileirada). Você recebe uma solicitação simultânea por trabalhador.

Na segunda-feira, 6 de janeiro de 2020, 02:45 alpinechicken, @ . * > escreveu: Sim, uma rota chama outra - isso é ruim?

É este o caso ao chamar a função 'redirecionar' como o valor de retorno de uma rota?

É este o caso ao chamar a função 'redirecionar' como o valor de retorno de uma rota?

Não. Um redirecionamento de frasco responde com um redirecionamento de HTTP e o trabalhador fica então livre para aceitar uma nova solicitação. O cliente faz outra solicitação ao ver essa resposta e sempre que um trabalhador estiver pronto receberá essa solicitação.

Corrigi isso adicionando trabalhadores extras ao gnuicorn:

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

Não faço ideia do porquê.

Isso está relacionado ao comentário anterior de @anilpai, onde ele definiu workers=1 + (multiprocessing.cpu_count() * 2) ..?

Eu tive um problema semelhante a este. Acontece que eu tive um erro no meu ponto de entrada para o aplicativo. Pela depuração, parecia que eu estava essencialmente iniciando um aplicativo de flask do gunicorn, cujos workers posteriormente entram em um loop de conexão infinito que expira a cada 30 segundos.

Tenho certeza de que isso não afeta todos os usuários acima, mas pode afetar alguns.

No meu arquivo module/wsgi.py que estou executando com gunicorn module.wsgi eu tinha -

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

Considerando que eu deveria ter -

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

Essencialmente, você não deseja chamar application.run() ao usar gunicorn. O __name__ sob gunicorn não será "__main__" , mas será no Flask, então você ainda pode depurar localmente.

Não consegui encontrar uma referência a isso nos documentos do gunicorn, mas posso imaginar que seja um caso de erro comum, então talvez algum aviso seja necessário.

Isso ainda está ocorrendo. Adicionar --preload à chamada do Gunicorn resolveu o problema para mim.

Este bug ainda não foi corrigido? Estou observando exatamente esse comportamento.

Gunicorn começa assim no 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

O processo de trabalho atinge o tempo limite e 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 é um aplicativo Trival Flask.

Este problema foi encerrado como Não corrigir?

Eu também estava tendo o mesmo problema

Mas depois de Debugging, sou capaz de descobrir que enquanto o gunicorn inicia o Django App, uma das dependências estava demorando mais do que o tempo esperado (no meu caso, conexão de banco de dados externa), o que faz com que o trabalhador gunicron atinja o tempo limite

Quando resolvi o problema de conexão, o problema de tempo limite também foi resolvido ...

Este não seria o meu caso. Testei com o tipo de app “Hello, World”, sem dependências. Ainda estou intrigado com isso, mas parece que não é possível ter Gunicorn com linha longa. O processo de trabalho é reiniciado e, portanto, elimina o encadeamento de longa execução.

@leonbrag
Provavelmente NÃO é um bug do gunicorn. Veja minha recomendação acima no tópico. É um efeito colateral dos navegadores enviando conexões TCP "previstas" vazias e executando o gunicorn com apenas alguns workers de sincronização sem proteção contra conexões TCP vazias.

Existe uma arquitetura / design de referência que mostra uma maneira adequada de configurar o aplicativo de frasco Gunicorn com thread de trabalho longo (permanente)?

Se isso não for um bug, então parece um artefato ou uma limitação da arquitetura / design do Gunicorn.

Por que o trabalho de sincronização não funciona para sempre e aceita conexões de clientes. Esse trabalhador fecharia o soquete conforme necessário, mas continuaria executando sem sair (e, portanto, o thread de trabalho continuaria em execução).

@leonbrag
Você deve ser mais específico sobre o problema que está tentando resolver.

O problema discutido neste encadeamento acontece no ambiente de desenvolvimento e a solução mais fácil é adicionar mais trabalhos de sincronização ou usar trabalhos encadeados.

Se quiser evitar esse problema na configuração da produção, você pode usar gevent workers ou pode colocar um nginx na frente do gunicorn.
Alguns PaaS já colocam um nginx na frente do contêiner do docker, então você não precisa se preocupar com isso. Mais uma vez, a solução depende do contexto e dos detalhes.

Esta é uma boa leitura.
https://www.brianstorti.com/the-role-of-a-reverse-proxy-to-protect-your-application-against-slow-clients/

você pode verificar a página de design da documentação. Os trabalhadores assíncronos são um
maneira de executar tarefas longas.

No sábado, 8 de agosto de 2020 às 18:00 leonbrag [email protected] escreveu:

Existe uma arquitetura / design de referência que mostra uma maneira adequada de configurar
Aplicativo de frasco Gunicorn com thread de trabalho longo (permanente)?

Se isso não for um bug, então parece um artefato ou uma limitação do
Arquitetura / design Gunicorn.

Por que o trabalho de sincronização não funciona para sempre e aceita conexões de clientes. Tal
trabalhador fecharia o soquete conforme necessário, mas continuaria a executar sem sair
(e, portanto, o thread de trabalho continua em execução).

-
Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/benoitc/gunicorn/issues/1801#issuecomment-670944797 ,
ou cancelar
https://github.com/notifications/unsubscribe-auth/AAADRIWRQGIP3R5PMVJ5ENTR7VZA3ANCNFSM4FDLD5PA
.

>

Enviado do meu celular

web: gunicorn --workers = 3 app: app --timeout 200 --log-file -

Eu resolvi meu problema aumentando o --timeout

Consulte também # 1388 para problemas de tmpfs relacionados ao Docker.

Oh, muito obrigado Randall, esqueci de adicionar --worker-tmp-dir /dev/shm aos argumentos do gunicorn quando estava executando o gunicorn no Docker.

BTW, 64 Mb serão suficientes para o cache do gunicorn?

app gunicorn
Ou
gunicorn app: app --preload

Funcionou para mim ... Prefiro o tempo limite um.

Estranho, adicionei --worker-tmp-dir /dev/shm mas ainda recebo:

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

Para ter certeza de que /dev/shm é ramfs, fiz o benchmark:

image

Os parâmetros são os próximos:

    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"

PS: Estou usando o PyPy

O tempo limite

@ivictbor obrigado por lmk. 1000 é para referência. Mesmo assim, coloquei o aplicativo em funcionamento assim que carregado. Ele está funcionando perfeitamente bem.

Também recebi este problema de erro e depois de várias vezes, descobri que a causa provável do problema é:

  1. Configuração Nginx
  2. Gunicorn / Uwsgi

Se você implantar seu aplicativo na nuvem como o GAE, isso não apresentará nenhum erro de dica.
você pode tentar detectar o erro usando esta solução de caso: https://stackoverflow.com/questions/38012797/google-app-engine-502-bad-gateway-with-nodejs

Se gerado 502 gateway incorreto;
provavelmente terá 2 possibilidades:

  1. gunicorn não está correndo
  2. gunicorn atingiu o tempo limite

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

espero que possa consertar qualquer um obteve um erro em [CRITICAL] WORKER TIMEOUT

Adicionando outra possibilidade para quem encontrar este tópico ...

Isso também pode ser causado por restrições de recursos impostas pelo docker que são muito baixas para seu aplicativo da web. Por exemplo, tive as seguintes restrições:

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

e estes eram evidentemente muito baixos para gunicorn então eu sempre recebia o erro [CRITICAL] WORKER TIMEOUT até remover as restrições.

Para gunicorn, esses recursos são perfeitamente adequados. Mas você realmente precisa
plano para o número de trabalhadores e os recursos necessários para o seu
aplicativo. 128M e 0,25cpu parece muito baixo para um aplicativo da web
escrito em Python .... em geral, você precisa de pelo menos 1 núcleo / vcpu e
512 MB de RAM no mínimo.

Na sexta-feira, 26 de março de 2021 às 02:14, Colton Hicks @ . * > escreveu:

Adicionando outra possibilidade para quem encontrar este tópico ...

Isso também pode ser causado por restrições de recursos impostas pelo docker que
são muito baixos para o seu aplicativo da web. Por exemplo, eu tinha o seguinte
restrições:

Serviços:
aplicativo web:
imagem: blá-blá
implantar:
Recursos:
limites:
cpus: "0,25"
memória: 128M

e estes eram evidentemente muito baixos para gunicorn, então eu sempre recebia o [CRÍTICO]
Erro de TEMPO LIMITE DO TRABALHADOR até que eu removesse as restrições.

-
Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/benoitc/gunicorn/issues/1801#issuecomment-807855647 ,
ou cancelar
https://github.com/notifications/unsubscribe-auth/AAADRITPZB7BMA6QW7LFNVLTFPNV3ANCNFSM4FDLD5PA
.

>

Enviado do meu celular

--timeout = 1000 funcionou para mim. O problema era uma máquina do GCP com poucos recursos de CPU. Funcionou bem na minha máquina local com o tempo limite padrão.

Esta página foi útil?
0 / 5 - 0 avaliações