我正在尝试构建一个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+=1I'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.
更多推荐
发布评论