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

GROUP-89 Added Initial State Support #22

Merged
merged 5 commits into from
Mar 19, 2024
Merged

Conversation

makmn1
Copy link
Member

@makmn1 makmn1 commented Mar 19, 2024

Description of Changes

This pull requests introduces several enhancements to how group updates are sent to users via Group Sync instances, most of which help simplify how clients keep up to date with the latest group info. The changes here are part of a larger cross-service effort to simplify loading and synchronization for clients.

Group Initial State Service

One of the major changes here is how users fetch the initial state of groups. Previously, users would have to make a separate request to fetch groups, meaning they'd have to keep track of the status of that request separately. While this wouldn't introduce much complexity on its own, clients would also need to keep track of an updates stream. To help simplify this, Group Sync now uses the Group Initial State Service class to fetch the latest group info from Group Service with the help of the new Group State Service class.

This new service relies on the state pattern for managing the initial state of groups. The initial state is built only once if successful, transitioning the service into the READY state. Groups are kept up-to-date using the same event stream that users subscribe to (groups.updates.all) using concurrency-safe Java utilities.

Group State Service

Provides utilities for initializing the current state of groups as well as handling event updates for groups and their members.

RSocket Endpoints

groups.updates.all

Previously returned a stream of group updates to users. Now it returns a concatenated stream of events in the following order:

  1. Events representing the initial state of groups and their members
  2. An empty event
  3. A stream of group updates (same stream used before)

This provides users with the initial state of groups when they initially connect. They can use the same event handling logic used for handling group updates to also handle building the initial state.

Also note the empty event. Currently, RSocketJS used by the GroupHQ client does not provide a way to hook into an 'on connected' event to a stream, meaning it's difficult to know when a stream is active and to trigger any changes as a result. One way to solve this is to set the state once an item is emitted from the stream. However, if the current state of groups is empty, and there are no updates from the stream, this emission will never occur. To solve this edge case, an empty event is emitted which contains no group updates. It is sent after the initial state of events since that stream will always be finite, while the stream of group updates never ends.

groups.user.member

Previously returned a user's member as a normal MemberModel. Now returns it as a PublicMember model. This change lessens the burden of clients having to keep track of two separate models. The MemberModel contains a user's unique identifying info, which isn't needed by the user in this context.

groups.ping

Added for the purposes of checking the stability of an RSocket connection. Currently, when a user tries to establish an RSocket connection with Group Sync, they first need to go through GroupHQ's API Gateway. This gateway is not set up to authenticate against RSocket connections for the /rsocket endpoint. Instead, any request to this endpoint is forwarded to Group Sync which does the authenticating. However, it seems like the API Gateway causes the connection to appear accepted client-side. If Group Sync is unavailable, or if it rejects the connection request, the client experiences a quick disconnection after connecting.

This can make it complicated for the client to know if their RSocket connection is ready, so this endpoint allows them to test their connection--which would only work if their connection has been accepted by Group Sync.

Event ID Handling

Previously we employed a zero-trust policy when it came to user-provided event ids. That is, we would always overwrite the event id of a received request event. The issue here is it makes it difficult for the user to keep track of their request on a separate event stream. Two solutions were considered:

  1. Keep the current logic, but return the real event id of the request to the user
  2. Accept the user's event id, as long as it parses to a valid Universal Unique Identifier (UUID)

Solution two was chosen, mainly because of the simplicity of not having to return to the client anything (and the client not having to keep track of the returned event id). The implications of this is that a user could send multiple requests with the same event id. That's fine, since Group Service is designed to reject any requests if there exists a request event with the same event id. And with version 4 UUIDs, there's no practical risk of id collision, whether it's generated by the client or the server.

Additional Info / Concerns

Group Initial State Service

This service still requires more work for added robustness. What happens if the update stream for groups errors out? What if the state of groups somehow go out of sync? A separate issue has been created to address this.

@makmn1 makmn1 added bug Something isn't working enhancement New feature or request labels Mar 19, 2024
@makmn1 makmn1 self-assigned this Mar 19, 2024
@makmn1 makmn1 merged commit 320e170 into main Mar 19, 2024
3 checks passed
@makmn1 makmn1 deleted the GROUP-89-Fix-Loading-Issues branch March 19, 2024 17:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant