Creating stock price monitor

  1. I run the app locally
    streamlit version: 1.29.0
    python version 3.11.4

I am trying to do the following simple app:
I connect to a broker api to get prices; i receive those prices in a separate thread in that brokers api library implementation. When this happens i want to trigger a script rerun so that the GUI updates

To simulate it I’m using this code:

import streamlit as st
import threading
import time
from streamlit.runtime.scriptrunner import add_script_run_ctx

print('streamlit_thread({}): =====> script run started'.format(threading. get_ident()))

class Data:
    lock_last_price = threading.Lock()
    last_price = 0

@st.cache_resource
def get_storage():
    return Data()

def generate_last_price():
    while(True):
        with get_storage().lock_last_price:
            get_storage().last_price += 1
            print('background_thread({}): last_price {}'.format(threading. get_ident(), get_storage().last_price))
        print('background_thread({}) sleep 1 sec'.format(threading.get_ident()))
        time.sleep(1)
        st.rerun()

@st.cache_resource
def start_singleton():
    print('streamlit_thread({}): -----> start_singleton only once'.format(threading. get_ident()))
    t = threading.Thread(target=generate_last_price, daemon=True)
    add_script_run_ctx(t)
    t.start()
    print('streamlit_thread({}): <----- start_singleton only once'.format(threading. get_ident()))

start_singleton()

streamlit_last_price = 0
with get_storage().lock_last_price:
    streamlit_last_price = get_storage().last_price

print('streamlit_thread({}): last_price {}'.format(threading. get_ident(), streamlit_last_price))
st.text(streamlit_last_price)

print('streamlit_thread({}): <===== script run finished'.format(threading. get_ident()))

Sample run:

streamlit_thread(17612): =====> script run started
streamlit_thread(5964): =====> script run started
streamlit_thread(5964): -----> start_singleton only once
streamlit_thread(5964): <----- start_singleton only once
background_thread(48768): last_price 1
background_thread(48768) sleep 1 sec
streamlit_thread(5964): last_price 1
streamlit_thread(37096): =====> script run started
streamlit_thread(5964): <===== script run finished
streamlit_thread(37096): last_price 1
streamlit_thread(37096): <===== script run finished
streamlit_thread(17612): last_price 1
streamlit_thread(17612): <===== script run finished
streamlit_thread(35928): =====> script run started
streamlit_thread(35928): last_price 1
streamlit_thread(35928): <===== script run finished
background_thread(48768): last_price 2
background_thread(48768) sleep 1 sec
background_thread(48768): last_price 3
background_thread(48768) sleep 1 sec
background_thread(48768): last_price 4
background_thread(48768) sleep 1 sec
background_thread(48768): last_price 5
background_thread(48768) sleep 1 sec
background_thread(48768): last_price 6
background_thread(48768) sleep 1 sec
background_thread(48768): last_price 7
background_thread(48768) sleep 1 sec
streamlit_thread(1224): =====> script run started
streamlit_thread(1224): last_price 7
streamlit_thread(1224): <===== script run finished
streamlit_thread(53844): =====> script run started
streamlit_thread(53844): last_price 7
streamlit_thread(53844): <===== script run finished
background_thread(48768): last_price 8
background_thread(48768) sleep 1 sec
background_thread(48768): last_price 9

The problem I get is that the script rerun does not get triggered from the background thread. The UI does not update and in the st.text value i see an old value (not synced with background_thread)

Any help on this? I can’t find where the bug is. Or if you have any other architecture changes/suggestions on what might be wrong?

Is this helpful? It auto refreshes or reruns the app from the front end every nth time (you set this) or forever (you set this too). An example of its implementation is here

1 Like

Thank you for the help. It’s not exactly what i had in mind but it’s good enough for what i want to achieve.
I’ve tested it and it works as expected. The only part that i don’t know how to address yet is how to properly clean up when the server stops(i press ctrl+c)
i must call disconnect api from brokers library, just don’t know where exactly. some at_exit or on_close functions to trigger an @st.cache_resource cleanup would be useful

If there is an indicator to signal the server has stopped providing data? If so, you could use session state to halt it like this:

import streamlit as st
from streamlit_autorefresh import st_autorefresh

if "stop_stream" not in st.session_state:
   st.session_state["stop_stream"] = False

if "count" not in st.session_state:
   st.session_state["count"] = 0

st.session_state["stop_stream"]  == False:
   st.session_state["count"]  = st_autorefresh(interval=2000, limit=None, key="fizzbuzzcounter")

# if data stops streaming:
   st.session_state["stop_stream"] = True

It wont refresh now

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.