Stop or Cancel button

Is there any mechanism is to cancel or stop a running process using a button? in my application, I want to start a process and then stop it using another button. I tried so many ways but couldn’t make it work.

import streamlit as st
import time
from SessionState import get
from multiprocessing import Process

st.sidebar.title("controls")
start = st.sidebar.button("start")
stop = st.sidebar.button("stop")


session_state = get(a=0)


def working():
    print("working started")
    session_state.a = 2
    for i in range(100):
        time.sleep(1)
        print(session_state.a)
        if session_state.a == 1:
            break

p = Process(target=working)
global pid
if start:
    print("start")
    p.start()
    pid = p.pid
    print("in start", pid)

if stop:
    print("stop")
    session_state.a = 1
    print("in stop", pid)

1 Like

Welcome to the forum, @rohola_zandie :wave:

I believe the code below does what you want:

from multiprocessing import Process
import streamlit as st
import SessionState
import time
import os
import signal

st.sidebar.title("Controls")
start = st.sidebar.button("Start")
stop = st.sidebar.button("Stop")

state = SessionState.get(pid=None)


def job():
    for _ in range(100):
        print("In progress")
        time.sleep(1)


if start:
    p = Process(target=job)
    p.start()
    state.pid = p.pid
    st.write("Started process with pid:", state.pid)

if stop:
    os.kill(state.pid, signal.SIGKILL)
    st.write("Stopped process with pid:", state.pid)
    state.pid = None

I’ve changed it a little bit, but the main idea is that you need to store the pid in the session state and only start a new process inside the start if condition.

Please let me know if you need any further clarification.

4 Likes

Thanks it’s working!

My pleasure!

1 Like

Hi,
This solution only works in linux but in windows I get this error.

ctx None
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "c:\users\mohsen\anaconda3\envs\tf_gpu\lib\multiprocessing\spawn.py", line 105, in spawn_main
exitcode = _main(fd)
  File "c:\users\mohsen\anaconda3\envs\tf_gpu\lib\multiprocessing\spawn.py", line 114, in _main
prepare(preparation_data)
  File "c:\users\mohsen\anaconda3\envs\tf_gpu\lib\multiprocessing\spawn.py", line 225, in prepare
_fixup_main_from_path(data['init_main_from_path'])
  File "c:\users\mohsen\anaconda3\envs\tf_gpu\lib\multiprocessing\spawn.py", line 277, in _fixup_main_from_path
run_name="mp_main")
  File "c:\users\mohsen\anaconda3\envs\tf_gpu\lib\runpy.py", line 263, in run_path
pkg_name=pkg_name, script_name=fname)
  File "c:\users\mohsen\anaconda3\envs\tf_gpu\lib\runpy.py", line 96, in _run_module_code
mod_name, mod_spec, pkg_name, script_name)
  File "c:\users\mohsen\anaconda3\envs\tf_gpu\lib\runpy.py", line 85, in _run_code
exec(code, run_globals)
  File "F:\codes\python\kiha_app\work_with_stop.py", line 15, in <module>
state = SessionState.get(pid=None)
  File "F:\codes\python\kiha_app\SessionState.py", line 69, in get
current_server = Server.get_current()
  File "c:\users\mohsen\anaconda3\envs\tf_gpu\lib\site-packages\streamlit\server\Server.py", line 165, in get_current
raise RuntimeError("Server has not been initialized yet")
RuntimeError: Server has not been initialized yet

You could solve that detecting the OS from platform and sending the correct signal but it’s easier with psutil:

from multiprocessing import Process
import streamlit as st
import SessionState
import time
import psutil

st.sidebar.title("Controls")
start = st.sidebar.button("Start")
stop = st.sidebar.button("Stop")

state = SessionState.get(pid=None)


def job():
    for _ in range(100):
        print("In progress")
        time.sleep(1)


if start:
    p = Process(target=job)
    p.start()
    state.pid = p.pid
    st.write("Started process with pid:", state.pid)

if stop:
    p = psutil.Process(state.pid)
    p.terminate()
    st.write("Stopped process with pid:", state.pid)
    state.pid = None
1 Like

@kantuni, thanks, your solution worked for me too.

But the snippet works perfectly when the start and stop are always used in pair and in the same sequence. If the start is pressed twice, it starts a new process and since the pid for the old process is no longer saved, it cannot be closed. Adding a flag to check process status before restarting a new process fixes this issue.

How did you add a flag to check the issue?

Note, there is now a st.stop function for stopping code upon some condition:

2 Likes