Python 在Flask应用程序中,后台线程记录到服务器发送的事件流
我正在尝试构建一个Flask应用程序,它在后台运行一些任务。此任务(工作人员)使用标准的Python 在Flask应用程序中,后台线程记录到服务器发送的事件流,python,multithreading,flask,gevent,Python,Multithreading,Flask,Gevent,我正在尝试构建一个Flask应用程序,它在后台运行一些任务。此任务(工作人员)使用标准的日志记录模块记录正在发生的事情。我想使用服务器发送的事件将日志消息直接推送到web浏览器,但我无法通过gevent广播它们 在下面的代码段中,正确启动了worker,SSEHandler.emit方法被调用,但是notify函数似乎在我执行gevent.spawn之后没有执行 main.py 问题是我用普通线程和睡眠代替了gevent。更改它和/或应用monkey补丁后,一切都很好。为什么使用线程.Threa
日志记录
模块记录正在发生的事情。我想使用服务器发送的事件将日志消息直接推送到web浏览器,但我无法通过gevent
广播它们
在下面的代码段中,正确启动了worker,SSEHandler.emit
方法被调用,但是notify
函数似乎在我执行gevent.spawn
之后没有执行
main.py
问题是我用普通线程和睡眠代替了gevent。更改它和/或应用monkey补丁后,一切都很好。为什么使用
线程.Thread
而不是gevent.spawn
?我按照您所说的更改了它,并用gevent.sleep
替换了time.sleep
,现在它可以工作了。然而,这种睡眠只是一种模拟,在真实的应用程序中,我与paramiko建立SSH连接,并使用sqlite数据库和sqlalchemy。我想如果我使用正确的补丁程序,它会起作用。如果你从gevent应用monkey补丁程序(patch\u all()
在所有导入之后),你可以使用time.sleep
)
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