Two people on same session state

Hi, everyone.

When I’m using an application with session state locally, I can use the same application, on two different windows with two different session states.

But when I put the application on cloud, my workmate and I are having the same session state.

Anyone had this problem on production? Or have an idea to work on a stateless application?

P.S. about the application:
It’s an annotator tool. We receive messages from AWS SQS, annotate, and save on AWS RDS database.
We needed to use SessionState to persist the message from SQS after a button click.
Our reference about SessionState: https://gist.github.com/tvst/036da038ab3e999a64497f42de966a92

1 Like

Thanks for posting @dcpadilha, this is definitely an interesting question. I’ll try to find an engineer who can help walk through this with you, as nothing immediately comes to mind.

Best,
Randy

1 Like

Hi @dcpadilha,

Could you maybe provide more info on your cloud deployment ?

Maybe a very long shot since I never actually deployed on AWS :sweat_smile:, but if the app is deployed behind a proxy/load balancer, maybe the Streamlit app believes you and your workmate are sharing the same session on the proxy side ?

Really long shot yeah, but that’s because it reminded me of this, so…you never know :slight_smile:

2 Likes

Hi @dcpadilha

But when I put the application on cloud, my workmate and I are having the same session state.

This is super strange… The SessionState hack puts the user’s state inside the user’s SessionInfo object, which has a 1-to-1 mapping with websockets. Since two different people will always have two different websocket connections, there should be (in theory) two different SessionInfo objects for them, and therefore two different SessionStates.

Since I can’t think of anything else, here are a few things to try:

  1. To double-check that different people are really being assigned the same SessionStates, try running the script below, then post here what the two different people see in their screens.
  2. Run Streamlit with --global.logLevel=debug, then share the logs here
  3. Let us know which version of Streamlit you’re using. That’s streamlit --version.
# debug_session_state.py

import streamlit as st
import SessionState
import random

session_state = SessionState.get(random_number=random.random())

st.write("This number should be unique for each browser tab:", session_state.random_number)

Thanks!

4 Likes

Hi @thiago and @andfanilo,

You both helped us a lot! We use a streamlit page to make the navigation between pages, and this navigation on maintaining the session on proxy.

We are using version 0.61.0.

Our solution was move the session state to this streamlit page that makes the navigation, we called it as main.py.

I made an example of our annotation tool, and you can see here .

Now, it works locally and on cloud.

Thank you all for this awesome framework!

2 Likes

2 Likes

Hi,
I still have the problem with Streamlit v0.66:

streamlit version
> Streamlit, version 0.66.0

Minimal example:

import random
import streamlit as st
import session_state

session = session_state.get(counter=0, random_number=random.random())

if st.button('Increment'):
    session.counter += 1

st.info(f'The random number is {session.random_number}')
st.info(f'The counter is {session.counter}')

The session_state is taken from https://gist.github.com/tvst/036da038ab3e999a64497f42de966a92 .

Problem

When I run this and open two browsers (or tabs), the counters in both browsers and their random numbers sync.

Timeline

B1 is browser 1, B2 is browser 2:

  1. Open B1 --> counter = 0, random_number = 0.7989246994876235
  2. Open B2 --> counter = 0, random _number = 0.983986819123734
  3. Click Increment in B1 --> counter = 1, random_number = 0.7989246994876235
  4. Click Increment in B2 --> counter = 2, random_number = 0.7989246994876235

The magic happens in step 4: Not only does the counter increment from 0 to 2, but also the random_number changes to the one from B1.

Is this an intended behavior?

1 Like

Hi @thiago,
I implemented what you suggested. But still sharing info between users (random number is the same for both users after I input some text in st.text_input). Streamlit, version 0.65.2.
I would appreciate very much your help.

Script:

import streamlit as st
import SessionState
import random
session_state = SessionState.get(random_number=random.random())
text = st.text_input("Input text:", value="")
st.write(f'Texto: {text}')
st.write("This number should be unique for each browser tab:", session_state.random_number)


2020-09-05 20:02:53.395
════════════════════════════════════════════════
global.logLevel IS DEPRECATED.
global.logLevel has been replaced with logger.level

This option will be removed on or after 2020-11-30.

Please update command-line argument or environment variable.
════════════════════════════════════════════════

2020-09-05 20:02:53.403 Initialized tornado logs
2020-09-05 20:02:53.403 Skipping PyPI version check
2020-09-05 20:02:53.404 Setting up signal handler
2020-09-05 20:02:53.405 Using selector: SelectSelector
2020-09-05 20:02:53.407 Server state: None -> State.INITIAL
2020-09-05 20:02:53.408 Starting server...
2020-09-05 20:02:53.408 Serving static content from c:\users\juan\appdata\local\continuum\anaconda3\envs\optimizacion_rutas\lib\site-packages\streamlit\static
2020-09-05 20:02:53.410 Server started on port 8501
2020-09-05 20:02:53.410 No singleton. Registering one.
2020-09-05 20:02:53.412 Watcher created for C:\Users\Juan\Documents\Trabajo\Data4Labs\optimizacion_rutas\debug_session_state.py
2020-09-05 20:02:53.413 ReportSession initialized (id=a10ebd86-ebce-461d-9163-be060196ec4a)
2020-09-05 20:02:53.414 Created new session for ws 140724295195872. Session ID: a10ebd86-ebce-461d-9163-be060196ec4a
2020-09-05 20:02:53.415 Beginning script thread
2020-09-05 20:02:53.415 Server state: State.INITIAL -> State.WAITING_FOR_FIRST_BROWSER
2020-09-05 20:02:53.416 Running script <streamlit.script_request_queue.RerunData object at 0x00000208CBBA21C8>
2020-09-05 20:02:53.416 Disconnecting files for session with ID a10ebd86-ebce-461d-9163-be060196ec4a
2020-09-05 20:02:53.416 Sessions still active: dict_keys([])
2020-09-05 20:02:53.417 Files: 0; Sessions with files: 0
2020-09-05 20:02:53.417 OnScriptRunnerEvent: ScriptRunnerEvent.SCRIPT_STARTED
2020-09-05 20:02:53.420 New browser connection: gather_usage_stats=True, sharing_enabled=False, max_cached_message_age=2
2020-09-05 20:02:53.426 OnScriptRunnerEvent: ScriptRunnerEvent.SCRIPT_STOPPED_WITH_SUCCESS
2020-09-05 20:02:53.426 OnScriptRunnerEvent: ScriptRunnerEvent.SHUTDOWN

  You can now view your Streamlit app in your browser.

  Local URL: http://localhost:8501
  Network URL: http://192.168.1.15:8501

2020-09-05 20:02:53.608 Watcher created for C:\Users\Juan\Documents\Trabajo\Data4Labs\optimizacion_rutas\SessionState.py
2020-09-05 20:02:55.414 Reused preheated session for ws 2236851561160. Session ID: a10ebd86-ebce-461d-9163-be060196ec4a
2020-09-05 20:02:55.414 Server state: State.WAITING_FOR_FIRST_BROWSER -> State.ONE_OR_MORE_BROWSERS_CONNECTED
2020-09-05 20:02:55.421 Report finished successfully; removing expired entries from MessageCache (max_age=2)
2020-09-05 20:02:55.466 Received the following back message:
rerun_script {
  widget_states {
  }
}

2020-09-05 20:02:55.467 Skipping rerun since the preheated run is the same
2020-09-05 20:02:58.399 Deleting expired files...
2020-09-05 20:03:07.718 Received the following back message:
rerun_script {
  widget_states {
    widgets {
      id: "6063455876306106503"
      string_value: "A"
    }
  }
}

2020-09-05 20:03:07.720 Beginning script thread
2020-09-05 20:03:07.721 Running script <streamlit.script_request_queue.RerunData object at 0x00000208CEBF2948>
2020-09-05 20:03:07.722 Disconnecting files for session with ID a10ebd86-ebce-461d-9163-be060196ec4a
2020-09-05 20:03:07.724 Sessions still active: dict_keys([])
2020-09-05 20:03:07.724 Files: 0; Sessions with files: 0
2020-09-05 20:03:07.725 OnScriptRunnerEvent: ScriptRunnerEvent.SCRIPT_STARTED
2020-09-05 20:03:07.736 OnScriptRunnerEvent: ScriptRunnerEvent.SCRIPT_STOPPED_WITH_SUCCESS
2020-09-05 20:03:07.737 OnScriptRunnerEvent: ScriptRunnerEvent.SHUTDOWN
2020-09-05 20:03:08.100 Report finished successfully; removing expired entries from MessageCache (max_age=2)
2020-09-05 20:03:12.709 Deleting expired files...
2020-09-05 20:03:15.946 Watcher created for C:\Users\Juan\Documents\Trabajo\Data4Labs\optimizacion_rutas\debug_session_state.py
2020-09-05 20:03:15.948 ReportSession initialized (id=8b01b5f5-b0e3-424d-a0e6-e731b6fb4575)
2020-09-05 20:03:15.949 Created new session for ws 2236851648968. Session ID: 8b01b5f5-b0e3-424d-a0e6-e731b6fb4575
2020-09-05 20:03:15.953 Server state: State.ONE_OR_MORE_BROWSERS_CONNECTED -> State.ONE_OR_MORE_BROWSERS_CONNECTED
2020-09-05 20:03:15.974 Received the following back message:
rerun_script {
  widget_states {
  }
}

2020-09-05 20:03:15.978 Beginning script thread
2020-09-05 20:03:15.979 Running script <streamlit.script_request_queue.RerunData object at 0x00000208CEBF7D88>
2020-09-05 20:03:15.980 Disconnecting files for session with ID 8b01b5f5-b0e3-424d-a0e6-e731b6fb4575
2020-09-05 20:03:15.982 Sessions still active: dict_keys([])
2020-09-05 20:03:15.983 Files: 0; Sessions with files: 0
2020-09-05 20:03:15.984 OnScriptRunnerEvent: ScriptRunnerEvent.SCRIPT_STARTED
2020-09-05 20:03:15.984 New browser connection: gather_usage_stats=True, sharing_enabled=False, max_cached_message_age=2
2020-09-05 20:03:15.987 OnScriptRunnerEvent: ScriptRunnerEvent.SCRIPT_STOPPED_WITH_SUCCESS
2020-09-05 20:03:15.989 OnScriptRunnerEvent: ScriptRunnerEvent.SHUTDOWN
2020-09-05 20:03:16.302 Watcher created for C:\Users\Juan\Documents\Trabajo\Data4Labs\optimizacion_rutas\SessionState.py
2020-09-05 20:03:16.304 Report finished successfully; removing expired entries from MessageCache (max_age=2)
2020-09-05 20:03:18.975 Received the following back message:
rerun_script {
  widget_states {
    widgets {
      id: "6063455876306106503"
      string_value: "B"
    }
  }
}

2020-09-05 20:03:18.978 Beginning script thread
2020-09-05 20:03:18.978 Running script <streamlit.script_request_queue.RerunData object at 0x00000208CEC02708>
2020-09-05 20:03:18.979 Disconnecting files for session with ID 8b01b5f5-b0e3-424d-a0e6-e731b6fb4575
2020-09-05 20:03:18.980 Sessions still active: dict_keys([])
2020-09-05 20:03:18.980 Files: 0; Sessions with files: 0
2020-09-05 20:03:18.981 OnScriptRunnerEvent: ScriptRunnerEvent.SCRIPT_STARTED
2020-09-05 20:03:18.983 OnScriptRunnerEvent: ScriptRunnerEvent.SCRIPT_STOPPED_WITH_SUCCESS
2020-09-05 20:03:18.985 OnScriptRunnerEvent: ScriptRunnerEvent.SHUTDOWN
2020-09-05 20:03:19.359 Report finished successfully; removing expired entries from MessageCache (max_age=2)
2020-09-05 20:03:20.975 Deleting expired files...
2020-09-05 20:03:23.987 Deleting expired files...
2020-09-05 20:03:27.592 Received the following back message:
rerun_script {
  widget_states {
    widgets {
      id: "6063455876306106503"
      string_value: "C"
    }
  }
}

2020-09-05 20:03:27.595 Beginning script thread
2020-09-05 20:03:27.596 Running script <streamlit.script_request_queue.RerunData object at 0x00000208CEC02988>
2020-09-05 20:03:27.598 Disconnecting files for session with ID a10ebd86-ebce-461d-9163-be060196ec4a
2020-09-05 20:03:27.598 Sessions still active: dict_keys([])
2020-09-05 20:03:27.599 Files: 0; Sessions with files: 0
2020-09-05 20:03:27.600 OnScriptRunnerEvent: ScriptRunnerEvent.SCRIPT_STARTED
2020-09-05 20:03:27.603 OnScriptRunnerEvent: ScriptRunnerEvent.SCRIPT_STOPPED_WITH_SUCCESS
2020-09-05 20:03:27.604 OnScriptRunnerEvent: ScriptRunnerEvent.SHUTDOWN
2020-09-05 20:03:27.978 Report finished successfully; removing expired entries from MessageCache (max_age=2)
2020-09-05 20:03:32.574 Deleting expired files...
2 Likes

Hello there,

same problem here :cold_sweat:
I am also using Streamlit version 0.66.

Can anyone help plz?

1 Like

Hi there,

I had the same problem with interference between sessions in Streamlit v0.65/v0.66 and found a problem in the SessionState from https://gist.github.com/tvst/036da038ab3e999a64497f42de966a92 . The problem is that the “Hack to get the session object from Streamlit” is based on the UploadedFileManager, which seems to be a singleton. Hence, all tabs/users are mapped to the exact same session.

I forked @thiago’s gist and changed it to work with Streamlit >= v0.65:

The idea was described by @Synode :clap:t2:.

With this SessionState the examples from @ch.morton and @Juan work as expected :ok_hand:t2:! Can you confirm that?

11 Likes

@FranzDiebold , you are the best. It works like a charm!
Thank you!

1 Like

Hi @FranzDiebold! Thanks a lot! It works on my side! :muscle:t2:

Also with the gist from @FranzDiebold I cannot get unique session states anymore on the most recent streamlit version. Is there any new workaround for that?

:pray: thank you

Thanks so much for the solution @FranzDiebold !!

I noticed that by adding this to SessionState:

def __contains__(self, item):
    return hasattr(self, item)

you can use it the same way as st.session_state, e.g.

session_state = get(user_name='', favorite_color='black')
if 'key' not in session_state :
    session_state.key = 'value'

Had the same issue before. This fixes my problem. Thanks!

Just a reminder: the SessionState gist is no longer required, and it’s not guaranteed to work anyway (it was just an experiment).

The official solution is to use st.session_state as described here: Session State - Streamlit Docs

1 Like