Flask服务器事件在开发中起作用,但在生产中不起作用

时间:2019-04-03 19:29:36

标签: python python-3.x nginx flask gunicorn

我有一个Flask路由,该路由应该生成浏览器的服务器事件。该函数的基本作用是:  1.加载一个csv文件  2.对于csv文件的每一行  3.将用户名和电子邮件保存在sql数据库中(使用sqlalchemy)  4.更新计数器(用于进度状态)  5.将事件发送到浏览器

问题是,当我处于开发模式(使用flask内置服务器)时,该功能运行良好,但在生产模式(使用NginX和gunicorn)中,该功能在几秒钟后停止,因此计数器永远无法到达100,它将导致浏览器再次调用该函数,并且该循环永远不会结束,因为该事件永远不会获得close语句。所以主要的问题是,为什么它在开发中起作用而不在生产中起作用? 这是mi代码:

# Update or construct database if a csv file was submitted
@app.route("/constructDatabase/<string:filename>", methods=["GET","POST"])
def constructDatabase(filename):
    # context manager to open csv file
    csvFile = open(os.path.join(os.getcwd(), filename), newline='')
    # get lines count of csv file
    totalLines = len(csvFile.readlines())
    # reset reader pointer
    csvFile.seek(0)
    # current percent status
    current_status = 0
    def generate(file, counter):
        # unpack and iterate over the csv file to get all the names and emails
    for Company,Address,City,State,Zip,County,Phone,Website,Contact,Title,Direct_Phone,Email,Sales,Employees,SIC_Code,Industry in csv.reader(file, delimiter=','):
        yield ':keep connection alive\n\n'
        counter += 1
        # if a user has not contact name or email then not useful
        if Email == None or Email == '':
            yield f'id: {counter}\nevent: message\ndata: {round(counter / totalLines * 100, 1)}\n\n'
            continue
        if Contact == None or Contact == '':
            yield f'id: {counter}\nevent: message\ndata: {round(counter / totalLines * 100, 1)}\n\n'
            continue
        # Create user as instance of User class
        user = Users(company=Company, address=Address, city=City, state=State, 
        zip=Zip, country=County, phone=Phone, website=Website, contact=Contact, 
        title=Title, direct_phone = Direct_Phone, email=Email, sales=Sales, 
        employees=Employees, sic_code=SIC_Code, industry=Industry)
        # Add user to database
        db.session.add(user)
        # get current percent status of building database
        yield f'id: {counter}\nevent: message\ndata: {round(counter / totalLines * 100, 1)}\n\n'
    # Save changes in database
    db.session.commit()
    print("SAVING DATABASE .......")
    # close file
    file.close()
return Response(generate(csvFile, current_status), mimetype='text/event-stream')

现在的Java脚本代码:     javascript

// create Event source connection with the server to listen for incoming msg
var source = new EventSource(`/constructDatabase/${filename}`);
// if new msg was received
source.onmessage = function(msg) {
// update progress bar
$('.progress-bar').css('width', msg.data+'%').attr('aria-valuenow', msg.data);  
// if is 100 percent close connection to the server
if (msg.data == 100) {
    source.close();
    // Hide label
    $('.prog-bar-label').addClass('d-none');
    // Hide CSV progress bar
    $('.csvProgressBar').addClass('d-none');
    // reset progress bar
    $('.csvProgressBar').find('.progress-bar').css('width', 0+'%').attr('aria-valuenow', 0);
           } 
     };
     source.onerror = function(error){
           console.log(error.data);
     };

1 个答案:

答案 0 :(得分:0)

我弄清楚这里发生了什么。事实是,flask开发人员服务器在运行时没有声明任何超时,因此函数可以等待很长一段时间的响应。但是在带有gunicorn的生产服务器中,它的默认超时时间非常短,因此,如果某个函数花很长时间才能获得响应并达到超时时间,则gunicorn会杀死该进程并退出该函数,因此浏览器端的流传输进程,认为那是服务器中的错误,而这实际上只是一个延迟的功能。解决方案是使用--timeout(此处为所需的超时值)来增加gunicorn中的超时,这样会很好。不要使用非常大的超时值,只需尝试弄清楚函数获取响应并使用该值需要多长时间。请记住,现在所有函数的该值都将相同。