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

improvement(client-presence): Consistent event ordering and state results #23797

Open
wants to merge 13 commits into
base: main
Choose a base branch
from

Conversation

WillieHabi
Copy link
Contributor

@WillieHabi WillieHabi commented Feb 5, 2025

Description

For consistent data reads, events from value manager updates should be placed in a queue to be processed directly after the incoming signal is processed. Then any data explorations a customer may trigger from event will get current values.

This PR makes every workspace return a list of "post update actions" that must be executed after every updated is processed from the incoming signal. This makes sure that if a client gets receives event from one update, all other updates within the same datastore update message will be consistently reflected.

Tests:

ValueManager eventing
  - is consistent with attendee + latest value manager updates
  - is consistent with attendee + latest map value manager updates
  - is consistent with attendee + notifications updates
  - is consistent with attendee + latest value manager + latest map value manager updates

Fixes AB#29542

@github-actions github-actions bot added area: framework Framework is a tag for issues involving the developer framework. Eg Aqueduct base: main PRs targeted against main branch labels Feb 5, 2025
@WillieHabi WillieHabi requested a review from jason-ha February 5, 2025 23:21
@WillieHabi WillieHabi marked this pull request as ready for review February 6, 2025 18:04
@Copilot Copilot bot review requested due to automatic review settings February 6, 2025 18:04

Choose a reason for hiding this comment

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

Copilot reviewed 5 out of 8 changed files in this pull request and generated no comments.

Files not reviewed (3)
  • packages/framework/presence/src/internalTypes.ts: Evaluated as low risk
  • packages/framework/presence/src/latestMapValueManager.ts: Evaluated as low risk
  • packages/framework/presence/src/latestValueManager.ts: Evaluated as low risk
Comments suppressed due to low confidence (1)

packages/framework/presence/src/notificationsManager.ts:254

  • The return type of the update method should be consistent. If there are no listeners, it should return an empty array. This ensures that the caller can always expect an array, regardless of whether there are listeners or not.
return [];
@rajatch-ff rajatch-ff requested review from a team, pragya91, markfields, jatgarg, kian-thompson, rajatch-ff and MarioJGMsoft and removed request for a team February 6, 2025 23:54
packages/framework/presence/src/latestMapValueManager.ts Outdated Show resolved Hide resolved
packages/framework/presence/src/latestMapValueManager.ts Outdated Show resolved Hide resolved
packages/framework/presence/src/latestMapValueManager.ts Outdated Show resolved Hide resolved
@@ -248,6 +248,7 @@ class NotificationsManagerImpl<
...value.value.args,
);
}
return [];
Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't seem to be returning any post update actions. Missing test coverage?

packages/framework/presence/src/presenceStates.ts Outdated Show resolved Hide resolved
Comment on lines 141 to 142
const joiningAttendees = new Set<SessionClient>();
const postUpdateActions: (() => void)[] = [];
Copy link
Contributor

Choose a reason for hiding this comment

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

I feel like maybe this was covered in a past review, but there isn't a comment.
Why is joiningAttendees a set?
If it doesn't need to be a set, then I recommend populating events instead of building set.
If set is needed, please comment. Then I recommend moving array declaration to later where it is built. (Also use PostUpdateAction type?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

A set isn't needed, we should just populate events here

Comment on lines 59 to 60
};
describe("State eventing", () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Not just state - order consistency should apply to notifications too. And beyond that the ordering matters for workspaceActivated (those need to happen early and let local registrations happen immediately, so they get updates especially for Notifications)
Also add a vertical space here.

Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like the test cases are only checking piece-wise consistency. During any event all of the states should be consistent with the final 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.

During any event all of the states should be consistent with the final state.

I think that's what is being tested here(?) Prior to update we set up all event listeners and each listener makes sure all other updates are reflected. If an event triggers before all updates are reflected the test will fail.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe if there's an example scenario not covered I'd understand better

Copy link
Contributor

Choose a reason for hiding this comment

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

How about this? Revert all of your implementation changes and see what parts of tests pass/fail.
You have changed things so you will see more failure than when I first commented.
But you also have too much tested at once such that a failure isn't pointing to one thing.
And I think that last test passes even if no events are fired.

Copy link
Contributor

Choose a reason for hiding this comment

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

Here is a little more detail on how to see what is going on. Revert implementation. Run tests. For line that fails, remove it and repeat. In the end there will still be new verifications that are passing without any impl changes.

Copy link
Contributor Author

@WillieHabi WillieHabi Feb 12, 2025

Choose a reason for hiding this comment

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

Tried a new implementation where we wait for the first event to fire and immediately check all state after (then finish by making sure all events fire). The first event's update will be reflected and pass regardless of new impl, but we still have to test this I'd assume.

Would it be better to have tests separated into "is consistent on {latestValue | attendee| latestMap | notification} update" where we wait for a one specific update and then check state after? One of these tests would still pass since it would be the first event.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: framework Framework is a tag for issues involving the developer framework. Eg Aqueduct base: main PRs targeted against main branch
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants