请教 Flask 离线程序中如何利用上下文传递 g 和 request 参数 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
luxiaoer
V2EX    Python

请教 Flask 离线程序中如何利用上下文传递 g 和 request 参数

  •  
  •   luxiaoer 2020-12-08 10:10:14 +08:00 3507 次点击
    这是一个创建于 1782 天前的主题,其中的信息可能已经有所发展或是发生改变。

    现状: 原钉钉发送消息是同步程序,发送钉钉消息程序中有记录 Flask 程序运行日志,日志包含当前请求用户信息,和请求参数信息。

    问题:Flask 调用 Celery,Celery 执行程序后发送钉钉消息,钉钉消息程序中记录日志。

    概要代码如下

    # __init__.py def create_app(): .... return app # mycelery.py def make_celery(app): celery = Celery(__name__, broker=celeryconfig.broker_url, backend=celeryconfig.result_backend) celery.config_from_object(celeryconfig) class ContextTask(celery.Task): def __call__(self, *args, **kwargs): with app.app_context(): return self.run(*args, **kwargs) celery.Task = ContextTask return celery app = Flask(__name__) celery_app = make_celery(app) # celery_task.py @celery_app.task(bind=True,ignore_result=True,max_retries=5) def celery_stock_sync(self,**kwargs): pass # dd_utils.py from record_log import run_log def send_dd_msg(): res = dd_sdk.request() run_log(res) pass # record_log.py def run_log(): # 这里需要记录当前操作的用户信息,以及用户请求信息 user_id = g.get('user_id',None) method= request.method pass 
    28 条回复    2020-12-10 10:16:49 +08:00
    coolair
        1
    coolair  
       2020-12-08 10:28:53 +08:00
    with app.app_context():
    # ...
    luxiaoer
        2
    luxiaoer  
    OP
       2020-12-08 10:40:11 +08:00
    @coolair
    求详细知道
    是否在 run_log 函数中 with app.app_context()
    app 有是如何导入的
    如果是 app 是如何导入,如果 from app import create_app 会提示循环导入
    如果从 Flask(__name__) g 为 None request 会提示 Working outside of request context.

    另外我在 celery_task 中也尝试 with app.app_context(),g 也是 None
    echowuhao
        3
    echowuhao  
       2020-12-08 10:51:21 +08:00 via Android
    你应该换方式 把需要得信息在 context 里面提取出来 传给 celery 而不是在 celery 中获取
    luxiaoer
        4
    luxiaoer  
    OP
       2020-12-08 10:58:28 +08:00
    @echowuhao
    可以是可以,但是这种方式不够解藕
    如果后续需要添加新的字段,就需要整个调整。
    关键是,原来的 run_log 就需要重写,就不能用 g 和 request 。相关的调用程序也需要重写吧
    14v45mJPBYJW8dT7
        5
    14v45mJPBYJW8dT7  
       2020-12-08 11:06:54 +08:00
    copy.deepcopy 可以实现么
    echowuhao
        6
    echowuhao  
       2020-12-08 11:14:39 +08:00 via Android
    @luxiaoer 代码要尽量少用 global 的东西 refactor 你的代码 object 进入 celery 都要序列化一个来回 费时费力
    luxiaoer
        7
    luxiaoer  
    OP
       2020-12-08 11:22:03 +08:00
    @echowuhao
    我们外部供应商给我们做外包,动不动就重构
    我自己写应用,有时候也动不动就重构
    但是自己挺反感重构的,怕缺陷。
    个人 觉得用 g 变量 和上下文是件很酷的事情
    不过还是谢谢,提供一个思路
    echowuhao
        8
    echowuhao  
       2020-12-08 11:24:21 +08:00
    @luxiaoer 你们单元测试咋写的。应该把每个函数的输入最小化,尽量减少 global,否则我不知道你们咋做测试的。
    no1xsyzy
        9
    no1xsyzy  
       2020-12-08 11:25:16 +08:00
    因为 flask 是用的 thread local
    g 和 request 信息限定在当前 thread 内有效。
    luxiaoer
        10
    luxiaoer  
    OP
       2020-12-08 11:26:12 +08:00
    @rimutuyuan
    copy 还是 参数传递 方式,就还是后续调整会觉得麻烦。
    我朝着这个方向也思考思考
    大家 都不用 g 和上下文么,不酷么
    luxiaoer
        11
    luxiaoer  
    OP
       2020-12-08 11:27:00 +08:00
    @no1xsyzy
    但是可以用上下文不是么。
    echowuhao
        12
    echowuhao  
       2020-12-08 11:31:18 +08:00
    celery 你可以理解为对当前程序任务的外包。

    外包的时候,你们会把现在公司的所有数据都送给他们,让他们方便么。只给最少能完成任务的信息。

    这个在原理上没有任何问题。外包的人说,把你们的数据都给我,多方便,你干么。
    luxiaoer
        13
    luxiaoer  
    OP
       2020-12-08 11:54:27 +08:00
    @echowuhao
    有道理,那我暂且去重构了
    仍然期待上下文的解决方案
    kaneg
        14
    kaneg  
       2020-12-08 12:13:44 +08:00 via iPhone
    flask 上下文只对当前线程有效,celery 是在新线程中异步执行,是无法获取当时 de 信息。
    你要做的时触发 job 时把当前需要传递的信息传给 celery 。
    luxiaoer
        15
    luxiaoer  
    OP
       2020-12-08 12:15:25 +08:00
    @kaneg
    感谢解惑
    no1xsyzy
        16
    no1xsyzy  
       2020-12-08 12:31:33 +08:00
    @luxiaoer app.app_context() 是建立了一个 dummy 上下文,里面就是些假数据。
    SjwNo1
        17
    SjwNo1  
       2020-12-08 13:32:42 +08:00
    flask 线程隔离的
    可以 app._get_current_object() 传给 task
    qdzzyb
        18
    qdzzyb  
       2020-12-08 14:07:17 +08:00
    flask 在一个进程里,celery 的 worker 在另外一个进程里
    celery worker 启动以后的 app 对象跟 flask 里的 app 对象不是同一个东西。

    3 楼已经的做法已经是最好的办法了, 后续添加新字段 worker 的处理函数还得处理

    实在想传 g 大概得用 pickle
    luxiaoer
        19
    luxiaoer  
    OP
       2020-12-08 15:30:05 +08:00
    @SjwNo1
    尝试过,没成功
    luxiaoer
        20
    luxiaoer  
    OP
       2020-12-08 15:30:38 +08:00
    @qdzzyb
    目前在这个方向努力
    luxiaoer
        21
    luxiaoer  
    OP
       2020-12-08 15:31:00 +08:00
    @no1xsyzy
    好的,谢谢
    nthhdy
        22
    nthhdy  
       2020-12-08 15:38:59 +08:00
    传 g 和 request 不合理,同意 @echowuhao 的方法
    Cookieeeeee
        23
    Cookieeeeee  
       2020-12-08 19:34:41 +08:00
    把具体的信息取出来 celery 里头上下文和 flask 里头不一样 传对象取不到值
    Cookieeeeee
        24
    Cookieeeeee  
       2020-12-08 19:35:36 +08:00
    或者序列化下传进去解耦
    goxy
        25
    goxy  
       2020-12-08 22:04:11 +08:00
    需要理解一下 context 的概念

    Celery 和 Flask 都是独立设计的,你可以理解为两个职业不同的人在一起协同工作,A 要分配任务给 B,是需要通过发一份邮件之类的东西给 B,而不是把 A B 缝起来让他们成为连体婴儿。g 和 request 都是设计在 flask 内部的,对于 celery 是透明的,而开发上要做的是设计这样一份 邮件
    cz5424
        26
    cz5424  
       2020-12-08 22:24:08 +08:00
    启动任务把参数传进去就好了,不要用全局,他们都是互相独立的进程
    cz5424
        27
    cz5424  
       2020-12-08 22:26:04 +08:00
    不要觉得 g 和上下文变量很酷,声明多了你都不知道声明了多少个全局变量。
    luxiaoer
        28
    luxiaoer  
    OP
       2020-12-10 10:16:49 +08:00
    感谢以上的提醒,已经用了 3 楼的思路重写中。
    重写一半又准备重写了,准备把日志记录功能拆解到 Celery 中做异步日志记录
    每次都不想重写,然鹅一次次重写
    @Cookieeeeee
    @goxy
    @cz5424
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     818 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 21:32 PVG 05:32 LAX 14:32 JFK 17:32
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86