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