Gunicorn: КРИТИЧЕСКИЙ ТАЙМ-АУТ РАБОТНИКА при запуске приложения Flask

Созданный на 5 июн. 2018  ·  82Комментарии  ·  Источник: benoitc/gunicorn

Кажется, уже было несколько отчетов, связанных с ошибкой [CRITICAL] WORKER TIMEOUT но она продолжает появляться. Вот моя проблема.

Я запускаю это приложение Flask hello world.

from flask import Flask
application = Flask(__name__)

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

Команда Gunicorn такова:

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

И это консольный вывод:

[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

Не могли бы вы четко объяснить, почему я получаю ошибку и ожидается ли это в этом примере? Как мне это исправить или, если это ожидаемое поведение, почему тогда критическая ошибка?

Investigation unconfirmed

Самый полезный комментарий

Использование gunicorn с gevent не устранило ошибку.

Все 82 Комментарий

Ошибка не ожидается, но в вашем примере нет ничего, что могло бы показать, почему это происходит. Расскажите нам больше о вашем окружении.

  • Какой клиент используется для подключения к Gunicorn?
  • Какой обратный прокси-сервер, если он есть, используется для подключения к Gunicorn?

Расскажите нам больше о вашем окружении.

  • Какой клиент используется для подключения к Gunicorn?
    => Я просто отправил запрос из Chromium: http: // localhost : 5000 /
  • Какой обратный прокси-сервер, если он есть, используется для подключения к Gunicorn?
    => Без прокси, только Gunicorn + Flask

Я только что воспроизвел проблему на совершенно новой установке, вот шаги:

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

hello.py - это то же самое приложение Flask, которое я опубликовал в первоначальном отчете.
Ниже представлен полный журнал.

~$ 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 Я думаю, это из-за тайм-аута по умолчанию ваш рабочий молчал 30 http://docs.gunicorn.org/en/stable/settings.html#timeout

Из вашего журнала

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

Я наблюдаю то же самое: время ожидания воркеров истекает, даже если они не обслуживают запросы, с синхронизирующим воркером.
В этом смысле журнал критического уровня довольно запутан.

Попробуйте использовать Gevent worker, чтобы решить эту проблему.

В этом смысле журнал критического уровня довольно запутан.

Собственно, это был мой первоначальный вопрос: если это ожидаемое поведение, почему тогда критическая ошибка?
Было бы также неплохо получить некоторую справочную информацию о том, почему необходимо перезапускать рабочие процессы, возможно, это можно было бы добавить в документ дизайна .

Я тоже это вижу (воспроизведено с использованием examples/test.py с gunicorn test:app -b localhost:9595 --log-level=debug --timeout=5 ), и я согласен, что критический уровень немного сбивает с толку. Я был бы в порядке, изменил его на уровень отладки. @benoitc @tilgovi что ты думаешь?

Я думаю, что уровень информации может быть немного лучше.

У меня было то же самое с MSYS2 на Win10, но, наконец, я решил.

в notify () of ... \ gunicorn \ worker \ workertmp.py изначально используется os.fchmod. Но в MSYS это не работает. Вместо os.fchmod я использовал os.utime. Код соблюдается. Я думаю, что это может работать на всех платформах.

    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 Я бы не ожидал, что рабочий завершится, потому что запросов не происходит. Эта ошибка должна произойти только в том случае, если рабочий был занят какое-то время> истечения тайм-аута. Так что ошибка критическая. Imo, мы должны улучшить документацию, чтобы предоставить больше вариантов использования и ответов на такие ошибки.

Если ошибка все еще возникает, когда воркер не занят, значит, что-то еще происходит, и у нас, вероятно, есть ошибка.

[РЕДАКТИРОВАТЬ]
Та же ошибка для меня.
С Django 1.10 / gunicorn 19.6.0 / Python 2.7.15 в python2.7-alpine на Debian 8.8 и стандартном ядре 3.16 все работало нормально.
После обновления до Django 1.11 и gunicorn 19.8.1 рабочие продолжают терпеть неудачу при загрузке с [CRITICAL WORKER TIMEOUT].
Понижение версии Gunicorn до 19.6.0 не решает проблемы.
Мы обновили ядро ​​хоста до 4.9.0 (это было запланировано), и рабочие успешно загрузились без ошибок.
Но:

  • мы используем 4 рабочих
  • после ровно 4 вызовов приложения Django следующие вызовы будут отключены по таймауту, и в журналах будет отображаться [CRITICAL WORKER TIMEOUT]
  • команда linux top показывает, что 4 процесса-пулеметчика застряли с довольно высоким потреблением ресурсов ЦП.

Мы собираемся попробовать gunicorn gevent, чтобы увидеть, сможем ли мы вернуть наше приложение в онлайн.

Использование gunicorn с gevent не устранило ошибку.

есть новости по этой проблеме?

Похоже, @neocolor обнаружил настоящую ошибку в MSYS. Возможно, это заслуживает отдельного разговора.

@bigunyak на какой платформе вы работаете? Я попытался воспроизвести на простом примере, и я не могу сделать это в точности, как описано выше. Это согласуется с моим опытом запуска нескольких приложений в производстве на нескольких фреймворках. Насколько мне известно, система уведомлений рабочих в последнее время не менялась. Моя платформа - Python 3.7 на MacOS 10.13.6, но я запускаю Gunicorn в производственной среде с синхронизирующими воркерами для нескольких приложений на Python 2.7 и 3.6.5 и вижу тайм-ауты воркеров только тогда, когда есть законно длинные запросы, которые блокируют воркеры.

Для @Tberdy : что произойдет, если вы попытаетесь установить --worker-tmp-dir где-нибудь за пределами файловой системы tmpfs? Мне просто интересно, может быть, alpine или docker или их комбинация как-то мешает тому, как рабочие уведомляют арбитра.

См. Также # 1388 о проблемах tmpfs, связанных с Docker.

у меня есть эта проблема.

У меня тоже есть эта проблема, синхронизация с пулеметом работала отлично до прошлой ночи, но не начала сообщать, тайм-аут рабочих [КРИТИЧНО] с использованием gevent, похоже, решил мою проблему, но я действительно хотел бы знать, почему это произошло.

@ timoj58 @cjmash не могли бы вы подробнее рассказать о проблеме? Как вы запускаете Gunicorn (в виртуальной машине ?, параметры ...), какую файловую систему, ОС? Было бы очень полезно все, что могло бы помочь воспроизвести :)

@benoitc Я запускаю gunicorn, чтобы запустить свой проект Django на кубернетах, мои аргументы Gunicorn --bind = $ port --workers = 7 --timeout = 1200 --log-level = debug --access-logfile - error-logfile - "

ошибки, которые я получаю из журналов

`` E [2018-08-09 21:47:56 +0000] [13] [INFO] Загрузка рабочего с pid: 13

E [2018-08-09 21:47:56 +0000] [14] [INFO] Загрузка worker с pid: 14

E [2018-08-09 21:47:56 +0000] [12] [INFO] Загрузка рабочего с pid: 12

E [2018-08-09 21:47:56 +0000] [1] [DEBUG] 7 рабочих

E [2018-08-09 21:47:56 +0000] [11] [INFO] Загрузка рабочего с pid: 11

E [2018-08-09 21:47:55 +0000] [10] [INFO] Загрузка worker с pid: 10

E [2018-08-09 21:47:55 +0000] [9] [INFO] Загрузка рабочего с pid: 9

E [2018-08-09 21:47:55 +0000] [8] [INFO] Загрузка рабочего с pid: 8

E [2018-08-09 21:47:55 +0000] [1] [INFO] Использование worker: sync

E [2018-08-09 21:47:55 +0000] [1] [INFO] Прослушивание: http://0.0.0.0 : 4040 (1)

E [2018-08-09 21:47:55 +0000] [1] [DEBUG] Arbiter загружен

E [2018-08-09 21:47:55 +0000] [1] [INFO] Запуск Gunicorn 19.7.1

E raw_paste_global_conf: []

E-шифры: TLSv1

E do_handshake_on_connect: Ложь

E suppress_ragged_eofs: Верно

E ca_certs: Нет

E cert_reqs: 0

E ssl_version: 2

E certfile: Нет

Ключевой файл E: Нет

E proxy_allow_ips: ['127.0.0.1']

E proxy_protocol: Ложь

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 when_ready:

E on_reload:

E on_starting:

E paste: Нет

E pythonpath: Нет

E default_proc_name: art.wsgi

E имя_процесса: Нет

E statsd_prefix:

E statsd_host: Нет

E enable_stdio_inheritance: Ложь

E syslog_facility: пользователь

E syslog_prefix: Нет

Системный журнал E: ложь

E syslog_addr: udp: // локальный хост: 514

E logconfig: Нет

E logger_class: gunicorn.glogging.Logger

E capture_output: ложь

E loglevel: отладка

E журнал ошибок: -

E access_log_format:% (h) s% (l) s% (u) s% (t) s "% (r) s"% (s) s% (b) s "% (f) s" "% ( в виде"

Журнал доступа E: -

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: Нет

E initgroups: Ложь

E umask: 0

Группа E: 0

E пользователь: 0

E worker_tmp_dir: Нет

E pidfile: Нет

E raw_env: []

Демон E: Ложь

Электронный адрес: / usr / src / app

E sendfile: Нет

E preload_app: Ложь

E check_config: Ложь

E spew: Ложь

E reload_engine: авто

E reload: Ложь

E limit_request_field_size: 8190

E limit_request_fields: 100

E limit_request_line: 4094

E keepalive: 2

E graceful_timeout: 30

E тайм-аут: 1200

E max_requests_jitter: 0

E max_requests: 0

E worker_connections: 1000

E потоков: 1

E worker_class: синхронизация

E рабочие: 7

Задание на E: 2048

E-привязка: ['0.0.0.0:4040']

E config: Нет

E [2018-08-09 21:47:55 +0000] [1] [DEBUG] Текущая конфигурация:

I Никаких миграций для применения.

I Выполняются миграции:

Применяю все миграции: admin, auth, contenttypes, core, dashboard, jet, oauth2_provider, sessions

I Операции, которые необходимо выполнить:

E [2018-08-09 21:47:20 +0000] [13] [INFO] Рабочий выходит (pid: 13)

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

E /usr/src/app/art/wsgi.py:19: Предупреждение пользователя: не читает /usr/src/app/.env - его не существует.

E [2018-08-09 21:47:00 +0000] [21] [INFO] Загрузочный воркер с pid: 21

E [2018-08-09 21:47:00 +0000] [1] [INFO] Сигнал обработки: срок

E [2018-08-09 21:46:35 +0000] [12] [INFO] Загрузка рабочего с pid: 12

E [2018-08-09 21:46:34 +0000] [13] [INFO] Загрузка рабочего с pid: 13

E [2018-08-09 21:46:34 +0000] [11] [INFO] Загрузка worker с pid: 11

E [2018-08-09 21:46:34 +0000] [1] [DEBUG] 7 рабочих

E [2018-08-09 21:46:34 +0000] [10] [INFO] Загрузка worker с pid: 10

E [2018-08-09 21:46:34 +0000] [9] [INFO] Загрузка рабочего с pid: 9

E [2018-08-09 21:46:34 +0000] [8] [INFO] Загрузка рабочего с pid: 8

E [2018-08-09 21:46:34 +0000] [7] [INFO] Загрузка рабочего с pid: 7

E [2018-08-09 21:46:34 +0000] [1] [INFO] Использование worker: sync

E [2018-08-09 21:46:34 +0000] [1] [INFO] Прослушивание: http://0.0.0.0 : 4040 (1)

E [2018-08-09 21:46:34 +0000] [1] [DEBUG] Arbiter загружен

E [2018-08-09 21:46:34 +0000] [1] [INFO] Запуск Gunicorn 19.7.1

E raw_paste_global_conf: []

E-шифры: TLSv1

E do_handshake_on_connect: Ложь

E suppress_ragged_eofs: Верно

E ca_certs: Нет

E cert_reqs: 0

E ssl_version: 2

E certfile: Нет

Ключевой файл E: Нет

E proxy_allow_ips: ['127.0.0.1']

E proxy_protocol: Ложь

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 when_ready:

E on_reload:

E on_starting:

E paste: Нет

E pythonpath: Нет

E default_proc_name: art.wsgi

E имя_процесса: Нет

E statsd_prefix:

E statsd_host: Нет

E enable_stdio_inheritance: Ложь

E syslog_facility: пользователь

E syslog_prefix: Нет

Системный журнал E: ложь

E syslog_addr: udp: // локальный хост: 514

E logconfig: Нет

E logger_class: gunicorn.glogging.Logger

E capture_output: ложь

E loglevel: отладка

E журнал ошибок: -

E access_log_format:% (h) s% (l) s% (u) s% (t) s "% (r) s"% (s) s% (b) s "% (f) s" "% ( в виде"

Журнал доступа E: -

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: Нет

E initgroups: Ложь

E umask: 0

Группа E: 0

E пользователь: 0

E worker_tmp_dir: Нет

E pidfile: Нет

E raw_env: []

Демон E: Ложь

Электронный адрес: / usr / src / app

E sendfile: Нет

E preload_app: Ложь

E check_config: Ложь

E spew: Ложь

E reload_engine: авто

E reload: Ложь

E limit_request_field_size: 8190

E limit_request_fields: 100

E limit_request_line: 4094

E keepalive: 2

E graceful_timeout: 30

E тайм-аут: 1200

E max_requests_jitter: 0

E max_requests: 0

E worker_connections: 1000

E потоков: 1

E worker_class: синхронизация

E рабочие: 7

Задание на E: 2048

E-привязка: ['0.0.0.0:4040']

E config: Нет

E [2018-08-09 21:46:34 +0000] [1] [DEBUG] Текущая конфигурация:

`` ''

На этот раз я немного попытался воспроизвести проблему, но она все еще присутствует в последней версии Gunicorn 19.9.0.
Шаги по воспроизведению точно такие же, как я описал в этом посте .
Моя система - Arch Linux x86_64 GNU / Linux (ядро 4.17.2-1-ARCH), Python 3.6.5
Вот свежая трассировка журнала.

~$ 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

Как и прежде, чтобы проверить это, я просто нажимал http://0.0.0.0 : 5000 / в Chromium.
Ниже приводится содержимое Pipfile и Pipfile.lock, чтобы вы могли увидеть точное окружение.

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

К вашему сведению, я также очень часто наблюдаю этот сбой с:

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

У меня есть только wsgi.py, в котором

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

Сообщите мне, если есть что-то, что вы хотите, чтобы я попробовал / поэкспериментировал, или если в журналах есть особенности, которые вы хотите, чтобы я проверил. Я запускаю фляжку на виртуальной машине GCP.

Извините за поздний ответ. Я управляю им как

gunicorn --log-file = / home / ubuntu / log / gunicorn.log api- предиктор localhost: 5000 &

Я использовал настройку gevent и т. д., но я изменил свой дизайн того, для чего мне это требовалось, чтобы обойти проблему, поэтому базовая настройка выше (которая также не удалась, но этого следовало ожидать, учитывая отсутствие gevent)

Python версии 3.6
env: aws tensorflow_p36 optmized (Ubuntu)
nginx находится перед Gunicorn, который запускает приложение flask.

версия фляги 1.0.2
nginx версии 1.10.3
Gunicorn версия 19.9.0

Я также изменил таймауты nginx, если это могло быть причиной.

Столкнувшись с той же проблемой с сервером 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 журналы / error.log --log-level = информация

Фляга == 0.12.1
пулеметчик == 19.7.1

когда я запускаю сервер с помощью приведенной выше команды, моя система зависает на некоторое время, и рабочие pid продолжают загружаться, хотя я сохранял тайм-аут 120 секунд, и сервер не принимает один запрос.

Есть новости по этой проблеме? У меня такая же проблема

[CRITICAL] ТАЙМ-АУТ РАБОТНИКА

Хотите знать, удалось ли кому-нибудь воспроизвести это в образе Docker?

Также это наблюдается при попытке реализовать рабочий процесс datadog ddtrace-run в существующем приложении, начиная с gunicorn -k gevent --threads 4.

Забавный след SystemExit, которого я тоже раньше не видел ...
[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

Я могу решить эту проблему, сопоставив количество рабочих и количество потоков.

Я установил workers = (2 * cpu_count) + 1 и не устанавливал потоки.

Как только я изменил threads = workers , все начало работать нормально. На всякий случай, если это кому-то поможет.

Вот как это выглядит сейчас

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

Я столкнулся с этой проблемой при запуске Django с одним контейнером Docker на AWS Elastic Beanstalk. Я решил проблему, исправив свои группы безопасности, чтобы мой экземпляр EC2 мог взаимодействовать с моим экземпляром RDS. Я понимаю, что это не может быть решением этой проблемы для 99% людей, но я оставляю эту заметку, чтобы помочь другим не тратить впустую часы, падая в эту кроличью нору.

В моем случае проблема была решена путем выполнения systemctl daemon-reload .
Короче говоря, я знал тайм-аут по умолчанию в 30 секунд, но не мог его изменить, пока не решил, что мне, конечно, нужно перезагрузить демон systemd, чтобы применить изменения к службе.

@bigunyak @benoitc @tilgovi
После долгой погони за гуглями и некоторых экспериментов я считаю, что основной причиной этой проблемы является хром «служба предварительного подключения / прогнозирования» (который по умолчанию включен как в Chrome, так и в Chromium).

@jeiting хорошо написал об этой проблеме
https://hackernoon.com/chrome-preconnect-breaks-singly-threaded-servers-95944be16400
Некоторые дополнительные материалы для чтения:
https://github.com/corydolphin/flask-cors/issues/147
https://github.com/pallets/flask/issues/2169

TL; DR
В некоторых случаях Chrome / Chromium открывает и удерживает «пустые» TCP-соединения (т. Е. Предсказывает, что скоро будет получен другой ресурс). Если «пустое» TCP-соединение сначала попадает на ваш сервер-пулемет, тогда любой последующий «настоящий» запрос от Chrome может застрять за «пустым» запросом до тех пор, пока не истечет время ожидания рабочего (-ых), обрабатывающего «пустой» запрос. Это более вероятно, если в Gunicorn запущен только один исполнитель синхронизации. Но, как показали мои эксперименты, это может произойти, даже если вы используете несколько рабочих процессов синхронизации.

Моя среда

  • Моя родная ОС - Ubuntu 17
  • У меня есть API отдыха, работающий в локальном контейнере докеров. Соответствующие строки из 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
......
  • У меня установлено 3 браузера: Firefox 61.0.1, Chromium 67.0.3396.99, Chrome 70.0.3538.102
  • У меня есть приложение для реагирования, которое обслуживается из другого контейнера докеров на другом порту.
  • Приложение React делает запросы CORS AJAX к моему API (это запросы CORS, потому что javascript обслуживается на одном порту localhost, а его вызовы API отправляются на другой порт localhost)
  • Запрос, который всегда «блокируется» в моих экспериментах, - это запрос CORS OPTIONS (запускаемый браузером для запроса разрешения на выполнение запроса POST). Кажется логичным, что браузер попытается установить предиктивные соединения с вызовом OPTIONS, потому что он, вероятно, последует за вызовом POST.

Эксперимент 1
Конфигурация Gunicorn: 1 синхронизатор (таймаут по умолчанию 30 секунд)

Firefox: почти при каждой загрузке страницы ответа запрос CORS OPTIONS блокируется на 5 секунд, а затем завершается успешно.
Chromium: при загрузке КАЖДОЙ страницы ответа запрос CORS OPTIONS блокируется на 1,5 минуты !!!! а потом добивается успеха.
Chromium (служба прогнозирования отключена): все загружается нормально
Chrome: все загружается нормально

Эксперимент 2
Конфигурация Gunicorn: 4 синхронизатора (таймаут по умолчанию 30 секунд)

Firefox: все загружается нормально
Chromium: при каждой загрузке третьей страницы ответа запрос CORS OPTIONS блокируется на 30 секунд, а затем выполняется успешно.
Chromium (служба прогнозирования отключена): все загружается нормально
Chrome: все загружается нормально

Эксперимент 3
Конфигурация Gunicorn: 8 синхронизаторов (таймаут по умолчанию 30 секунд)

Firefox: все загружается нормально
Хром: все загружается нормально
Chrome: все загружается нормально

Эксперимент 4.
Запустите сервер flask dev с threaded=True

Firefox: все загружается нормально
Хром: все загружается нормально
Chrome: все загружается нормально

Сводка эксперимента

  • В Firefox, похоже, тоже есть служба прогнозирования, но она кажется более изящной. (Эксперимент 1)
  • Chromium кажется наиболее агрессивным в создании "предсказательных" связей. Похоже, что во время запроса OPTIONS запускается до 3-4 "прогнозных" соединений (эксперимент 1 и 2).
  • Удивительно, хотя в Chrome также включена служба прогнозирования, это не вызвало никаких проблем ни в одном из экспериментов (возможно, порядок или количество "прогнозирующих" соединений отличается от Chromium)

Решение
В производстве: самое простое решение - поставить nginx перед пулеметом. Если вы хотите понять, почему nginx решает эту проблему, вот хорошая статья, которая объясняет это: https://www.brianstorti.com/the-role-of-a-reverse-proxy-to-protect-your-application-against -медленные клиенты /

В dev: самое простое решение - запустить сервер flask dev с threaded=True . Или вы можете отключить службу прогнозов в Chrome / Chromium.

улучшения отладки Gunicorn
Чтобы помочь отладить подобную проблему в будущем, я думаю, что было бы неплохо добавить операторы журнала отладки рядом с вызовами select() и accept() в работнике синхронизации.
https://github.com/benoitc/gunicorn/blob/e974f30517261b2bc95cfb2017a8688f367c8bf3/gunicorn/workers/sync.py#L26
https://github.com/benoitc/gunicorn/blob/e974f30517261b2bc95cfb2017a8688f367c8bf3/gunicorn/workers/sync.py#L34
Это покажет, что работник принял новое TCP-соединение, но не получает никаких данных.

@asnisarenko супер

Это может быть Gunicorn, для однопоточных синхронизаторов потребуется некоторая новая настраиваемая функция, агрессивное отбрасывание клиента для клиентов, которые не могут отправить хотя бы первую строку заголовка запроса, если не все заголовки, в разумные сроки.

Если это происходит в вашем приложении, вы можете добавить временный диагностический код:

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)

Надеюсь, это покажет, где зависает ваше приложение.

Например, мне каким-то образом удалось import flask перед gevent.monkey.patch_all() и поэтому мой Flask app._before_request_lock оказался блокировкой, не связанной с gevent (то есть простой незапатченной threading.Lock ). В таком случае два последовательных запроса при запуске приложения могут привести к его зависанию (второй запрос заблокирует весь поток). Но это была моя ошибка, и ваша ошибка может отличаться.

@asnisarenko Я не уверен, почему у вас зависание. Вам абсолютно _не_ нужен воркер на соединение, поскольку каждый воркер может совместно обрабатывать тысячи соединений (до тех пор, пока код обработки не монополизирует ЦП / блокирует весь поток). В частности, если браузер задерживает запрос, это просто означает, что когда gunicorn read() s из сокета, он заблокирует гринлет, но поскольку read должен быть пропатчен как обезьяна, он уступит другие гренлеты.

@ikonst
Эта проблема касается запуска Gunicorn с конфигурацией по умолчанию. Рабочий класс по умолчанию - sync http://docs.gunicorn.org/en/stable/settings.html#worker -class

sync worker используют модель pre-fork, и каждый рабочий обрабатывает одно TCP-соединение / запрос за раз.

Я не знаю, чем это вызвано для меня, но переключение с рабочего типа sync по умолчанию на eventlet решило проблему:

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

Удачи.

Возможно, это поможет только мне, но поскольку мне потребовалось 7 часов, чтобы отладить эту проблему на моей стороне (приложение Flask / Gunicorn, работающее в Docker на EC2), если я смогу избавить от этой головной боли несколько человек, это маленькая победа.

Слишком низкий предел памяти контейнера.

Если в будущем у меня будут утечки памяти, я постараюсь поставить более высокий лимит памяти, но пока никаких ограничений не будет.

Спасибо

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)

Вы очень мне помогаете. ЕГУ)))

Куда идет этот метод trace_on_abort() ? В файле кода приложения? Нужна ли аннотация?

@ mattg-vbt добавьте это в начало вашего приложения, когда вам нужно отлаживать, и удалите его, когда закончите отладку

@ikonst Я добавил это в свое приложение, но не вижу, чтобы оно стало популярным. Я получаю тайм-аут рабочего, но этот метод не работает.

@ mattg-vbt, можете попробовать сделать kill -ABRT $pid чтобы увидеть, как вызывается функция print_trace ? (идея состоит в том, что вы получите SIGABRT от werkzeug, когда время вашего воркера истечет, но давайте сначала проверим, вызывается ли он вообще)

@asnisarenko для менее сообразительных из нас, как мне тогда обновить procfile?

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

@SumNeuron
Если вы используете gevent worker'ы (вместо sync worker), вы не должны сталкиваться с этой проблемой. Итак, опубликованная вами команда кажется прекрасной.

У меня проблема с работниками gevent только при инициализации, что немного раздражает, поскольку я обрабатываю некоторые задачи перед запуском своего приложения. Но пока я устанавливаю высокий тайм-аут.
Я разместил воспроизводимое тестовое репо здесь: https://github.com/zamponotiropita/test-gunicorn-worker-timeout -> test_0 не работает, test_1 и test_2 проходят

@zamponotiropita Вы пытаетесь сделать это для каждого рабочего или для каждого приложения до разветвления?

@ikonst, пожалуйста, проверьте файл запуска run.sh , он на одного воркера. Проблема возникла не с предварительной загрузкой, но у меня были проблемы с подключением к базе данных при предварительной загрузке, поскольку объект приложения (и вместе с ним соединение с базой данных) копируется и передает процессы при разветвлении -> моя база данных не могла справиться идентичные связи мастера и рабочих, и я не мог найти обходного пути

У меня похожая проблема. Я пытаюсь сгенерировать много данных на лету с помощью Flask, используя
этот метод, и он терпит неудачу, потому что время ожидания рабочего истекает после того, как истечет время, установленное в --timeout . Минимальный пример для воспроизведения:

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

Затем запустите gunicorn --timeout 10 test_gunicorn_timeout:app и при запросе localhost:8000 через 10 секунд вы получите
[CRITICAL] WORKER TIMEOUT .

Я также пробовал работать с -k gevent и -k eventlet и ничего не изменилось.

Я использую Windows 10 Pro. С докером сочинить
gunicorn app -b 0.0.0.0:8000 -k gevent
Работал для меня, установив gevent в моем контейнере python
Как установить gevent

Затем запустите gunicorn --timeout 10 test_gunicorn_timeout:app и при запросе localhost:8000 через 10 секунд вы получите
[CRITICAL] WORKER TIMEOUT .

Я также пробовал работать с -k gevent и -k eventlet и ничего не изменилось.

@ltskv

Вы нашли решение проблемы с [КРИТИЧЕСКИМ] ТАЙМ-АУТОМ РАБОТНИКА?

У меня аналогичная проблема с конечной точкой потоковой передачи фляги, которую я пытаюсь развернуть на heroku (которая использует Gunicorn). Предполагается, что интерфейс прокси-сервера поддерживает соединение до тех пор, пока некоторые данные отправляются в течение 30 секунд, но похоже, что Gunicorn просто убивает процесс, если он не завершился в течение 30 секунд, даже если он все еще работает и производит данные.

Документация Gunicorn не совсем ясна мне по этому поводу. Для --timeout он говорит, что Workers silent for more than this many seconds are killed and restarted. Но кажется, что рабочие убиты через 30 секунд, даже если они все еще производят данные?

Документация Gunicorn не совсем ясна мне по этому поводу. Для --timeout он говорит, что Workers, молчащие дольше этого количества секунд, убиваются и перезапускаются. Но кажется, что рабочих убивают через 30 секунд, хотя они все еще производят данные?

@ kurt-hectic, что документацию нужно улучшить. Под молчанием мы подразумеваем молчание с точки зрения процесса-арбитра, который общается с рабочими через временный файл. Если воркер занят отправкой данных, он не обновляет этот файл. С точки зрения арбитра, у рабочего отсутствует сердцебиение.

См. Также # 1974.

Используя любой рабочий процесс, отличный от стандартного, синхронный рабочий должен смягчить проблему с потоковой передачей больших тел, потому что другие рабочие будут обрабатывать временный файл, даже когда они обрабатывают запросы.

@ kurt-hectic Я еще раз перепроверил опцию -k gevent и вставил sleep(0) между итерациями генератора, и это действительно сработало для меня (я не уверен, почему это не сработало в то время Я все же разместил вопрос).

--timeout = 5

Это наиболее частая причина данной проблемы.

Надеюсь, мое решение может вам помочь. Я столкнулся с этой критической проблемой тайм-аута работника несколько дней назад и попробовал несколько решений. Теперь он работает хорошо.

Вот мое понимание и решения:

  1. Попробуйте предварительную загрузку в Gunicorn

Не удается загрузить рабочие процессы, потому что для запуска службы требуется больше времени для загрузки пакета, такого как серверная часть tenorflow. Поэтому, когда вы испытываете медленную загрузку приложения, попробуйте включить опцию предварительной загрузки в Gunicorn (см. Https://devcenter.heroku.com/articles/python-gunicorn#advanced-configuration).

Gunicorn привет: приложение --preload

  1. Попробуйте увеличить тайм-аут для стрельбы

Тайм-аут по умолчанию - 30 секунд. Если вашему приложению действительно нужно много времени, чтобы закончить api, увеличьте тайм-аут.

Gunicorn привет: приложение - тайм-аут 10

Однако, с моей точки зрения, это не имеет смысла, если для завершения api требуется более 1 минуты. Если да, попробуйте улучшить свой код.

  1. Если вы используете k8s, вы также можете установить timeoutSeconds для вашего контейнера / изображения в yaml.

Сегодня я столкнулся с той же проблемой. В моем случае api потребовалось около минуты для вычисления данных и возврата клиенту, что привело к КРИТИЧЕСКИМ ошибкам РАБОТНИКА ТАЙМАУТА. Я решил это, увеличив флаг тайм-аута для Gunicorn до более чем минуты - это сработало, проблема не вернулась. Надеюсь это поможет. Я использую uvicorn.workers.UvicornWorker.

Я исправил это, добавив в gnuicorn дополнительных рабочих:

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

Понятия не имею почему.

Может у вас был тупик? Ваше приложение делает запросы к самому себе?

Вс, 5 января 2020 г., 10:52 alpinechicken, [email protected] написал:

Я исправил это, добавив в gnuicorn дополнительных рабочих:

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

Понятия не имею почему.

-
Вы получили это, потому что прокомментировали.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/benoitc/gunicorn/issues/1801?email_source=notifications&email_token=AAAEQJVQRCW3C63EZJWIN5DQ4G3WTA5CNFSM4FDLD5PKYY3PNVWWK3TRE52XG43-5VMVM8VWWK3TREXG4DVMVMV8
или отказаться от подписки
https://github.com/notifications/unsubscribe-auth/AAAEQJXZM4NLK56DZMFSZALQ4G3WTANCNFSM4FDLD5PA
.

Да один маршрут вызывает другой - это плохо?

Это означает, что вам нужно как минимум два воркера, иначе ваш сервер будет
тупик. Запрос будет ждать, пока сервер не ответит на второй
запрос (который будет поставлен в очередь).

Вы получаете один одновременный запрос на каждого работника.

В пн, 6 января 2020 г., 02:45 alpinechicken, [email protected] написал:

Да один маршрут вызывает другой - это плохо?

-
Вы получили это, потому что прокомментировали.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/benoitc/gunicorn/issues/1801?email_source=notifications&email_token=AAAEQJSFEFBBI6AMZJCM4C3Q4KLOJA5CNFSM4FDLD5PKYY3PNVWWK3TVMOWIQNXWWWK3TREVMXWWWWK3TREVMXWWWWWK3TREVMXWWWWK3TREVMXWMWW2
или отказаться от подписки
https://github.com/notifications/unsubscribe-auth/AAAEQJXTCPOFIZJU5PUPOODQ4KLOJANCNFSM4FDLD5PA
.

Ах, в этом есть смысл. Спасибо!

Во вторник, 7 января 2020 г., в 6:23, bobf [email protected] написал:

Это означает, что вам нужно как минимум два воркера, иначе ваш сервер будет
тупик. Запрос будет ждать, пока сервер не ответит на второй
запрос (который будет поставлен в очередь).

Вы получаете один одновременный запрос на каждого работника.

В пн, 6 января 2020 г., 02:45 alpinechicken, [email protected] написал:

Да один маршрут вызывает другой - это плохо?

-
Вы получили это, потому что прокомментировали.
Ответьте на это письмо напрямую, просмотрите его на GitHub
<
https://github.com/benoitc/gunicorn/issues/1801?email_source=notifications&email_token=AAAEQJSFEFBBI6AMZJCM4C3Q4KLOJA5CNFSM4FDLD5PKYY3PNVWWK3TVMOJWI2KWMWWWK3TREVMXWWWWK3TREVMXWWW2KNVWWWK3TREVMXWW2
,
или отказаться от подписки
<
https://github.com/notifications/unsubscribe-auth/AAAEQJXTCPOFIZJU5PUPOODQ4KLOJANCNFSM4FDLD5PA

.

-
Вы получили это, потому что прокомментировали.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/benoitc/gunicorn/issues/1801?email_source=notifications&email_token=AAH2WRPVPVO2EJ53BKQW5B3Q4OHLRA5CNFSM4FDLD5PKYY3PNVWWK3TREX63JVLVMWWK3TREXWWWWWWK3TREXWWWWK3TREXWWWWWWK3TULXXXXXXWWWWK3TREXWWWWB08CM03VB08B08B08
или отказаться от подписки
https://github.com/notifications/unsubscribe-auth/AAH2WRM2LLIB4O6OHCU5UG3Q4OHLRANCNFSM4FDLD5PA
.

worker_class ',' синхронизация ')

Я могу решить эту проблему, сопоставив количество рабочих и количество потоков.

Я установил workers = (2 * cpu_count) + 1 и не устанавливал потоки.

Как только я изменил threads = workers , все начало работать нормально. На всякий случай, если это кому-то поможет.

Вот как это выглядит сейчас

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

Согласно документу gunicorn, он изменяет рабочий класс с синхронизации на gthread, если упоминается более одного потока.
PS: -
Если вы попытаетесь использовать тип рабочего процесса синхронизации и установите для параметра потоков значение больше 1, вместо него будет использоваться тип рабочего процесса gthread.

Мое дело:

Окружающая среда: Ubuntu18.04 + gunicorn + nginx + flask

pip install gunicorn [gevent] в моей виртуальной среде

Измените gunicorn -b localhost:8000 -w 4 web:app на gunicorn -b localhost:8000 -k gevent web:app

Оно работает.

Спасибо всем присутствующим, кто так много сделал, чтобы помочь друг другу решить свои проблемы. Продолжайте публиковать сообщения об этом выпуске, если это кажется уместным.

Однако я закрываю этот вопрос, потому что не думаю, что здесь есть какая-то ошибка в Gunicorn, и я не думаю, что нужно что-то предпринимать, хотя я с радостью помогу просмотреть PR, которые пытаются как-то добавить документацию для этого или улучшить сообщения журнала.

Пожалуйста, не поймите неправильно мои намерения. Если вы подозреваете ошибку в Gunicorn и хотите продолжить обсуждение, сделайте это. Желательно открыть новый билет с примером приложения, которое воспроизводит вашу проблему. Однако на данный момент в этом выпуске слишком много разных проблем, решений и обсуждений, чтобы его можно было легко разобрать.

Если вы запустите Gunicorn без буферизирующего обратного прокси-сервера перед ним, вы _will_ получите тайм-ауты с синхронизирующим воркером по умолчанию по любому количеству причин. Общие из них:

  • Медленные клиенты
  • Предварительное подключение / предварительная выборка соединений, которые открыты браузерами и прокси-серверами
  • Длинные ответы из-за вызова внешних API-интерфейсов или выполнения большого количества работы, связанной с процессором.

Вы можете переключиться на асинхронные или многопоточные рабочие типы, или вы можете поместить Gunicorn за буферизирующим обратным прокси-сервером. Если вы знаете, что тайм-ауты возникают из-за того, что ваш собственный код выполняет медленные вызовы внешних API-интерфейсов или выполняет значительную работу, которую вы ожидаете, вы можете увеличить значение параметра --timeout .

Это означает, что вам нужно как минимум два воркера, иначе ваш сервер зайдет в тупик. Запрос будет ждать, пока сервер не ответит на второй запрос (который будет поставлен в очередь). Вы получаете один одновременный запрос на каждого работника.

В пн, 6 янв 2020, 02:45 alpinechicken, @ . * > писал (а): Ага один маршрут вызывает другой - это плохо?

Так ли это при вызове функции «перенаправления» в качестве возвращаемого значения для маршрута?

Так ли это при вызове функции «перенаправления» в качестве возвращаемого значения для маршрута?

Нет. Перенаправление фляги отвечает перенаправлением HTTP, и работник может принять новый запрос. Клиент делает другой запрос, когда видит этот ответ, и всякий раз, когда рабочий будет готов, получит этот запрос.

Я исправил это, добавив в gnuicorn дополнительных рабочих:

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

Понятия не имею почему.

Связано ли это с комментарием workers=1 + (multiprocessing.cpu_count() * 2) ..?

У меня была аналогичная проблема. Оказывается, в моей точке входа в приложение произошла ошибка. Из-за отладки казалось, что я, по сути, запускал приложение flask из Gunicorn, работники которого впоследствии входят в бесконечный цикл подключения, который истекает каждые 30 секунд.

Я уверен, что это не коснется всех перечисленных выше пользователей, но может повлиять на некоторых.

В моем module/wsgi.py файле, который я запускаю с gunicorn module.wsgi меня было -

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

Тогда как я должен был -

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

По сути, вы не хотите вызывать application.run() при использовании Gunicorn. __name__ под gunicorn не будет "__main__" , но будет во Flask, так что вы все равно можете отлаживать локально.

Я не смог найти ссылку на это в документации по Gunicorn, но могу представить, что это обычная ошибка, поэтому, возможно, необходимо какое-то предупреждение.

Это все еще происходит. Добавление --preload к вызову Gunicorn устранило проблему для меня.

Эта ошибка все еще не исправлена? Я наблюдаю именно это поведение.

Gunicorn в 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

Рабочий процесс постоянно выходит из строя и перезапускается:

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 - это альтернативное приложение Flask.

Эта проблема закрыта как "Не исправлять"?

У меня тоже была такая же проблема

Но после отладки я смог обнаружить, что пока Gunicorn запускает приложение Django, одна из зависимостей занимала больше времени, чем ожидалось (в моем случае внешнее соединение с БД), что заставляет gunicron worker тайм-аут

Когда я решил проблему с подключением, проблема с тайм-аутом также решилась ...

Это не мой случай. Я тестировал приложение типа «Hello, World», без зависимостей. Так что я все еще озадачен этим, но кажется, что у Gunicorn нет возможности иметь долго работающий поток. Рабочий процесс перезапускается и, следовательно, прерывает длительный поток.

@leonbrag
Скорее всего, это НЕ ошибка пулеметчика. См. Мой отзыв выше в ветке. Это побочный эффект того, что браузеры отправляют пустые «предсказанные» TCP-соединения и запускают gunicorn только с несколькими синхронизаторами без защиты от пустых TCP-соединений.

Есть ли эталонная архитектура / дизайн, показывающий, как правильно настроить приложение фляги Gunicorn с длинным (постоянным) рабочим потоком?

Если это не ошибка, значит, это артефакт или ограничение архитектуры / дизайна Gunicorn.

Почему бы Sync worker не запускался вечно и не принимал подключения клиентов. Такой рабочий закрывал бы сокет по мере необходимости, но продолжал бы работать без выхода (и, следовательно, рабочий поток продолжал бы работать).

@leonbrag
Вам следует более конкретно указать, какую проблему вы пытаетесь решить.

Проблема, обсуждаемая в этом потоке, возникает в среде разработки, и самым простым решением является либо добавление дополнительных рабочих процессов синхронизации, либо использование потоковых рабочих процессов.

Если вы хотите избежать этой проблемы при настройке производства, вы можете использовать gevent worker или поставить nginx перед gunicorn.
Некоторые PaaS уже помещают nginx перед вашим контейнером докеров, поэтому вам не о чем беспокоиться. И снова решение зависит от контекста и деталей.

Это хорошее чтение.
https://www.brianstorti.com/the-role-of-a-reverse-proxy-to-protect-your-application-against-slow-clients/

Вы можете проверить страницу дизайна в документации. Асинхронные рабочие - это одно
способ запускать длинные задачи.

В субботу 8 августа 2020 года в 18:00 leonbrag [email protected] написал:

Есть ли эталонная архитектура / дизайн, показывающий, как правильно настроить
Приложение Gunicorn Flask с длинным (постоянным) рабочим потоком?

Если это не ошибка, значит, это артефакт или ограничение
Архитектура / дизайн Gunicorn.

Почему бы Sync worker не запускался вечно и не принимал подключения клиентов. Такой
worker закрывал сокет по мере необходимости, но продолжал работать без выхода
(и поэтому рабочий поток продолжает работать).

-
Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/benoitc/gunicorn/issues/1801#issuecomment-670944797 ,
или отказаться от подписки
https://github.com/notifications/unsubscribe-auth/AAADRIWRQGIP3R5PMVJ5ENTR7VZA3ANCNFSM4FDLD5PA
.

>

Отправлено с моего мобильного

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

Я исправил свою проблему, увеличив --timeout

См. Также # 1388 о проблемах tmpfs, связанных с Docker.

О, спасибо большое, Рэндалл, я забыл добавить --worker-tmp-dir /dev/shm к аргументам gunicorn, когда я запускал gunicorn в Docker.

Кстати, хватит ли 64 Мб для кеш-памяти Gunicorn?

приложение- пулемет
Или
приложение- пулеметчик

У меня сработало ... Я предпочитаю таймаут один.

Странно, я добавил --worker-tmp-dir /dev/shm но все равно получаю:

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

Чтобы убедиться, что /dev/shm - это ramfs, я протестировал его:

image

Параметры следующие:

    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: я использую PyPy

@attajutt timeout - это хорошо, но вы рискуете, что главный процесс gunicorn обнаружит зависание в вашем рабочем процессе только через 1000 секунд, и вы пропустите много запросов. Также его будет сложно обнаружить, если зависнет только один из нескольких воркеров. Я бы не стал делать 1000 по крайней мере.

@ivictbor спасибо за lmk. 1000 для справки. Тем не менее, я запустил приложение после загрузки. Оно работает отлично.

У меня тоже возникла эта проблема с ошибкой, и спустя несколько раз я обнаружил, что проблема, вероятно, вызвана:

  1. Конфигурация Nginx
  2. Gunicorn / Uwsgi

Если вы развернете свое приложение в облаке, таком как GAE, это не вызовет никаких намеков.
вы можете попытаться выявить ошибку, используя это решение для случая: https://stackoverflow.com/questions/38012797/google-app-engine-502-bad-gateway-with-nodejs

Если поднято 502 плохой шлюз;
вероятно будет 2 возможности:

  1. Gunicorn не работает
  2. Gunicorn получил тайм-аут

полное описание здесь: https://www.datadoghq.com/blog/nginx-502-bad-gateway-errors-gunicorn/

надеюсь, что это поможет исправить ошибку в [CRITICAL] WORKER TIMEOUT

Добавляем еще одну возможность для тех, кто найдет эту ветку ...

Это также может быть вызвано ограничениями ресурсов, наложенных докером, которые слишком малы для вашего веб-приложения. Например, у меня были следующие ограничения:

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

и они были явно слишком малы для gunicorn поэтому я постоянно получал ошибку [CRITICAL] WORKER TIMEOUT пока не снял ограничения.

Для Gunicorn эти ресурсы вполне подойдут. Но вам действительно нужно
самолет за количество рабочих и ресурсы, необходимые для вашего
применение. 128 МБ и 0,25 ЦП кажутся очень маленькими для веб-приложения
написано на Python .... вообще говоря, вам нужно как минимум 1 ядро ​​/ vcpu и
Минимум 512 МБ ОЗУ.

Пт 26 марта 2021 в 02:14, Colton Hicks @ . * > написал:

Добавляем еще одну возможность для тех, кто найдет эту ветку ...

Это также может быть вызвано ограничениями ресурсов, наложенными докером, которые
слишком низки для вашего веб-приложения. Например, у меня было следующее
ограничения:

Сервисы:
web_app:
изображение: бла-бла
развертывать:
Ресурсы:
пределы:
процессор: "0,25"
память: 128 МБ

и они были явно слишком низкими для пулеметчика, поэтому я постоянно получал [КРИТИЧЕСКИЙ]
Ошибка ВРЕМЕНИ РАБОТНИКА, пока я не снял ограничения.

-
Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/benoitc/gunicorn/issues/1801#issuecomment-807855647 ,
или отказаться от подписки
https://github.com/notifications/unsubscribe-auth/AAADRITPZB7BMA6QW7LFNVLTFPNV3ANCNFSM4FDLD5PA
.

>

Отправлено с моего мобильного

--timeout = 1000 у меня сработало. Проблема заключалась в том, что машина GCP с низким уровнем ресурсов ЦП. Он отлично работал на моем локальном компьютере с тайм-аутом по умолчанию.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги