烧瓶有状态后端:任务完成后从一个状态跳到另一个状态

时间:2019-02-12 23:21:43

标签: flask flask-socketio stateful

我正在尝试在flask中编写一个后端,该后端必须对外部计算机(check1,check2等)执行许多检查。这是一个顺序过程(检查n之后,我们检查n + 1),但是它需要存储“当前状态”。例如,check1包含从外部API轮询资源(每秒卷曲),该API返回计算机的某些日志。

每当后端在检索到的日志中找到“某些字符串”时,后端就必须更新后端的全局状态,将其报告给前端(以刷新布局组件)并跳至下一个状态。

同样,在下一个状态中,后端正在检查其他内容,当找到“另一个字符串”时,更新全局状态,通知前端新状态并跳至下一个状态。

以此类推,这是核心思想。

它只有一条路线(/)。

该Webapp并非用于生产,仅需工作即可,其目的只是演示系统的发展方式(监视示例)。必须广播全局状态,以便任何人去路由/将看到当前状态布局。

我是Web开发的新手,我认为这是一个奇怪的应用程序,没有我想的那么琐碎。

下面,我显示一些代码,表示:

状态0:通过套接字将新状态(数据)传达给前端。不执行任何操作,仅在开始按钮中等待onClick事件。发生这种情况时,跳到状态1。

状态1:通过socketio将新状态(数据)传达到前端。然后,执行一些任务。当任务“成功”将跳到下一个状态2。

无论状态如何,用户都可以在Web UI中更改参数(参数)。我通过底部的socketio条目进行处理。

main.py

from flask import Flask, render_template
from flask_socketio import SocketIO, emit
import time, json

global data
data = {'state': '0', 'param': '50', 'disableStart': 'false', 'disableReset': 'true', 'info': 'Waiting to start'}

def state_1():
    print("[Server.state_1]: In state 1...checking service")
    data['state'] = '1'
    data['disableStart'] = 'true'
    data['disableReset'] = 'true'
    data['info'] = 'Waiting for service is OK'
    socketio.emit('refresh', json.dumps(data), broadcast=True)
    # Checking if service is OK...
    # Below is just a dummy sustitute
    counter = 0
    while counter < 100:
        print("Checking..." + str(counter) + "%")  
        time.sleep(1) 
        counter += 1
    # When service is OK jump to state_2()  


def state_0():
    print("[Server.state_0]: In state 0...waiting to start...")
    data['state'] = '0'
    data['info'] = 'Waiting to start'
    socketio.emit('refresh', json.dumps(data), broadcast=True)

# initialize Flask
app = Flask(__name__)
socketio = SocketIO(app)

@app.route('/')
def index():   
    print("[Server.index]: "  + json.dumps(data))   
    return render_template('index.html') 

@socketio.on('connect')
def on_connect():
    print("[Server.on_connect]: A new connection!")
    print("[Server.on_connect]: " + json.dumps(data))
    # In every new refresh or new tab, we need to display current state
    emit('refresh', json.dumps(data), broadcast=True)
    # Jump to current state
    print("[Server.on_connect]: Jump to state " + data['state'])
    f_name = "state_" + data['state']
    globals()[f_name]()

@socketio.on('start')
def on_start():
    print("[Server.on_start]: Clicked on START button! Jump to state 1")
    state_1()

@socketio.on('update_slide_param')
def on_update_slide_param(paramVal):
    data['param'] = paramVal
    # Setting this param to an external machine...
    print("[Server.on_update_slide_param]: A new value has been set! Jump to state " + data['state'])
    f_name = "state_" + data['state']
    globals()[f_name]()

if __name__ == '__main__':
    socketio.run(app, debug=True)

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Flask SocketIO Test</title>
</head>

<body>
    <p>Some sample code to make sure Flask-SocketIO works...</p>
    <button onclick="onClickStart()" id="startButton">START</button>
    <button onclick="onClickReset()" id="resetButton">RESET</button>
    <input onchange="onSetSliderVal()" class="slider" type="range" id="idSlider" min="50" max="300" value="50"/>
    <p>Value: <span id="idSliderVal"></span></p>


    <script type="text/javascript" charset="utf-8">
        var slider = document.getElementById("idSlider");
        var output = document.getElementById("idSliderVal");
        output.innerHTML = slider.value; // Display the default slider value

        // Update the current slider value (each time you drag the slider handle)
        slider.oninput = function () {
            output.innerHTML = this.value;
        }
    </script>


    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>

    <script type="text/javascript" charset="utf-8">

        var socket = io.connect('http://' + document.domain + ':' + location.port);
        // verify our websocket connection is established
        socket.on('connect', function () {
            console.log('Websocket connected!');
        });

        // onClickStart - emit a message on the 'start' channel to 
        // launch a new demo with default parameters
        function onClickStart() {
            console.log('Starting demo...');
            socket.emit('start');
        };

        // onSetSliderVal - emit a message on the 'update_slide_param' channel to 
        // perform the action and update global 'data'
        function onSetSliderVal() {
            var paramVal = document.getElementById('idSlider').value;
            console.log('Setting a value of ' + paramVal + '...');
            socket.emit('update_slide_param', paramVal);
        };

        socket.on('refresh', function (data) {
            var x = JSON.parse(data); // This is the way we can use our dictionary 'data' as a JSON in JS
            console.log('[refresh] Frontend has updated info! Now we are in state ' + x.state);
            console.log('[refresh] All variables are:'); console.log(x);

            document.getElementById('idSlider').value = x.param;
            document.getElementById("idSliderVal").innerHTML = x.param;
            document.getElementById('startButton').disabled = JSON.parse(x.disableStart); // This is the cleanest way JS converts a "true"/"false" (string) into true/false (boolean)
            document.getElementById('resetButton').disabled = JSON.parse(x.disableReset);

        });

    </script>

</body>

</html>

问题:

如果我在状态0期间刷新,则可以正常工作。在此状态下,我可以更改“参数”,并且在每个打开的浏览器选项卡中都会更新信息。如果我刷新,则更新的“参数”将保持不变。

然后,我按开始按钮,一切都很好(前端状态根据需要进行了更新)。但是,如果刷新选项卡,则会发生两件事:

a。在浏览器开发工具中,套接字中的控制台信息消失了。

b。服务器中的state_1()函数将再次执行,服务器日志中将显示以下内容:

检查中... 2% 检查中... 16% 检查中... 3% 检查中... 17% 正在检查... 4%

...

当然,似乎执行了该函数的新“实例”。

总而言之,很高兴收到一些反馈。您可以使用提供的代码快速测试问题(创建venv,pip3安装flask flask-socketio,创建index.html的模板文件夹,然后仅创建“ python3 main.py”)

0 个答案:

没有答案