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

chore: linking ComponentManager to session #248

Merged
merged 6 commits into from
Feb 21, 2024

Conversation

mmikita95
Copy link
Contributor

Making ComponentManager a part of session as a prerequisite to link the state of the UI to each particular session instead of the whole app.

Making ComponentManager a part of session in order to link the state of the UI to each particular session instead of the whole app.
@mmikita95
Copy link
Contributor Author

Whoah, checks don't look good 😢
Not something I was expecting, I'll look into it.

@@ -723,7 +724,8 @@ class Evaluator:

template_regex = re.compile(r"[\\]?@{([\w\s.]*)}")

def __init__(self, session_state: StreamsyncState):
def __init__(self, session_id: str, session_state: StreamsyncState):
self.session_id = session_id
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why are we passing an id instead of following what was done with session_state and passing component like session_components?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The id is currently needed to access component manager inside session(s) – previously, Evaluator used "application-wide" ComponentManager in the evaluate_field method; to replace it with session-linked manager, we first need to know what session we're working on specifically. I might've misunderstood the purpose of the StreamsyncState, but I couldn't see a way to utilize it for this.

Copy link
Collaborator

Choose a reason for hiding this comment

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

But what I mean is, follow exactly what has been done with State. Rather than getting the session by id and then getting the component manager, pass the reference to the component manager when instantiating the Evaluator, similarly to how we pass session_state.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, I see, I've misunderstood your comment, apologies.

Good point, as session context is accessible during the creation of Evaluator, we might as well just pass the manager, without having the overhead of resolving it each time. I'll adjust it.

Copy link
Collaborator

@FabienArcellier FabienArcellier left a comment

Choose a reason for hiding this comment

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

I would advocate to keep the ComponentManager as high level class and to store inside the list of components associate with a session id. Having a Manager inside an instance feels wrong regards to the existing architecture.

On this strategy, we would have to change slightly the SessionPruner

        while True:
            self.is_session_pruner_terminated.wait(
                timeout=SessionPruner.PRUNE_SESSIONS_INTERVAL_SECONDS)
            if self.is_session_pruner_terminated.is_set():
                return

            expired_sessions = streamsync.session_manager.expired_sessions()
            for session in expired_sessions:
              streamsync.session_manager.prune_session(session)
              streamsync.component_manager.prune_components(session)

@@ -879,6 +885,13 @@ def __init__(self, session_id: str, cookies: Optional[Dict[str, str]], headers:
new_state.user_state.mutated = set()
self.session_state = new_state
self.event_handler = EventHandler(self)
self.component_manager = ComponentManager()
Copy link
Collaborator

Choose a reason for hiding this comment

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

I am not convince about the pattern integrating a manager in an instanced class.

I would advocate to keep the list of components the ComponentManager but we would ingest them with the session id. The component manager would stay a high level class we can rely on.

I would make the signature of ComponentManager evolve to keep the list of component per session id. It would be more easier to inspect application memory model and to make it evolve. We know all the components from all the session are in the ComponentManager. It may also allow advanced optimization as storing the diff between static component declaration and dynamic declaration.

We would also keep the ability to query the ComponentManager application wide. It may be interesting for some pattern.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it's aligned with the current architecture. We're already managing sessions for State, my idea is to just put components there so we can manage them in the same way. There's a mechanism for example to clear out expired sessions and we'd have to replicate it for components.

@@ -1075,7 +1088,7 @@ def handle(self, ev: StreamsyncEvent) -> StreamsyncEventResult:
try:
instance_path = ev.instancePath
target_id = instance_path[-1]["componentId"]
target_component = component_manager.components[target_id]
target_component = self.session.component_manager.components[target_id]
Copy link
Collaborator

Choose a reason for hiding this comment

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

The code would look like this.

component_manager.get_components(target_id, self.session.session_id)

@@ -928,7 +941,7 @@ def _check_proposed_session_id(self, proposed_session_id: Optional[str]) -> bool
return True
return False

def get_new_session(self, cookies: Optional[Dict] = None, headers: Optional[Dict] = None, proposed_session_id: Optional[str] = None) -> Optional[StreamsyncSession]:
def get_new_session(self, cookies: Optional[Dict] = None, headers: Optional[Dict] = None, proposed_session_id: Optional[str] = None, components: Optional[Dict[str, Any]] = None) -> Optional[StreamsyncSession]:
Copy link
Collaborator

Choose a reason for hiding this comment

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

We won't have to give the list of component instanciating the session.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree that this shouldn't happen, should we mirrored in the same way that we handle initial state.


for i in range(len(instance_path)):
Copy link
Collaborator

Choose a reason for hiding this comment

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

the code stay almost the same except on line 764

component_manager.get_components(component_id, self.session_id)

@@ -336,14 +332,14 @@ def _main(self) -> None:
if self.mode == "run":
terminate_early = True

try:
streamsync.component_manager.ingest(self.components)
Copy link
Collaborator

Choose a reason for hiding this comment

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

streamsync.component_manager.ingest(self.components, self.session_id)

@ramedina86 ramedina86 merged commit 3b3b5c3 into writer:dev Feb 21, 2024
12 checks passed
@mmikita95 mmikita95 deleted the release-component-mng-to-session-mng branch February 22, 2024 08:50
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.

3 participants