Quantcast
Channel: Active questions tagged javascript - Stack Overflow
Viewing all articles
Browse latest Browse all 140131

Selectively close individual child python processes, on demand, from jquery event

$
0
0

My problem is selectively and cleanly (or at all) stopping a child process, without terminating the main parent process, from a client side web browser jquery event. My example code is below. Flask is serving a simple web page with a button. When the button is pressed, a new python process is created, and data is acquired. However, when the button is pressed again (to stop data acquisition), I get UnboundLocalError: local variable 'acquire_process' referenced before assignment exception thrown. Moreover, when running the $ ps -ef | grep python command in another terminal, both the main process, and the created child process are still running until I throw a KeyboardInterrupt. However, this also kills the main parent process, which, in my actual project, needs to keep serving other content to the client.

My question is: What is the best way to selectively start and stop an individual child python process, on demand, from a client side jquery event?

#!/usr/bin/env python
#  -*- coding: utf-8 -*-

import time, os, random
import socket as sock
import psycopg2 as sql
import multiprocessing as mp
from flask_socketio import SocketIO, emit
from flask import Flask, render_template, url_for

from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT

app = Flask(__name__)
socket = SocketIO(app)

#Get the server's IP on which to serve app, client can navigate to IP
def get_ip_address():
    """ Utility function to get the IP address of the device. """
    ip_address = '127.0.0.1'  # Default to localhost
    s = sock.socket(sock.AF_INET, sock.SOCK_DGRAM)
    try:
        s.connect(('1.1.1.1', 1))  # Does not have to be reachable
        ip_address = s.getsockname()[0]
    finally:
        s.close()
    return ip_address

#create a table to store acquired data, erasing old data
def build_table():
    conn_main = sql.connect('dbname=mp_example user=pi')
    conn_main.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
    cm = conn_main.cursor()
    cm.execute('DROP TABLE IF EXISTS DAQ_example;')
    cm.execute('CREATE TABLE DAQ_example \
        (id SERIAL PRIMARY KEY,\
        ch0 VARCHAR,\
        ch1 VARCHAR,\
        ch2 VARCHAR,\
        ch3 VARCHAR);')
    cm.close()
    conn_main.close()
    print('table built')

#function run in the process for acquiring data
def acquire_data():
    print('acquire_data function called')
    conn_fill = sql.connect('dbname=mp_example user=pi')
    conn_fill.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
    cf = conn_fill.cursor()
    while True:
        ch0 = random.random()
        ch1 = random.random()
        ch2 = random.random()
        ch3 = random.random()
        cf.execute('INSERT INTO DAQ_example\
            (ch0, ch1, ch2, ch3)\
            VALUES (%s, %s, %s, %s);', (ch0, ch1, ch2, ch3))
        time.sleep(0.001)

#When client requests homepage
@app.route('/')
def render_index():
    #serve the html
    return render_template('index.html')

#Listen for client to start measurement    
@socket.on('control_measurement_process')
def start_process(state):
    #start a process to acquire data
    if state == True:
        build_table()
        acquire_process = mp.Process(target=acquire_data)
        acquire_process.start()
        print('acquire_process')
        print(os.system("ps -ef | grep python"))
    #attempt to clean up acquire_process
    elif state == False:
        print('terminate bool called')  
        acquire_process.terminate()
        print('acquire_process.terminate()')
        print(os.system("ps -ef | grep python"))

if __name__ == '__main__':
    print('main process')
    print(os.system("ps -ef | grep python"))
    #mp.set_start_method('spawn')
    socket.run(app, host=get_ip_address(), port=8080)

The 'index.html' is as follows:

<!DOCTYPE html>
<html>
<head>
    <link
        rel="stylesheet"
        href="{{ url_for('static', filename='css/style.css') }}">
    <link
        rel="stylesheet"
        href="{{ url_for('static', filename='bs/bootstrap-grid.css') }}">
    <script
        src="{{ url_for('static', filename='js/jquery-3.3.1.js') }}"></script>
    <script
        src="{{ url_for('static', filename='js/socket.io.js') }}"></script>
    <script
        src="{{ url_for('static', filename='js/bokeh-0.12.15.min.js') }}"></script>
</head>
<body>
    <div id="controls_title">
        Controls:
    </div>
    <div id="controls" class="row">
        <button id="measure" class="col-3">start<br>measurement</button>
    </div>

    <script>
    <!-- jQuery here -->

        var socket = 
            io.connect(location.origin, {transport: ['websocket']});
        var allow_measurement = true;

        //listens for client to start measurement acquisition
        $("#measure").on("click", function() {
            if ($("#measure").text() == "startmeasurement") {
                $("#measure").html("stop<br>measurement");
                allow_measurement = 1;
                socket.emit("control_measurement_process",
                            state=allow_measurement);
            }
            else {
                $("#measure").html("start<br>measurement");
                allow_measurement = 0;
                socket.emit("control_measurement_process",
                            state=allow_measurement);
            }
        });

    </script>
</body>
</html>

Viewing all articles
Browse latest Browse all 140131

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>