Flask应用程序将多个日志流式传输到多个客户端

时间:2017-11-15 22:12:06

标签: flask web-applications server-sent-events eventlet eventsource

我编写了一个小型Flask应用,可通过互联网将多个日志文件流式传输到浏览器。

import json
import os
import re
import flask
from shelljob import proc

import eventlet
eventlet.sleep()
eventlet.monkey_patch()

app = flask.Flask(__name__)

@app.route( '/stream/<string:case_name>/<string:wind_dir>' )
def stream(case_name, wind_dir):
    g = proc.Group()
    foamrun = os.environ["FOAM_RUN"]
    foamcase = os.path.join(foamrun, case_name, wind_dir)
    log_file = os.path.join(foamcase, 'logs', 'run.log')
    print log_file
    p = g.run( [ "tail", "-f", log_file ] )
    def read_process():
        while g.is_pending():
            lines = g.readlines()
            for proc, line in lines:
                # process line and create payload
                yield "data:" + json.dumps(payload) + "\n\n"

    return flask.Response( read_process(), mimetype='text/event-stream' )

@app.after_request
def after_request(response):
  response.headers.add('Access-Control-Allow-Origin', '*')
  response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
  response.headers.add('Access-Control-Allow-Methods', 'GET')
  return response

if __name__ == "__main__":
    foamrun = os.environ["FOAM_RUN"]
    app.run(threaded=True, host='0.0.0.0', port=9001)

我用gunicorn使用命令

运行此应用程序
gunicorn server:app -k eventlet -b 0.0.0.0:9001

当我打开两个链接时:

http://X.X.X.X:9001/stream/test01_base_Baseline/NW
http://X.X.X.X:9001/stream/test01_base_Baseline/N

我有一种奇怪的行为。两个流中的一个按预期工作,但第二个流挂起或以批量传输。例如,在第一页上我每秒接收一行,而在第二页上我每20秒左右收到大约15-20行。行为也不一致。有时它是第一个挂起的页面,第二个页面经常出现。

我对网络开发很陌生。

修改

我尝试用更简单的版本替换read_process

def read_process():
    i = 1
    while True:
       payload = 'line' + str(i)
       i += 1
       yield "data:" + json.dumps(payload) + "\n\n"
       sleep(1)

此版本具有相同的问题并且行为与我预期的一样。两个流一起收到。

1 个答案:

答案 0 :(得分:0)

g.readlines()进程提供更多数据之前,tail阻止发生了什么。不幸的是,它阻止了整个程序,而不是一个绿色线程。

应该可以在没有eventlet.tpool.Proxy(open(log_file, 'rb'))进程的情况下使用tail

如果失败,现在的下一个最佳选择是在单独的OS线程中进行文件操作,并通过全局变量传递数据,并通过本地套接字同步对所述变量的访问。我知道这是蹩脚的,因为它重复了shelljob的一半代码和eventlet.tpool的另一半代码。抱歉,我们在tpool中有一个错误,可以防止更简单的解决方案。