Gunicorn: Tempo limite do trabalhador instantâneo após solicitações de longa duração

Criado em 8 ago. 2013  ·  45Comentários  ·  Fonte: benoitc/gunicorn

Temos enfrentado um problema muito estranho envolvendo tempos limite de solicitação com Gunicorn em execução na frente de nosso aplicativo Django no Heroku.

Em essência, o problema ocorre quando uma solicitação de execução muito longa é feita ao aplicativo, fazendo com que ela seja interrompida pelo tempo limite da solicitação em nível de

[CRITICAL] WORKER TIMEOUT (pid:15)

Isso resulta no retorno imediato da página Erro interno do servidor ao cliente. Esse comportamento não é consistente - às vezes, a próxima solicitação será bem-sucedida, às vezes não. Minha suspeita é que o erro ocorrerá se a solicitação for tratada pelo mesmo trabalhador Gunicorn que estava lidando com a solicitação de longa duração.

Estamos executando o Gunicorn diretamente do Django da seguinte maneira:

python app/manage.py run_gunicorn -b 0.0.0.0:$PORT -w 2 -k gevent

Outros parâmetros de configuração relevantes, como worker_connections e max_requests, são definidos em seus padrões. No entanto, experimentamos alterar essas configurações, bem como o número de trabalhadores, mas o problema descrito acima ocorre em todos os casos que tentamos. Nossa versão atual do Gunicorn é 0.14.6, tendo sido revertida após o upgrade para 17.5, caso essa seja a origem do problema. Infelizmente, o mesmo comportamento ocorre em ambas as versões.

Estamos tendo grande dificuldade em compreender a causa raiz deste problema. Da documentação do Heroku com link acima:

Embora o roteador tenha retornado uma resposta ao cliente, seu aplicativo não saberá que a solicitação que está processando atingiu o tempo limite e seu aplicativo continuará a trabalhar na solicitação.

Presumo que isso signifique que, apesar do fato de a solicitação original de longa duração ter expirado da perspectiva do cliente, um trabalhador Gunicorn ainda está processando a solicitação. O que me deixa perplexo é como isso faria com que uma nova solicitação subsequente eliminasse o tempo limite do trabalhador imediatamente, visto que os trabalhadores estão usando gevent e, portanto, threads assíncronos para lidar com as solicitações. Eu teria pensado que a primeira solicitação de longa duração seria

  1. sem bloqueio devido ao fato de que existem vários threads de gevent de trabalho, e
  2. morto por Gunicorn antes que qualquer solicitação subsequente ocorresse, já que o tempo limite de solicitação padrão para Gunicorn é de 30 segundos - idêntico ao tempo limite de solicitação do próprio Heroku.

Pode ser importante mencionar que as solicitações de longa duração estão se conectando ao nosso banco de dados PostgreSQL e realizando várias consultas complexas. Os travamentos parecem ocorrer apenas depois que a conexão de longa duração atinge o tempo limite, graças ao Heroku durante a interface com o DB. Testamos isso em nosso servidor de teste criando duas visualizações separadas, uma das quais executa longas consultas no banco de dados até que o tempo limite do Heroku seja atingido e a outra simplesmente espera além da marca de 30 segundos para produzir o tempo limite do Heroku. A visão anterior era capaz de causar tempos limite do trabalhador Gunicorn na próxima solicitação, enquanto a visão 'adormecida' não era.

Seria fantástico se alguém tivesse alguma ideia do comportamento subjacente que está causando esse problema - qualquer informação adicional que eu possa fornecer para ajudar a diagnosticar o problema, por favor me avise. Espero que esta seja a maneira correta de lidar com esse problema e que não tenha sido levantado / abordado antes.

( FeaturWorker - Bugs -

Todos 45 comentários

@Jwpe Excelente relatório de bug.

A primeira coisa que eu verificaria é se você está usando um driver PostgreSQL ecológico. Costumava haver uma versão específica que você precisava usar com um patch monkey para fazer isso funcionar corretamente. Não sei o estado atual das coisas agora. Mas o tempo limite que você colou é um tempo limite do trabalhador e em um dos trabalhadores assíncronos que basicamente se resume a "um greenlet não cedeu por mais de $ tempo limite segundos". Visto que você está descrevendo solicitações de longa duração do PostgreSQL, é o primeiro lugar que eu investigaria.

@davisp Obrigado pela resposta rápida sobre isso!

Seguindo sua orientação, dei uma olhada no adaptador psycopg2 - que usamos para conectar nosso aplicativo Django ao Postgres - e descobri esta seção da documentação que afirma:

Aviso: as conexões Psycopg não são seguras para thread verde e não podem ser usadas simultaneamente por diferentes threads verdes. Tentar executar mais de um comando por vez usando um cursor por thread resultará em um erro (ou um deadlock nas versões anteriores a 2.4.2).
Portanto, os programadores são aconselhados a evitar o compartilhamento de conexões entre co-rotinas ou a usar um bloqueio amigável para a biblioteca para sincronizar conexões compartilhadas, por exemplo, para agrupamento.

Em outras palavras - psycopg2 não gosta de fios verdes. Com base no comportamento que encontramos, acho que essa é a origem do erro. A maneira sugerida de lidar com esse problema, de acordo com os documentos do psycopg, é usar uma biblioteca que habilite o suporte do psycopg para corrotinas. A biblioteca recomendada é psycogreen .

Vou tentar recriar o problema em nosso servidor de teste usando a biblioteca psycogreen e ver se isso resolve o problema. Espero poder relatar alguns resultados relativamente em breve.

@Jwpe Esse parece o gancho que eu estava lembrando.

@benoitc Talvez devêssemos divulgar isso nos documentos do Gunicorn em algum lugar? Não tenho certeza de onde seria o melhor lugar.

@davisp talvez em uma seção de FAQ?

hmppff esquece que já existia (http://docs.gunicorn.org/en/latest/faq.html) Então talvez pudéssemos ter um link para uma seção de "solução de problemas" a partir daí. não tenho certeza, mas também poderíamos mover nessa seção qualquer informação sobre o virtualenv e outros truques.

Talvez uma página de advertências ou "Notas sobre tópicos verdes". Não é muito urgente.

Eu estava vendo praticamente o mesmo comportamento exato no Heroku executando gunicorn com gevent workers mais alguns outros, então mudei para workers síncronos, conforme recomendado neste tópico, e ainda estava vendo basicamente o mesmo problema sério. Eu obtinha um corte de Heroku H12 de 30 segundos e, em seguida, repetia os erros de H12 e [CRITICAL] Worker Timeout até zerar todo o dinamômetro (às vezes uma hora ou mais depois ou até que o máximo de solicitações fosse atingido). Portanto, ajustei o tempo limite do gunicorn para 28 segundos, de modo que o tempo limite se esgotasse antes que o Heroku o interrompesse. O mesmo (ou muito semelhante) problema acontecendo uma ou duas vezes por dia e persistindo até que o processo mestre seja reiniciado, só que desta vez ele começa com um H13 (conexão fechada) já que o gunicorn o está cortando. Não há picos significativos de tráfego durante esses períodos.

Aqui está minha entrada atual do procfile:

web: newrelic-admin run-program gunicorn publisher.wsgi -b 0.0.0.0:$PORT -w 4 --max-requests 1000 --timeout 28 --preload

Detalhe da série de eventos:

Primeiro, recebo algumas solicitações que parecem demorar muito (5+ segundos), depois uma solicitação falha com um tempo limite H12 (o tempo limite do trabalhador o corta) e mais algumas solicitações serão concluídas, mas com tempos excepcionalmente longos (20 segundos). A partir de então, é puro H11 30 segundos de corte de heroku até eu reiniciar o dinamômetro.

Usamos gunicorn (v 18.0) como nosso servidor web (que executa python / django).

Executamos o newrelic, que mostra o tempo de inatividade e os tempos de enfileiramento de solicitações absurdamente elevados, mas não oferece nenhuma outra visão. Não houve picos na taxa de transferência ou outras condições anormais que posso ver no NR. Usamos papertrail para processamento de log e para enviar e-mails de erro.

Oct 15 15:08:53 nutrislice-stockton heroku/router: at=info method=GET path=/marketingtools/api/slides/?format=json-p&callback=_jqjsp&_1381871332239= host=oldham.nutrislice.com fwd="74.138.24.95" dyno=web.2 connect=15ms service=216ms status=200 bytes=21 Oct 15 15:08:54 nutrislice-stockton heroku/router: at=info method=GET path=/menu/api/menutypes/?format=json-p&callback=_jqjsp&_1381871332232= host=oldham.nutrislice.com fwd="74.138.24.95" dyno=web.2 connect=2ms service=90ms status=200 bytes=231 Oct 15 15:08:56 nutrislice-stockton heroku/router: at=info method=GET path=/menu/api/schools/?format=json-p&callback=_jqjsp&_1381871323514= host=oldham.nutrislice.com fwd="74.138.24.95" dyno=web.2 connect=3ms service=94ms status=200 bytes=5986 Oct 15 15:09:03 nutrislice-stockton heroku/router: at=info method=HEAD path=/heartbeat/ host=stockton.nutrislice.com fwd="54.247.188.179" dyno=web.2 connect=3ms service=23ms status=200 bytes=0 Oct 15 15:09:13 nutrislice-stockton heroku/router: at=info method=GET path=/menu/api/settings/?format=json-p&callback=_jqjsp&_1381871237946= host=pcsb.nutrislice.com fwd="66.87.110.127" dyno=web.2 connect=5ms service=166ms status=200 bytes=468 Oct 15 15:09:20 nutrislice-stockton heroku/router: at=info method=GET path=/menu/api/settings/?format=json-p&callback=_jqjsp&_1381871323611= host=oldham.nutrislice.com fwd="74.138.24.95" dyno=web.2 connect=6ms service=183ms status=200 bytes=453 Oct 15 15:09:40 nutrislice-stockton heroku/router: at=info method=GET path=/ host=nps.nutrislice.com fwd="74.190.240.28" dyno=web.2 connect=1ms service=260ms status=200 bytes=35951 Oct 15 15:09:55 nutrislice-stockton heroku/router: at=info method=GET path=/menuwidgets/api/list/school-menu-profile/87/menu-type/43/?format=json-p&callback=jQuery18008709754704032093_1381871379465&_=1381871393589 host=nps.nutrislice.com fwd="74.190.240.28" dyno=web.2 connect=15ms service=129ms status=200 bytes=400 Oct 15 15:09:55 nutrislice-stockton heroku/router: at=info method=GET path=/menuwidgets/api/list/school-menu-profile/306/menu-type/187/?format=json-p&callback=jQuery180013075259909965098_1381873891397&_=1381873896600 host=sdhc.nutrislice.com fwd="72.186.96.121" dyno=web.2 connect=2ms service=33ms status=200 bytes=486 Oct 15 15:10:00 nutrislice-stockton heroku/router: at=info method=GET path=/menuwidgets/186/?smp=257 host=coppellisd.nutrislice.com fwd="76.199.114.157" dyno=web.2 connect=7ms service=103ms status=200 bytes=323 Oct 15 15:10:00 nutrislice-stockton app/web.2: INFO http://stockton.nutrislice.com/heartbeat/ Pinged from IP: 10.190.159.205 -- AGENT: NewRelicPinger/1.0 (269661) Oct 15 15:10:00 nutrislice-stockton heroku/router: at=info method=HEAD path=/heartbeat/ host=stockton.nutrislice.com fwd="50.112.95.211" dyno=web.2 connect=1ms service=10ms status=200 bytes=0 Oct 15 15:10:09 nutrislice-stockton heroku/router: at=info method=GET path=/menuwidgets/239/?smp=341 host=edenpr.nutrislice.com fwd="75.73.177.139" dyno=web.2 connect=8ms service=334ms status=200 bytes=277 Oct 15 15:10:16 nutrislice-stockton heroku/router: at=info method=GET path=/menuwidgets/395/?smp=306 host=sdhc.nutrislice.com fwd="72.186.96.121" dyno=web.2 connect=1ms service=96ms status=200 bytes=245 Oct 15 15:10:20 nutrislice-stockton heroku/router: at=info method=GET path=/menuwidgets/391/?smp=305 host=sdhc.nutrislice.com fwd="173.170.34.126" dyno=web.2 connect=32ms service=5207ms status=200 bytes=290 Oct 15 15:10:22 nutrislice-stockton heroku/router: at=info method=GET path=/menuwidgets/350/?smp=305 host=sdhc.nutrislice.com fwd="173.170.34.126" dyno=web.2 connect=60ms service=7676ms status=200 bytes=1147 Oct 15 15:10:31 nutrislice-stockton heroku/router: at=info method=GET path=/menuwidgets/258/?smp=341 host=edenpr.nutrislice.com fwd="75.73.177.139" dyno=web.2 connect=42ms service=517ms status=200 bytes=26974 Oct 15 15:10:43 nutrislice-stockton heroku/router: at=info method=GET path=/menu/api/schools/?format=json-p&callback=_jqjsp&_1381871432885= host=ocps.nutrislice.com fwd="71.47.21.97" dyno=web.2 connect=1490ms service=9883ms status=200 bytes=1565 Oct 15 15:10:52 nutrislice-stockton heroku/router: at=error code=H13 desc="Connection closed without response" method=GET path=/ host=jordandistrict.nutrislice.com fwd="71.199.48.37" dyno=web.2 connect=1959ms service=29230ms status=503 bytes=0 Oct 15 15:10:52 nutrislice-stockton app/web.2: 2013-10-15 21:10:50 [2] [CRITICAL] WORKER TIMEOUT (pid:12) Oct 15 15:10:52 nutrislice-stockton app/web.2: 2013-10-15 21:10:50 [2] [CRITICAL] WORKER TIMEOUT (pid:12) Oct 15 15:10:52 nutrislice-stockton app/web.2: 2013-10-15 21:10:50 [26] [INFO] Booting worker with pid: 26 Oct 15 15:10:52 nutrislice-stockton app/web.2: 2013-10-15 21:10:50,930 (26/MainThread) newrelic.core.agent INFO - New Relic Python Agent (2.0.0.1) Oct 15 15:10:54 nutrislice-stockton heroku/router: at=info method=GET path=/surveys/api/activesurveycount/?format=json-p&callback=_jqjsp&_1381871433429= host=henrico.nutrislice.com fwd="96.248.5.53" dyno=web.2 connect=1181ms service=20074ms status=200 bytes=32 Oct 15 15:10:55 nutrislice-stockton heroku/router: at=info method=GET path=/menu/api/schooltypes/?format=json-p&callback=_jqjsp&_1381871433374= host=henrico.nutrislice.com fwd="96.248.5.53" dyno=web.2 connect=1136ms service=20393ms status=200 bytes=142 Oct 15 15:11:01 nutrislice-stockton app/web.2: using heroku production settings Oct 15 15:11:01 nutrislice-stockton app/web.2: WARNING /app/.heroku/python/lib/python2.7/site-packages/django/utils/hashcompat.py:9: DeprecationWarning: django.utils.hashcompat is deprecated; use hashlib instead Oct 15 15:11:01 nutrislice-stockton app/web.2: DeprecationWarning) Oct 15 15:11:01 nutrislice-stockton heroku/router: at=info method=GET path=/menu/api/settings/?format=json-p&callback=_jqjsp&_1381871432922= host=ocps.nutrislice.com fwd="71.47.21.97" dyno=web.2 connect=1435ms service=23198ms status=200 bytes=486 Oct 15 15:11:03 nutrislice-stockton app/web.2: WARNING /app/.heroku/python/lib/python2.7/site-packages/django/conf/urls/defaults.py:3: DeprecationWarning: django.conf.urls.defaults is deprecated; use django.conf.urls instead Oct 15 15:11:03 nutrislice-stockton app/web.2: DeprecationWarning) Oct 15 15:11:05 nutrislice-stockton heroku/router: at=info method=GET path=/menu/api/schooltypes/?format=json-p&callback=_jqjsp&_1381871443300= host=martinschools.nutrislice.com fwd="99.114.229.202" dyno=web.2 connect=1089ms service=20040ms status=200 bytes=268 Oct 15 15:11:10 nutrislice-stockton heroku/router: at=error code=H12 desc="Request timeout" method=GET path=/menu/api/weeks/school-menu-profile/135/menu-type/63/2013/10/14/?format=json-p&callback=_jqjsp&_1381871439548= host=henrico.nutrislice.com fwd="96.248.5.53" dyno=web.2 connect=1018ms service=30001ms status=503 bytes=0 Oct 15 15:11:15 nutrislice-stockton heroku/router: at=error code=H12 desc="Request timeout" method=GET path=/menu/api/sales/?format=json-p&callback=_jqjsp&_1381871443267= host=martinschools.nutrislice.com fwd="99.114.229.202" dyno=web.2 connect=1096ms service=30001ms status=503 bytes=0 Oct 15 15:11:15 nutrislice-stockton heroku/router: at=error code=H12 desc="Request timeout" method=GET path=/menu/api/schools/?format=json-p&callback=_jqjsp&_1381871443296= host=martinschools.nutrislice.com fwd="99.114.229.202" dyno=web.2 connect=1108ms service=30000ms status=503 bytes=0 Oct 15 15:11:23 nutrislice-stockton heroku/router: at=info method=GET path=/menu/api/weeks/school-menu-profile/48/menu-type/21/2013/10/14/?format=json-p&callback=_jqjsp&_1381871449451= host=martinschools.nutrislice.com fwd="99.114.229.202" dyno=web.2 connect=1114ms service=31756ms status=200 bytes=48771 Oct 15 15:11:26 nutrislice-stockton heroku/router: at=error code=H12 desc="Request timeout" method=GET path=/menu/api/sales/?format=json-p&callback=_jqjsp&_1381871455129= host=pcsb.nutrislice.com fwd="66.87.110.127" dyno=web.2 connect=990ms service=30001ms status=503 bytes=0 Oct 15 15:11:26 nutrislice-stockton heroku/router: at=error code=H12 desc="Request timeout" method=GET path=/menu/api/schools/?format=json-p&callback=_jqjsp&_1381871455291= host=pcsb.nutrislice.com fwd="66.87.110.127" dyno=web.2 connect=1028ms service=30008ms status=503 bytes=0 Oct 15 15:11:31 nutrislice-stockton heroku/router: at=error code=H12 desc="Request timeout" method=GET path=/menuwidgets/179/?smp=6 host=cusdnutrition.nutrislice.com fwd="68.99.246.16" dyno=web.2 connect=2492ms service=30000ms status=503 bytes=0 Oct 15 15:11:32 nutrislice-stockton heroku/router: at=error code=H12 desc="Request timeout" method=GET path=/menuwidgets/192/?smp=6 host=cusdnutrition.nutrislice.com fwd="68.99.246.16" dyno=web.2 connect=2713ms service=30003ms status=503 bytes=0 Oct 15 15:11:39 nutrislice-stockton heroku/router: at=error code=H12 desc="Request timeout" method=GET path=/menu/ host=hebisd.nutrislice.com fwd="38.107.226.1" dyno=web.2 connect=2115ms service=30001ms status=503 bytes=0 Oct 15 15:11:45 nutrislice-stockton heroku/router: at=error code=H12 desc="Request timeout" method=GET path=/menu/api/weeks/school-menu-profile/44/menu-type/19/2013/10/14/?format=json-p&callback=_jqjsp&_1381871472583= host=pcsb.nutrislice.com fwd="66.87.110.127" dyno=web.2 connect=2168ms service=30000ms status=503 bytes=0 Oct 15 15:11:48 nutrislice-stockton heroku/router: at=error code=H12 desc="Request timeout" method=GET path=/marketingtools/api/active-announcements/?format=json-p&callback=_jqjsp&_1381871476287= host=sdhc.nutrislice.com fwd="65.34.72.116" dyno=web.2 connect=1927ms service=30000ms status=503 bytes=0 Oct 15 15:11:48 nutrislice-stockton heroku/router: at=error code=H12 desc="Request timeout" method=GET path=/surveys/api/activesurveycount/?format=json-p&callback=_jqjsp&_1381871476543= host=sdhc.nutrislice.com fwd="65.34.72.116" dyno=web.2 connect=2117ms service=30000ms status=503 bytes=0 Oct 15 15:11:48 nutrislice-stockton heroku/router: at=error code=H12 desc="Request timeout" method=GET path=/menu/api/schooltypes/?format=json-p&callback=_jqjsp&_1381871476481= host=sdhc.nutrislice.com fwd="65.34.72.116" dyno=web.2 connect=2111ms service=30009ms status=503 bytes=0 Oct 15 15:11:50 nutrislice-stockton app/web.2: 2013-10-15 15:11:32,597 (26/NR-Activate-Session/nutrislice-stockton) newrelic.core.data_collector INFO - Successfully registered New Relic Python agent where app_name='nutrislice-stockton', pid=26, redirect_host='collector-2.newrelic.com' and agent_run_id=474482914, in 40.26 seconds. Oct 15 15:11:50 nutrislice-stockton app/web.2: INFO Successfully registered New Relic Python agent where app_name='nutrislice-stockton', pid=26, redirect_host='collector-2.newrelic.com' and agent_run_id=474482914, in 40.26 seconds. Oct 15 15:11:52 nutrislice-stockton heroku/router: at=error code=H12 desc="Request timeout" method=GET path=/marketingtools/api/active-announcements/?format=json-p&callback=_jqjsp&_1381871480294= host=sdhc.nutrislice.com fwd="65.34.72.116" dyno=web.2 connect=1689ms service=30006ms status=503 bytes=0 Oct 15 15:11:55 nutrislice-stockton heroku/router: at=error code=H12 desc="Request timeout" method=GET path=/menu/api/settings/?format=json-p&callback=_jqjsp&_1381871482566= host=henrico.nutrislice.com fwd="72.84.233.45" dyno=web.2 connect=2067ms service=30004ms status=503 bytes=0 Oct 15 15:11:57 nutrislice-stockton app/web.2: 2013-10-15 21:11:41 [2] [CRITICAL] WORKER TIMEOUT (pid:26) Oct 15 15:11:57 nutrislice-stockton app/web.2: 2013-10-15 21:11:41 [2] [CRITICAL] WORKER TIMEOUT (pid:26) Oct 15 15:11:57 nutrislice-stockton app/web.2: 2013-10-15 21:11:41 [29] [INFO] Booting worker with pid: 29 Oct 15 15:11:57 nutrislice-stockton app/web.2: 2013-10-15 21:11:41,067 (29/MainThread) newrelic.core.agent INFO - New Relic Python Agent (2.0.0.1) Oct 15 15:11:57 nutrislice-stockton app/web.2: using heroku production settings Oct 15 15:11:57 nutrislice-stockton app/web.2: WARNING /app/.heroku/python/lib/python2.7/site-packages/django/utils/hashcompat.py:9: DeprecationWarning: django.utils.hashcompat is deprecated; use hashlib instead Oct 15 15:11:57 nutrislice-stockton app/web.2: DeprecationWarning) Oct 15 15:11:57 nutrislice-stockton app/web.2: 2013-10-15 21:11:44 [2] [CRITICAL] WORKER TIMEOUT (pid:23) Oct 15 15:11:57 nutrislice-stockton app/web.2: 2013-10-15 21:11:44 [2] [CRITICAL] WORKER TIMEOUT (pid:23) Oct 15 15:11:57 nutrislice-stockton app/web.2: 2013-10-15 21:11:44 [32] [INFO] Booting worker with pid: 32 Oct 15 15:11:57 nutrislice-stockton app/web.2: 2013-10-15 21:11:44,154 (32/MainThread) newrelic.core.agent INFO - New Relic Python Agent (2.0.0.1) Oct 15 15:11:57 nutrislice-stockton app/web.2: using heroku production settings Oct 15 15:11:57 nutrislice-stockton app/web.2: WARNING /app/.heroku/python/lib/python2.7/site-packages/django/utils/hashcompat.py:9: DeprecationWarning: django.utils.hashcompat is deprecated; use hashlib instead Oct 15 15:11:57 nutrislice-stockton app/web.2: DeprecationWarning) Oct 15 15:11:57 nutrislice-stockton app/web.2: 2013-10-15 21:11:48 [2] [CRITICAL] WORKER TIMEOUT (pid:14) Oct 15 15:11:57 nutrislice-stockton app/web.2: 2013-10-15 21:11:48 [2] [CRITICAL] WORKER TIMEOUT (pid:14) Oct 15 15:11:57 nutrislice-stockton app/web.2: 2013-10-15 21:11:48 [35] [INFO] Booting worker with pid: 35 Oct 15 15:11:57 nutrislice-stockton app/web.2: 2013-10-15 21:11:48,273 (35/MainThread) newrelic.core.agent INFO - New Relic Python Agent (2.0.0.1) Oct 15 15:11:57 nutrislice-stockton app/web.2: using heroku production settings Oct 15 15:11:57 nutrislice-stockton app/web.2: WARNING /app/.heroku/python/lib/python2.7/site-packages/django/utils/hashcompat.py:9: DeprecationWarning: django.utils.hashcompat is deprecated; use hashlib instead Oct 15 15:11:57 nutrislice-stockton app/web.2: DeprecationWarning) Oct 15 15:11:57 nutrislice-stockton heroku/router: at=info method=GET path=/menuwidgets/353/?smp=306 host=sdhc.nutrislice.com fwd="72.186.96.121" dyno=web.2 connect=21ms service=76ms status=200 bytes=255 Oct 15 15:12:00 nutrislice-stockton app/web.2: 2013-10-15 21:11:54 [2] [CRITICAL] WORKER TIMEOUT (pid:13) Oct 15 15:12:00 nutrislice-stockton app/web.2: 2013-10-15 21:11:54 [2] [CRITICAL] WORKER TIMEOUT (pid:13) Oct 15 15:12:00 nutrislice-stockton app/web.2: 2013-10-15 21:11:54 [38] [INFO] Booting worker with pid: 38 Oct 15 15:12:00 nutrislice-stockton app/web.2: 2013-10-15 21:11:54,388 (38/MainThread) newrelic.core.agent INFO - New Relic Python Agent (2.0.0.1) Oct 15 15:12:00 nutrislice-stockton app/web.2: using heroku production settings Oct 15 15:12:01 nutrislice-stockton app/web.2: WARNING /app/.heroku/python/lib/python2.7/site-packages/django/utils/hashcompat.py:9: DeprecationWarning: django.utils.hashcompat is deprecated; use hashlib instead Oct 15 15:12:01 nutrislice-stockton app/web.2: DeprecationWarning) Oct 15 15:12:02 nutrislice-stockton app/web.2: WARNING /app/.heroku/python/lib/python2.7/site-packages/django/conf/urls/defaults.py:3: DeprecationWarning: django.conf.urls.defaults is deprecated; use django.conf.urls instead Oct 15 15:12:02 nutrislice-stockton app/web.2: DeprecationWarning) Oct 15 15:12:03 nutrislice-stockton heroku/router: at=error code=H12 desc="Request timeout" method=GET path=/menuwidgets/353/?smp=306 host=sdhc.nutrislice.com fwd="108.9.154.78" dyno=web.2 connect=3650ms service=30006ms status=503 bytes=0 Oct 15 15:12:03 nutrislice-stockton heroku/router: at=error code=H12 desc="Request timeout" method=GET path=/menuwidgets/395/?smp=306 host=sdhc.nutrislice.com fwd="108.9.154.78" dyno=web.2 connect=3581ms service=30006ms status=503 bytes=0 Oct 15 15:12:06 nutrislice-stockton heroku/router: at=error code=H12 desc="Request timeout" method=GET path=/menu/api/settings/?format=json-p&callback=_jqjsp&_1381871492466= host=canyonsdistrict.nutrislice.com fwd="174.52.155.49" dyno=web.2 connect=3582ms service=30001ms status=503 bytes=0 Oct 15 15:12:09 nutrislice-stockton heroku/router: at=error code=H12 desc="Request timeout" method=GET path=/mobile/api_version/?deviceType=iphone host=pasco.nutrislice.com fwd="173.65.148.9" dyno=web.2 connect=3837ms service=30004ms status=503 bytes=0 Oct 15 15:12:11 nutrislice-stockton heroku/router: at=error code=H12 desc="Request timeout" method=GET path=/mobile/api_version/?deviceType=iphone host=canyonsdistrict.nutrislice.com fwd="174.52.155.49" dyno=web.2 connect=3987ms service=30001ms status=503 bytes=0 Oct 15 15:12:11 nutrislice-stockton heroku/router: at=error code=H12 desc="Request timeout" method=GET path=/menu/api/schools/?format=json-p&callback=_jqjsp&_1381871497105= host=canyonsdistrict.nutrislice.com fwd="174.52.155.49" dyno=web.2 connect=3962ms service=30001ms status=503 bytes=0 Oct 15 15:12:11 nutrislice-stockton heroku/router: at=error code=H12 desc="Request timeout" method=GET path=/menu/api/menutypes/?format=json-p&callback=_jqjsp&_1381871497128= host=canyonsdistrict.nutrislice.com fwd="174.52.155.49" dyno=web.2 connect=4020ms service=30007ms status=503 bytes=0
E essa "espiral mortal" de tempos limite H12 e TIMEOUT [CRÍTICO] DO TRABALHADOR continua indefinidamente até que o processo mestre seja reiniciado.

Alguma ideia se este é o mesmo problema ou diferente? Alguma sugestão para corrigir? Eu pensaria que, uma vez que o gunicorn está matando os processos de trabalho após o tempo limite e os reiniciando, eles seriam capazes de começar a processar as coisas normalmente, mas parece que as solicitações nem chegam até eles depois disso. Talvez seja um problema Heroku.

: +1: Também vendo este problema.

Também estou vendo esse problema no Heroku

@sprynmr @richardkeen você pode compartilhar a forma como você está lançando gunicorn e qualquer log que você pode? Isso ajudaria muito a resolver o problema.

@nebstrebor e se você não limitar o número de solicitações?

Estávamos lançando assim:
web: newrelic-admin run-program python manage.py run_gunicorn -b "0.0.0.0:$PORT" --log-level=DEBUG -w 3 -k gevent --max-requests 250

Mesmo com o DEBUG em nível de log, não obtivemos muitos logs sobre o que estava acontecendo. Não usar gevent resolveu o problema para nós por enquanto, mas não é o ideal.

@sprynmr e se você remover o número máximo de solicitações? Também qual versão do gevent?

Estávamos em 1.0rc2 . Não tenho certeza sobre o número máximo de solicitações. Não quero ativá-lo novamente em nosso ambiente de produção agora.

Lendo a página do Heroku sobre o tempo limite da well under 30 seconds, such as 10 or 15 . Você tentou a sugestão usando o parâmetro de tempo limite no gunicorn?

De qualquer forma, o problema que aparece com gevent é provavelmente devido à forma como as conexões são tratadas. A versão atual do trabalhador está gerando um greenlet / conexões aceitas sem qualquer supervisão real deste greenlet. O que provavelmente acontecerá é que um dos soquetes aceitos ficará esperando por um longo tempo, e nenhum outro evento será tratado, fazendo com que o gunicorn worker reinicie. Mas eu preciso verificar ..

Interessante. Não, nós não tentamos isso.

: +1: Também estou vendo isso em meu aplicativo. @Jwpe / @sprynmr alguma vez chegou a uma resolução para este problema? Parece que já se passaram mais de 2 meses desde a ocorrência de qualquer atividade sobre este problema. Estou ansioso para saber se você encontrou algo que resolva o problema.

Obrigado!

@dencold você tentou https://github.com/benoitc/gunicorn/issues/588#issuecomment -29267541

Não tenho nenhuma conta no heroku, então não tenho certeza do que ele faz. Você também tem os mesmos logs?

Olá @benoitc , muito obrigado pela resposta rápida. Os logs são exatamente os mesmos que @Jwpe e @nebstrebor relataram. Terei prazer em retirar as partes relevantes e adicioná-las aqui se isso ajudar a isolar o problema, avise-me.

Vou seguir seu conselho de seu comentário anterior e configurar o tempo limite do gunicorn para ser menor do que o tempo limite do roteador heroku e ver se isso ajuda. Obrigado pela sugestão.

Seria útil descobrir a causa real dessa falha em cascata. É realmente estranho ver um trabalhador falhar e, em seguida, todo o servidor gunicorn parar de responder completamente. Deixe-me saber se houver algo que eu possa fazer para ajudar no diagnóstico. Não consigo reproduzir esse tempo limite localmente. Parece ocorrer apenas na infraestrutura do heroku.

Desculpe @dencold, eu nunca encontrei uma solução. Parecia um bug misterioso muito profundo e não tive tempo de lutar contra ele. Ficará curioso para ver se o bit de tempo limite o ajuda. Relate de volta.

@dencold você também está usando uma nova relíquia?

@benoitc sim, também estamos usando uma nova relíquia.

Da mesma forma,

@Jwpe você pelo menos tentou a solução proposta? Além disso, o resultado é estranho e eu nunca reproduzo isso com o gunicorn sozinho.

Eu tinha o tempo de corte reduzido para 15 segundos e ainda estava vendo o problema

No domingo, 26 de janeiro de 2014, Benoit Chesneau [email protected]
escreveu:

@Jwpe https://github.com/Jwpe você pelo menos experimentou a proposta
solução? Além disso, o resultado é estranho e eu nunca reproduzo isso com gunicorn
por si próprio.

-
Responda a este e-mail diretamente ou visualize-o em Gi tHubhttps: //github.com/benoitc/gunicorn/issues/588#issuecomment -33316333
.

Ben Roberts
CTO
Nutrislice, Inc.
866-524-3444 ramal 702
[email protected]

@Jwpe / @nebstrebor muito obrigado por responder a esta questão.

@benoitc , implementamos a solução de tempo limite proposta em nossa instância heroku. Vou manter uma vigilância cuidadosa sobre isso nos próximos dias. Postarei de volta se eu vir o mesmo problema aparecer depois que o novo tempo limite for estabelecido.

Obrigado novamente a todos pela ajuda. É bom saber que não sou o único com esse problema. Espero que possamos chegar ao fundo da causa.

@benoitc só queria informar que já se passaram cerca de duas semanas com o tempo limite inferior em vigor. Vimos alguns tempos limite de trabalho, mas nenhum que faça com que todo o processo do gunicórnio pare de responder. Isso parece resolver o problema, mas ainda não tenho certeza por que os tempos limite de 30s estavam causando o erro em cascata em primeiro lugar.

Só queria mantê-lo informado. Obrigado novamente por toda a ajuda aqui!

Tendo o mesmo erro [CRITICAL] WORKER TIMEOUT executando Django com gunicorn em um Raspberry PI.

Sem novidades.

Estou recebendo o mesmo [CRÍTICO] TEMPO LIMITE DO TRABALHADOR.
O problema é que após o tempo limite real do trabalhador (solicitação longa), o gunicórnio mata o trabalhador e tenta gerar um novo, mas o novo trabalhador não pode iniciar dentro do limite de TIMEOUT e não chega ao local onde informa ao processo pai que ele é ao vivo, então o gunicorn o mata repetidamente :(. No nosso caso, o problema estava relacionado a Gevent e Sentry (https://github.com/getsentry/raven-python/issues/305). Sentry apenas trava na inicialização .
A propósito, será útil ter um tempo limite separado para o horário de início do trabalhador e alguns logs adicionais dentro de um trabalhador que não pode ser iniciado dentro de um tempo de "tempo limite".

O tempo limite não é um tempo limite de solicitação, exceto no trabalhador de sincronização. Os outros trabalhadores ainda pulsam para o árbitro, mesmo quando lidam com solicitações longas. O tempo limite é o tempo limite de inicialização nesse caso.

Em certo sentido, não há "tempo limite de solicitação" no gunicorn.

sim, o tempo limite do trabalhador é diferente do tempo limite da solicitação em assíncrono. Mas as solicitações de longa execução sem nenhuma chamada de função em que a "troca de contexto" assíncrona pode acontecer (como "soquete - leitura / gravação") são as causas dos tempos limite do trabalhador. E, além disso, pode haver tempo limite na inicialização do trabalhador (onde não há solicitação alguma). Mas nos logs do Gunicorn não há como distinguir esses 2 casos diferentes, há apenas uma mensagem "TEMPO LIMITE DO TRABALHADOR".

Devemos adicionar uma configuração de tempo limite de solicitação? Isso permitiria que aplicativos com inicializações longas diminuíssem o tempo limite do trabalhador.

Acho que não, por causa de
1) Medir o tempo de execução da solicitação é difícil, não podemos usar a diferença de tempo no início e no final da solicitação.
2) Como eu sei, capturar tempos limite de "unidades de execução" (a quantidade de código que é executado entre a troca de contexto) não é possível no gevent.

Alguma sugestão então?

Se esse problema for devido apenas a tempos limite legítimos e potencialmente em cascata
tempos limite devido à carga do servidor que não existe na primeira execução, existe
algo para fazer aqui? Ou esse problema pode ser fechado e é melhor tratado
operacionalmente em um nível diferente de infraestrutura?
Em 30 de julho de 2014, 13h14, "Mkrtich" [email protected] escreveu:

Acho que não, por causa de
1) Medir o tempo de execução da solicitação é difícil, não podemos usar a diferença de tempo no
implorando e no final do pedido.
2) Como eu sei, capturar tempos limite de "unidades de execução" (a quantidade de código
que funciona entre a troca de contexto) não é possível no gevent.

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/benoitc/gunicorn/issues/588#issuecomment -50673040.

A sugestão é ter 2 parâmetros de tempo limite e 2 logs diferentes.
1) Um é o parâmetro de tempo limite atual que funcionará apenas durante o tratamento da solicitação.
2) O segundo será o tempo limite de inicialização do trabalhador.

Também vendo este problema

Acabamos mudando para uWSGI para Heroku e tivemos mais sucesso ... não é uma correção para Gunicorn, eu percebo, mas achei que a sugestão pode ser útil para alguém que está vendo esse problema em seu servidor de produção e precisa de uma resolução mais cedo ou mais tarde .

@nebstrebor bem, você tentou a sugestão para diminuir o tempo limite?

@CrazyPython o tíquete foi fechado. Você pode abrir um novo tíquete, descrever o problema que você tem e como podemos reproduzi-lo? Definitivamente ajudaria a descobrir se é o mesmo problema, outra coisa e co :)

Sim, não fez diferença, conforme observado acima. O problema era esporádico
o suficiente (nunca foi capaz de reproduzir) e catastrófico o suficiente para que tivéssemos que
fazer esse movimento (já se passou mais de um ano). Eu realmente gosto de Gunicorn embora,
e o usamos fora do Heroku sem problemas.

Ben Roberts
CTO e cofundador
Nutrislice, Inc.
[email protected]
célula - 801-735-7845

Na terça-feira, 30 de junho de 2015 às 8h08, Benoit Chesneau [email protected]
escreveu:

@nebstrebor https://github.com/nebstrebor bem, você tentou o
sugestão para diminuir o tempo limite?

@CrazyPython https://github.com/CrazyPython o tíquete foi fechado.
Você pode abrir um novo tíquete, descrever o problema que você tem e como podemos
reproduzi-lo? Definitivamente ajudaria a descobrir se é o mesmo problema,
outra coisa e co :)

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/benoitc/gunicorn/issues/588#issuecomment -117199606.

Acho que também estamos vendo esse problema. Ambos os trabalhadores (--workers 2) se atrapalharam com algumas solicitações de longa duração, eventualmente morreram (--timeout 20), e imediatamente vemos dois H13s, e então começamos a reiniciar H12s & WORKER TIMEOUT. Nos 10 minutos seguintes, isso continuou, os trabalhadores nunca processaram com êxito uma solicitação antes de atingirem o tempo limite e serem reiniciados. Então, reiniciamos o dinamômetro e isso corrigiu.

Uma coisa interessante que notei que não vi ninguém notar - vemos dois H13s (Conexão fechada sem resposta) no início do problema e, então, quando finalmente emitimos o SIGTERM, vimos uma inundação de H13s - 48 para ser exato, que é o mesmo número de WORKER TIMEOUTs que vimos (excluindo os dois primeiros para os quais vimos um H13 imediato). Não tenho certeza do que isso significa, mas parece suspeito ....

o que é H13s ou H12s? Isso é algo de heroku? Como é dada a porta na qual o gunicorn será ligado? Suspeito que o proxy heroku não está detectando que o soquete está fechado.

Além disso, qual trabalhador você está usando?

Sim, são códigos de erro Heroku:
H12 - Solicitar tempo limite - geralmente 30s (https://devcenter.heroku.com/articles/error-codes#h12-request-timeout)
H13 - Conexão fechada sem resposta - (https://devcenter.heroku.com/articles/error-codes#h13-connection-closed-without-response)

Edit: Acabei de notar que o gunicorn usará PORT se existir como uma variável de ambiente, então é assim que a porta é configurada.

Estamos usando trabalhadores síncronos.

E também esqueci de mencionar que estamos executando o gunicorn 19.3.0

encerrando a emissão já que há muito tempo não acontecia ali nenhuma atividade. Talvez ter um tempo limite atrasado seja bom para aplicativos de início demorado, mas isso deve ser feito em outro tíquete, se necessário.

Ei, eu também estou enfrentando o mesmo problema com gunicorn uvicorn no heroku com procfile de administração new-relic:

newrelic-admin run-program gunicorn -w 4 -k uvicorn.workers.UvicornWorker app.main:fastapi_app -b 0.0.0.0:${PORT:-5000} --log-level info --access-logfile=- --logger-class=gunicorn_color.Logger --preload

Isso me leva a este log assim que o sistema é inicializado:

2021-03-19T13:18:19.187532+00:00 heroku[web.1]: State changed from starting to up
2021-03-19T13:18:51.964740+00:00 heroku[router]: at=error code=H12 desc="Request timeout" method=GET path="/" host=api-app-clienti-pr-49.herokuapp.com request_id=8742009a-3e56-4f83-a147-97ff84d4e30b fwd="5.89.111.249" dyno=web.1 connect=1ms service=30003ms status=503 bytes=0 protocol=https
2021-03-19T13:19:04.292784+00:00 heroku[router]: at=error code=H12 desc="Request timeout" method=GET path="/api" host=api-app-clienti-pr-49.herokuapp.com request_id=85b6320a-7728-4074-87eb-b0992e7c3f9d fwd="5.89.111.249" dyno=web.1 connect=3ms service=30001ms status=503 bytes=0 protocol=https
Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

benoitc picture benoitc  ·  4Comentários

bywangxp picture bywangxp  ·  4Comentários

ttcqaq picture ttcqaq  ·  4Comentários

lordmauve picture lordmauve  ·  3Comentários

Abraxos picture Abraxos  ·  4Comentários