Skip to content

iter states#3769

Closed
benedikt-bartscher wants to merge 10 commits intoreflex-dev:mainfrom
benedikt-bartscher:iter-states
Closed

iter states#3769
benedikt-bartscher wants to merge 10 commits intoreflex-dev:mainfrom
benedikt-bartscher:iter-states

Conversation

@benedikt-bartscher
Copy link
Copy Markdown
Contributor

@benedikt-bartscher benedikt-bartscher commented Aug 9, 2024

import asyncio
import datetime

import reflex as rx
from reflex.utils.prerequisites import get_app


class State(rx.State):
    async def invalidate(self) -> None:
        app = get_app()
        async for state in app.modify_states(from_state=self, substate_cls=State):
            pass

    @rx.var
    def time(self) -> str:
        return datetime.datetime.now().strftime("%H:%M:%S")


def index() -> rx.Component:
    return rx.container(
        rx.text(f"Current time: {State.time}"),
        rx.button("Invalidate State", on_click=State.invalidate),
    )


async def invalidate_lifespan() -> None:
    app = get_app()
    while True:
        async for state in app.modify_states(substate_cls=State):
            pass
        await asyncio.sleep(5)


app = rx.App(lifespan_tasks=[invalidate_lifespan])
app.add_page(index)

@benedikt-bartscher benedikt-bartscher marked this pull request as ready for review August 10, 2024 08:38
@benedikt-bartscher benedikt-bartscher changed the title wip: iter states iter states Aug 10, 2024
@benedikt-bartscher
Copy link
Copy Markdown
Contributor Author

benedikt-bartscher commented Aug 11, 2024

@masenf do you have any idea if there is a cool way to automatically detect if modify_states was called from an event handler to check for from_state=self for deadlock prevention?

@benedikt-bartscher
Copy link
Copy Markdown
Contributor Author

benedikt-bartscher commented Aug 19, 2024

@masenf do you have any idea if there is a cool way to automatically detect if modify_states was called from an event handler to check for from_state=self for deadlock prevention?

We could also add a BaseState.modify_states partial-like method which calls app.modify_states(..., from_state=self) and advise users to use self.modify_states in event handlers

Copy link
Copy Markdown
Contributor

@picklelo picklelo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay here. I think the changes look good - we need to rebase this onto main and implement it for StateManagerDisk which is becoming the default in 0.7.0

Comment thread reflex/utils/string.py Outdated
@benedikt-bartscher
Copy link
Copy Markdown
Contributor Author

Sorry for the delay here. I think the changes look good - we need to rebase this onto main and implement it for StateManagerDisk which is becoming the default in 0.7.0

No worries, I just implemented it for StateManagerDisk

Copy link
Copy Markdown
Contributor

@picklelo picklelo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code works well for me. I'll wait for @masenf 's final approval to merge. What was the use case for this?

@benedikt-bartscher
Copy link
Copy Markdown
Contributor Author

benedikt-bartscher commented Oct 10, 2024

Code works well for me. I'll wait for @masenf 's final approval to merge. What was the use case for this?

You can use it for cache invalidation, f.e. to have all blog pages as infinitely cached computed vars and invalidate/reload them globally if a page changes.

Maybe we could later use it for some kind of state migration.

@benedikt-bartscher
Copy link
Copy Markdown
Contributor Author

Will rebase if there is intention to merge this

Copy link
Copy Markdown
Collaborator

@masenf masenf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the main problem i forsee with this feature is that it works great in testing/dev mode, and then once it's deployed prod with redis, some clients are not going to get deltas sent when their state is modified, because they're connected to a different instance of the app than where this API is used.

it's not a new problem, we've had it for a long time. but currently there is no mechanism for an app instance to send a delta to a client that is connected to a different instance. @Lendemor had a WiP to handle this, but i think it's closed without merging.

raise


def get_app(reload: bool = False) -> App:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we make this new function get_app_instance and leave get_app the way it was, to retain as much compatibility as possible

Comment thread reflex/state.py
The state names.
"""
for path in self._iter_pkl_files():
token = path.stem
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unfortunately this wont work anymore, because we started hashing the token to avoid file path limits on windows.

however, we should be able to use the same implementation here as we do for StateManagerMemory as the on-disk pickles are only read when the backend starts after a hot reload

@Lendemor
Copy link
Copy Markdown
Contributor

Marking this as draft until ready for review.

@Lendemor Lendemor marked this pull request as draft October 25, 2024 18:20
@benedikt-bartscher
Copy link
Copy Markdown
Contributor Author

it's not a new problem, we've had it for a long time. but currently there is no mechanism for an app instance to send a delta to a client that is connected to a different instance. @Lendemor had a WiP to handle this, but i think it's closed without merging.

Thanks for the review. Yes, that's currently a limitation, but i think it can be implemented with redis pub/sub and some maps.
Do you mean this PR #2819 ?

@masenf
Copy link
Copy Markdown
Collaborator

masenf commented Oct 27, 2025

Closing in favor of #5927

https://github.com/reflex-dev/reflex/pull/5927/files#diff-f54b166b5fbb1cbd472d99aa3a943150590610a2f3fd2db8745f277ce443b9b1R70-R77

Using the new TokenManager.enumerate_tokens interface, along with lost+found, we can finally achieve the dream of editing states on arbitrary instances and delivering updates to the proper frontend client

@masenf masenf closed this Oct 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants