现状: 原钉钉发送消息是同步程序,发送钉钉消息程序中有记录 Flask 程序运行日志,日志包含当前请求用户信息,和请求参数信息。
# __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
1
coolair 2020-12-08 10:28:53 +08:00
with app.app_context():
# ... |
2
luxiaoer OP @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 |
3
echowuhao 2020-12-08 10:51:21 +08:00 via Android
你应该换方式 把需要得信息在 context 里面提取出来 传给 celery 而不是在 celery 中获取
|
4
luxiaoer OP @echowuhao
可以是可以,但是这种方式不够解藕 如果后续需要添加新的字段,就需要整个调整。 关键是,原来的 run_log 就需要重写,就不能用 g 和 request 。相关的调用程序也需要重写吧 |
5
rimutuyuan 2020-12-08 11:06:54 +08:00
copy.deepcopy 可以实现么
|
6
echowuhao 2020-12-08 11:14:39 +08:00 via Android
@luxiaoer 代码要尽量少用 global 的东西 refactor 你的代码 object 进入 celery 都要序列化一个来回 费时费力
|
7
luxiaoer OP @echowuhao
我们外部供应商给我们做外包,动不动就重构 我自己写应用,有时候也动不动就重构 但是自己挺反感重构的,怕缺陷。 个人 觉得用 g 变量 和上下文是件很酷的事情 😂 不过还是谢谢,提供一个思路 |
9
no1xsyzy 2020-12-08 11:25:16 +08:00
因为 flask 是用的 thread local
g 和 request 信息限定在当前 thread 内有效。 |
10
luxiaoer OP |
12
echowuhao 2020-12-08 11:31:18 +08:00
celery 你可以理解为对当前程序任务的外包。
外包的时候,你们会把现在公司的所有数据都送给他们,让他们方便么。只给最少能完成任务的信息。 这个在原理上没有任何问题。外包的人说,把你们的数据都给我,多方便,你干么。 |
14
kaneg 2020-12-08 12:13:44 +08:00 via iPhone
flask 上下文只对当前线程有效,celery 是在新线程中异步执行,是无法获取当时 de 信息。
你要做的时触发 job 时把当前需要传递的信息传给 celery 。 |
17
SjwNo1 2020-12-08 13:32:42 +08:00
flask 线程隔离的
可以 app._get_current_object() 传给 task |
18
qdzzyb 2020-12-08 14:07:17 +08:00
flask 在一个进程里,celery 的 worker 在另外一个进程里
celery worker 启动以后的 app 对象跟 flask 里的 app 对象不是同一个东西。 3 楼已经的做法已经是最好的办法了, 后续添加新字段 worker 的处理函数还得处理 实在想传 g 大概得用 pickle |
23
Cookieeeeee 2020-12-08 19:34:41 +08:00
把具体的信息取出来 celery 里头上下文和 flask 里头不一样 传对象取不到值
|
24
Cookieeeeee 2020-12-08 19:35:36 +08:00
或者序列化下传进去解耦
|
25
goxy 2020-12-08 22:04:11 +08:00
需要理解一下 context 的概念
Celery 和 Flask 都是独立设计的,你可以理解为两个职业不同的人在一起协同工作,A 要分配任务给 B,是需要通过发一份邮件之类的东西给 B,而不是把 A B 缝起来让他们成为连体婴儿。g 和 request 都是设计在 flask 内部的,对于 celery 是透明的,而开发上要做的是设计这样一份 邮件 |
26
cz5424 2020-12-08 22:24:08 +08:00
启动任务把参数传进去就好了,不要用全局,他们都是互相独立的进程
|
27
cz5424 2020-12-08 22:26:04 +08:00
不要觉得 g 和上下文变量很酷,声明多了你都不知道声明了多少个全局变量。
|
28
luxiaoer OP 感谢以上的提醒,已经用了 3 楼的思路重写中。
重写一半又准备重写了,准备把日志记录功能拆解到 Celery 中做异步日志记录😂 每次都不想重写,然鹅一次次重写 @Cookieeeeee @goxy @cz5424 |