后台线程记录到Flask应用程序中的Server Sent Event流

时间:2014-07-22 16:08:16

标签: python multithreading flask gevent

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

在以下代码段中,工作人员已正确启动,SSEHandler.emit方法被调用,但notify函数似乎在执行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

1 个答案:

答案 0 :(得分:0)

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

相关问题