Как предотвратить истечение времени ожидания рабочих-инициалистов gunicorn в длительных задачах Flask -Apscheduler? - PullRequest
0 голосов
/ 23 марта 2020

У меня небольшое приложение Flask, работающее на сервере, предназначенном для анализа диска. Это показывает умные параметры дисков, и я пытаюсь добавить функцию форматирования диска к нему. Неважно, что это за операция (безопасный переход или просто «клочок»), но это занимает довольно много времени. Сначала я попробовал syn c работников с командой:

./venv/bin/gunicorn -b :5000 --access-logfile - --error-logfile - --log-file - -p myapp.pid -w 5 run:app

С задачами планировщика, создающими деталь:

if disk_type == 'NVMe':
    scheduler.add_job(id=f'{serial}_formatting',
                      func=format_nvme,
                      args=[name, serial])
elif disk_type == 'HDD':
    scheduler.add_job(id=f'{serial}_formatting',
                      func=format_hdd,
                      args=[name, serial])
...

И функцией форматирования:

def format_hdd(name, serial):
    from run import app
    with app.app_context():
        print(f'[{datetime.now()}] initiated ssd formatting. name={name}, serial={serial}')
        record_in_db = Disk.query.filter(Disk.serial == serial).first()
        record_in_db.formatting_status = 1
        db.session.commit()
        info, error = Popen(f'wipefs -a {name}', shell=True, stdout=PIPE,
                        stderr=PIPE).communicate()
        process = Popen(f'shred -v {name}', shell=True, stdout=PIPE, stderr=PIPE,
                    encoding='utf-8', errors='replace', bufsize=1)
        while True:
            realtime_output = process.stdout.readline()
            if realtime_output == '' and process.poll() is not None:
                break
            if realtime_output:
                record_in_db.formatting_last_msg = realtime_output
                db.session.commit()

As Вы можете видеть, я хочу хранить сообщения процесса, чтобы иметь возможность видеть ход форматирования, это важная часть.

run.py:

from flaskapp import create_app

app = create_app()
from flaskapp import routes

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', use_reloader=True)

И в create_app () он просто инициализирует планировщик / db следующим образом:

    if not scheduler.running:
        scheduler.init_app(app)
        scheduler.start()
    ...
    return app

Запуск flaskapp с командой gunicorn, как описано выше, в большинстве случаев приводит к выходу тайм-аута одного / нескольких рабочих, поскольку иногда на консоли не выводится никакой команды, а выполняется:

[11209] [CRITICAL] WORKER TIMEOUT (pid:11214)

Простое решение - больший тайм-аут, но форматирование - действительно длительная операция ... Ответ на этот вопрос stackoverflow дал мне идею использовать работников eventlet, но это не помогло и я все еще получаю ошибки:

[2020-03-23 14:13:33 +0800] [29136] [CRITICAL] WORKER TIMEOUT (pid:29142)
Exception in worker
Traceback (most recent call last):
  File "/usr/lib/python3.7/concurrent/futures/thread.py", line 78, in _worker
    work_item = work_queue.get(block=True)
  File "/home/user/flaskapp/venv/lib/python3.7/site-packages/gunicorn/workers/base.py", line 201, in handle_abort
    sys.exit(1)
SystemExit: 1

Как я могу это исправить и всегда иметь возможность видеть, что операция закончилась? (Все эти команды заканчиваются каким-либо образом, но я просто не вижу при из-за погибших рабочих) Или, может быть, есть более подходящие способы для реализации этой функциональности?

...