How can I stop excessive inputs that crash the application

I’m creating a calculator of sorts to make a prediction, the user is prompted for some data and an output is created using their model of choice, such as random forests, LightGBM, etc. However, when deployed to Streamlit cloud, there’s nothing stopping anyone from mashing inputs and the calculate button to create too many calculations going at once, and the application crashes due to memory overflow, and the developer has to login to manually reboot it. It’s not the case on just my application as well, I was able to go click an app on the front page of the gallery and crash it by mashing inputs on my keyboard.

So my question is, how can I limit inputs on my application, or prevent too many calculations from running at once. I’m not able to replicate this in a local environment bc there’s no memory constraint. I’m supposed to be deploying this application as an assignment for a class, however, there’s nothing stopping any user from crashing my app and then my professor just opens a dead link when he goes to grade it.

Hi there! It sounds like you’re running into a common challenge with resource-intensive Streamlit apps, especially in shared environments like Streamlit Cloud. There are several strategies you can explore to address this, such as using caching to reuse results and limit redundant calculations, adding debouncing or rate-limiting to control how often users can trigger actions, and managing concurrency with Streamlit’s session state to prevent overlapping processes. If you’d like, feel free to share your app code or a simplified version, and we’d be happy to provide more tailored guidance!

Here’s what my code currently looks like so far

if tab == "Lift Prediction Calculator":
    st.subheader("Predict Your Missing Lift")
    st.write("""
    Use this calculator to predict one of your lifts (Squat, Bench, or Deadlift) based on your body weight, sex, and the other two lifts. This can be useful if you want to predict where you should be on a lift, or to identify which of your lifts is the weakest.
    """)

    # Prepare data for training
    df_data = df_new_powerlift[['Best3SquatKg', 'Best3BenchKg', 'Best3DeadliftKg', 'BodyweightKg', 'Sex_Encoded']].dropna()

    # Split data into predictors and target
    def data_split(target):
        X = df_data.drop(columns=[target])
        y = df_data[target]
        return X, y

    # Dropdown to select the model type
    model_type = st.selectbox("Select the model type:", ["LightGBM", "MLP", "Random Forest", "KNN"])

    # Create models for the lift based on the model
    models = {}
    for target in ['Best3SquatKg', 'Best3BenchKg', 'Best3DeadliftKg']:
        X, y = data_split(target)
        if model_type == "LightGBM":
            model = LGBMRegressor(n_estimators=100, learning_rate=0.1)
        elif model_type == "MLP":
            model = MLPRegressor(hidden_layer_sizes=(100,), max_iter=500)
        elif model_type == "Random Forest":
            model = RandomForestRegressor(n_estimators=100)
        elif model_type == "KNN":
            model = KNeighborsRegressor(n_neighbors=5)

        model.fit(X, y)
        models[target] = model

    # Form for user input
    with st.form(key="lift_prediction_form"):
        input_lift = st.selectbox("Which lift do you want to predict?", ["Squat", "Bench", "Deadlift"])
        bodyweight = st.number_input("Enter your body weight (kg):", min_value=20.0, max_value=200.0, step=0.1)
        sex = st.selectbox("Select your sex:", ["Male", "Female"])
        sex_encoded = 0 if sex == "Male" else 1

        if input_lift == "Squat":
            bench = st.number_input("Enter your Bench (kg):", min_value=20.0, max_value=600.0, step=0.1, key="bench_input")
            deadlift = st.number_input("Enter your Deadlift (kg):", min_value=20.0, max_value=600.0, step=0.1, key="deadlift_input")
        elif input_lift == "Bench":
            squat = st.number_input("Enter your Squat (kg):", min_value=20.0, max_value=600.0, step=0.1, key="squat_input")
            deadlift = st.number_input("Enter your Deadlift (kg):", min_value=20.0, max_value=600.0, step=0.1, key="deadlift_input")
        elif input_lift == "Deadlift":
            squat = st.number_input("Enter your Squat (kg):", min_value=20.0, max_value=600.0, step=0.1, key="squat_input")
            bench = st.number_input("Enter your Bench (kg):", min_value=20.0, max_value=600.0, step=0.1, key="bench_input")

        # Submit button
        submit = st.form_submit_button(label="Predict")

    # Perform prediction only after the form is submitted
    if submit:
        if input_lift == "Squat":
            predicted_value = models['Best3SquatKg'].predict([[bench, deadlift, bodyweight, sex_encoded]])[0]
            st.write("Predicted Squat:", round(predicted_value, 2), "kg")
        elif input_lift == "Bench":
            predicted_value = models['Best3BenchKg'].predict([[squat, deadlift, bodyweight, sex_encoded]])[0]
            st.write("Predicted Bench:", round(predicted_value, 2), "kg")
        elif input_lift == "Deadlift":
            predicted_value = models['Best3DeadliftKg'].predict([[squat, bench, bodyweight, sex_encoded]])[0]
            st.write("Predicted Deadlift:", round(predicted_value, 2), "kg")`Preformatted text`

I am unable to reproduce the issue with that code. Of course I have neither your data nor the rest of your code, and that may make a difference.

The error can only be replicated when deployed to Streamlit cloud, as that’s where the memory constraints are. The data size probably makes a difference, my data set is 10,000 points, but the error can be replicated by simply inputting as fast as possible. For example, clicking in a box, and repeatedly alternating between the “9” key and the “enter” button on the keyboard will stack inputs until the application crashes. This can also be done on any application where the user can change inputs faster than the application can calculate it. I was able to replicate this with an application on the front page that featured some sliders, and I just clicked through the sliders quickly for about 30 seconds, and the application crashed. I’m wondering what I can do to debounce those inputs if possible, but every debouncing method I have tried involves the code fully calculating, and does not work if inputs are spammed.