后台线程记录到Flask应用程序中的Server Sent Event流(Background thread logging to a Server Sent Event stream in a Fl

编程入门 行业动态 更新时间:2024-10-24 06:28:12
后台线程记录到Flask应用程序中的Server Sent Event流(Background thread logging to a Server Sent Event stream in a Flask app)

我正在尝试构建一个Flask应用程序,它在后台运行一些任务。 此任务(工作人员)使用标准logging模块记录正在进行的操作。 我想使用Server Sent Events将日志消息直接推送到Web浏览器,但我无法通过gevent广播gevent 。

在下面的代码片段中,worker正确启动, SSEHandler.emit方法被调用,但是在执行gevent.spawn后似乎没有执行notify函数。

main.py

import gevent from gevent.wsgi import WSGIServer from gevent.queue import Queue from flask import Flask, Response import time import logging import threading from worker import Worker class SSEHandler(logging.Handler): def __init__(self): logging.Handler.__init__(self) self.subscriptions = [] def emit(self, record): try: msg = self.format(record) print "sending", msg def notify(subs, msg): print "broadcasting!" for sub in subs[:]: sub.put(msg) gevent.spawn(notify, self.subscriptions, msg) except (KeyboardInterrupt, SystemExit): raise except: self.handleError(record) def subscribe(self): print "subscribed" q = Queue() self.subscriptions.append(q) try: while True: result = q.get() yield "data: %s\n\n"%result except GeneratorExit: # Or maybe use flask signals subscriptions.remove(q) app = Flask(__name__) handler = SSEHandler() handler.setLevel(logging.DEBUG) worker = None # Client code consumes like this. @app.route("/") def index(): debug_template = """ <html> <head> </head> <body> <h1>Server sent events</h1> <div id="event"></div> <script type="text/javascript"> var eventOutputContainer = document.getElementById("event"); var evtSrc = new EventSource("/subscribe"); evtSrc.onmessage = function(e) { console.log(e.data); eventOutputContainer.innerHTML = e.data; }; </script> </body> </html> """ return(debug_template) @app.route("/subscribe") def subscribe(): return Response(handler.subscribe(), mimetype="text/event-stream") @app.route("/start") def start(): def run(): global worker global handler worker = Worker(handler) worker.go() threading.Thread(target=run).start() return "Going" if __name__ == "__main__": app.debug = True server = WSGIServer(("", 5000), app) server.serve_forever()

worker.py

import logging import time class Worker: def __init__(self, handler): self.log = logging.getLogger('sselog.worker.Worker') self.log.setLevel(logging.DEBUG) self.log.addHandler(handler) self.log.info("Initialized") def go(self): i = 0 while True: time.sleep(1) self.log.info("I'm working so hard %u", i) i+=1

I'm trying to build a Flask application that has some task running in the background. This task (a worker) uses standard logging module for logging what is going on. I would like to use Server Sent Events to push the log messages directly to the web browser, but I can't get them broadcasted by gevent.

In the following snippet the worker is launched properly, SSEHandler.emit method is called as it should, but the notify function doesn't seem to be executed after I do gevent.spawn.

main.py

import gevent from gevent.wsgi import WSGIServer from gevent.queue import Queue from flask import Flask, Response import time import logging import threading from worker import Worker class SSEHandler(logging.Handler): def __init__(self): logging.Handler.__init__(self) self.subscriptions = [] def emit(self, record): try: msg = self.format(record) print "sending", msg def notify(subs, msg): print "broadcasting!" for sub in subs[:]: sub.put(msg) gevent.spawn(notify, self.subscriptions, msg) except (KeyboardInterrupt, SystemExit): raise except: self.handleError(record) def subscribe(self): print "subscribed" q = Queue() self.subscriptions.append(q) try: while True: result = q.get() yield "data: %s\n\n"%result except GeneratorExit: # Or maybe use flask signals subscriptions.remove(q) app = Flask(__name__) handler = SSEHandler() handler.setLevel(logging.DEBUG) worker = None # Client code consumes like this. @app.route("/") def index(): debug_template = """ <html> <head> </head> <body> <h1>Server sent events</h1> <div id="event"></div> <script type="text/javascript"> var eventOutputContainer = document.getElementById("event"); var evtSrc = new EventSource("/subscribe"); evtSrc.onmessage = function(e) { console.log(e.data); eventOutputContainer.innerHTML = e.data; }; </script> </body> </html> """ return(debug_template) @app.route("/subscribe") def subscribe(): return Response(handler.subscribe(), mimetype="text/event-stream") @app.route("/start") def start(): def run(): global worker global handler worker = Worker(handler) worker.go() threading.Thread(target=run).start() return "Going" if __name__ == "__main__": app.debug = True server = WSGIServer(("", 5000), app) server.serve_forever()

worker.py

import logging import time class Worker: def __init__(self, handler): self.log = logging.getLogger('sselog.worker.Worker') self.log.setLevel(logging.DEBUG) self.log.addHandler(handler) self.log.info("Initialized") def go(self): i = 0 while True: time.sleep(1) self.log.info("I'm working so hard %u", i) i+=1

最满意答案

好吧,问题是我使用普通线程而不是gevent的东西睡觉。 更换它和/或应用猴子补丁后,一切都很完美。

Well, the problem was that I used plain threads and sleep instead of the gevent stuff. After changing it and/or applying a monkey patch, everything works perfectly.

更多推荐

本文发布于:2023-08-07 06:45:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1463136.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:线程   应用程序   后台   Server   Event

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!