我正在尝试构建一个在后台运行某些任务的Flask应用程序。此任务(工作人员)使用标准logging
模块记录正在进行的操作。我想使用服务器发送事件将日志消息直接推送到Web浏览器,但我无法通过gevent
广播它们。
在以下代码段中,工作人员已正确启动,SSEHandler.emit
方法被调用,但notify
函数似乎在执行gevent.spawn
之后无法执行
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()
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
答案 0 :(得分:0)
嗯,问题是我使用普通线程而不是gevent的东西睡觉。更换它和/或应用猴子补丁之后,一切都很完美。