Python 3.x Flask SocketIO-如何从子进程发出事件
我有一个Flask应用程序,它在某些rest调用时使用ProcessPoolExecutor运行几个模块 更新:添加redis作为消息队列(使用docker,redis作为redis的主机) 现在我添加了redis,它在从主应用程序发射时仍然可以工作。 下面是我正在运行的子进程中的一些代码:Python 3.x Flask SocketIO-如何从子进程发出事件,python-3.x,flask,socket.io,flask-socketio,Python 3.x,Flask,Socket.io,Flask Socketio,我有一个Flask应用程序,它在某些rest调用时使用ProcessPoolExecutor运行几个模块 更新:添加redis作为消息队列(使用docker,redis作为redis的主机) 现在我添加了redis,它在从主应用程序发射时仍然可以工作。 下面是我正在运行的子进程中的一些代码: def __init__(self): self.executor = futures.ProcessPoolExecutor(max_workers=4) self.socketio =
def __init__(self):
self.executor = futures.ProcessPoolExecutor(max_workers=4)
self.socketio = SocketIO(async_mode='eventlet', message_queue='redis://redis')
(...)
future = self.executor.submit(process, params)
future.add_done_callback(functools.partial(self.finished_callback, pid))
然后在该回调中,我调用emit\u事件
方法:
def finished_callback(self, pid, future):
pid.status = Status.DONE.value
pid.finished_at = datetime.datetime.utcnow
pid.save()
self.socketio.emit('update_reports', 'done', namespace='/test')
从我的控制器从/向客户端获取和发送/发送消息工作正常,如果我从curl或postman调用/info,我的客户端也会收到消息-但是-当尝试从这个子流程回调中以相同的方式发送事件时,现在它会显示以下错误:
这主要是用于通知,比如当一个长过程完成时通知等等
INFO:socketio:向所有[/test]发送事件“更新报告”
错误:socketio:无法发布到redis。。。重试
错误:socketio:无法发布到redis。。。放弃
我做错了什么
谢谢 在设置Flask SocketIO扩展时,您需要遵循一些特定规则,以便外部进程可以发出消息,其中包括使用主进程和外部进程用来协调工作的消息队列。有关说明,请参阅文档的部分。能否添加用于从子流程发出的代码?您还提到了
/info
路线,但您的示例中有/test
。我假设这就是您从curl调用的路由?感谢您的回复,Miguel,在子流程中,我只是从它所在的主py文件导入emit\u event
方法,并以与我在该/test
调用中相同的方式使用它。是的,这就是我正在调用的url。结果是,从子进程中,事件/消息永远不会到达(控制台中没有错误)@Miguel我刚刚添加了一些代码,请告诉我您的想法谢谢您的回答。我刚刚试着从我的子进程运行那里写的东西,但是这是我在日志中得到的无法发布到redis。。。重试,放弃
我刚刚用更多细节和代码更新了问题。看来您的子进程没有连接到Redis。您可以尝试编写一个简单的脚本来连接到消息队列并发出消息吗?如果这样做有效,那么您必须找出您的子进程中有什么影响到与redis的连接。子进程不需要使用eventlet,只有主进程才需要。您在子流程中所做的事情似乎与eventlet不兼容,所以最好不要在那里使用它。您可以通过在SocketIO
类构造函数中传递async\u mode='threading'
并删除所有monkey补丁来强制Socket.IO不使用eventlet。然后您可以单独启动子进程吗?我自己并没有真正和执行者合作过,我更喜欢把事情分开,自己启动每个服务。如果您正在寻找我见过的成功使用的替代方案,芹菜和RedisQueue都很好,但我坚持认为您必须确保这些工作进程不使用eventlet,因为您似乎正在使用eventlet不支持的函数。
def finished_callback(self, pid, future):
pid.status = Status.DONE.value
pid.finished_at = datetime.datetime.utcnow
pid.save()
self.socketio.emit('update_reports', 'done', namespace='/test')