我有这个小的Flask视图,它从正在运行的pg_dump
命令中流出数据。只要我没有在启动过程中发生任何错误,就可以完美运行。有没有什么方法可以延迟设置HTTP状态代码,直到生成器函数pg_dump_yielder
的第一次收益发生?至少可以处理初始错误。
import errno
import os
import fcntl
import subprocess as subp
from flask import Flask, Response, abort
app = Flask(__name__)
cmd = ['pg_dump', '--format=c', '--no-owner', '--no-privileges', '--no-acl',
'--username=postgres', 'mywebsite_db']
def make_fd_async(fd):
"""Helper function to add the O_NONBLOCK flag to a fd"""
fcntl.fcntl(fd, fcntl.F_SETFL,
fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)
def read_async(fd):
"""Helper function to read some data from a fd, ignoring EAGAIN errors"""
try:
return fd.read()
except IOError as exc:
if exc.errno == errno.EAGAIN:
return b''
else:
raise exc
@app.route('/')
def pg_dump_view():
proc = subp.Popen(cmd, stdout=subp.PIPE, stderr=subp.PIPE)
make_fd_async(proc.stdout)
make_fd_async(proc.stderr)
def pg_dump_yielder():
stderr_data = b''
while True:
stdout_data = read_async(proc.stdout)
new_stderr_data = read_async(proc.stderr)
if new_stderr_data:
stderr_data += new_stderr_data
continue
if stderr_data:
abort(500, stderr_data.decode())
if stdout_data:
yield stdout_data
return_code = proc.poll()
if return_code is not None:
return abort(500, "Exited with: {}".format(return_code))
return Response(pg_dump_yielder(), mimetype='application/octet-stream')
app.run(debug=True)