3

My Flask 项目POST从多个在线商店接收订单作为请求,将这些订单保存到数据库中,并将购买信息转发到交付产品的服务。有时,产品未在最终服务中设置,请求以“未解决”状态位于我的服务数据库中。

在最终服务中设置产品时,我想启动一个长时间运行(可能是一分钟)的流程,将所有“未解决”的订单发送到最终服务。在这个过程中,Flask 是否仍然能够接收来自商店的订单并继续正常处理?如果没有,我是否需要将其卸载到像这样的任务运行器rq

我并不担心速度,而是担心一致性。购买的物品是现场活动的门票,因此只要在活动开始前传递订单信息,对客户应该没有任何影响。

4

2 回答 2

3

有几个不同的答案在不同的情况下都是有效的。快速的回答是,像 RQ 这样的作业队列通常是正确的解决方案,尤其是从长远来看,随着项目的增长。

只要 WSGI 服务器有可用的工作人员,就可以处理另一个请求。每个工作人员一次处理一个请求。开发服务器使用线程,因此可用的工作线程数量不受限制(受 Python 中线程的性能限制)。像 Gunicorn 这样的生产服务器可以使用多个 worker,以及不同类型的 worker,例如线程、进程或 eventlet。如果您想运行一个任务以响应 HTTP 请求并等到任务完成发送响应,您将需要足够的工作人员来阻止这些任务以及处理常规请求。

@app.route("/admin/send-purchases")
def send_purchases():
    ...  # do stuff, wait for it to finish
    return "success"

但是,您所描述的任务似乎是一个清理任务,无论用户的 HTTP 请求如何,都应该运行该任务。在这种情况下,您应该编写一个 Flask CLI 命令并使用 cron 或其他调度系统调用它。

@app.cli.command()
def send_purchases():
    ...
    click.echo("done")
# crontab hourly job
0 * * * * env FLASK_APP=myapp /path/to/venv/bin/flask send-purchases

如果您确实希望用户启动任务,但又不想阻止等待它完成的工作人员,那么您需要一个任务队列,例如 RQ 或 Celery。您也可以创建一个提交作业的 CLI 命令,以便能够按请求和按计划触发它。

@rq.job
def send_purchases():
    ...

@app.route("/admin/send-purchases", endpoint="send_purchases")
def send_purchases_view():
    send_purchases.queue()
    return "started"

@app.cli.command("send-purchases")
def send_purchases_command():
    send_purchases.queue()
    click.echo("started")
于 2020-09-27T00:04:16.960 回答
1

Flask 的开发服务器将为每个请求生成一个新线程。同样,生产服务器可以由多个工作人员启动。

您可以使用 gunicorn 或类似的多进程运行您的应用程序。例如,有四个流程工人:

gunicorn -w 4 app:app

例如使用 eventlet 工作者:

gunicorn -k eventlet app:app

请参阅有关在生产中部署的文档:https ://flask.palletsprojects.com/en/1.1.x/deploying/

于 2020-09-26T20:24:34.633 回答