Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iter states #3769

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
Draft

Conversation

benedikt-bartscher
Copy link
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
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
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
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

reflex/utils/string.py Outdated Show resolved Hide resolved
@benedikt-bartscher
Copy link
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
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
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
Contributor Author

Will rebase if there is intention to merge this

Copy link
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.

@@ -279,6 +282,18 @@ def get_app(reload: bool = False) -> ModuleType:
raise


def get_app(reload: bool = False) -> App:
Copy link
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

The state names.
"""
for path in self._iter_pkl_files():
token = path.stem
Copy link
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
Collaborator

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
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 ?

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