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

Lazy load room members - Part I #667

Merged
merged 47 commits into from
Jul 26, 2018

Conversation

bwindels
Copy link
Contributor

@bwindels bwindels commented Jul 10, 2018

Lazy loading of members, for now using the /joined_members endpoint until we have something better.

  • prototype lazily loaded members with /joined_members
  • pull code that assumes RoomMember.events... into RoomMember so it can transparently take lazily loaded members into account.
  • return fake sentinels with just user id when users haven't been loaded yet, better than breaking message continuation.
  • timeline reset should take into account lazily loaded members of previous timeline
  • use /members endpoint
  • fix rooms not visible on initial sync where user wasn't active recently
  • write/fix unit tests

Parent issue: element-hq/element-web#6611

@@ -287,7 +321,7 @@ RoomState.prototype.getLastModifiedTime = function() {
/**
* Get user IDs with the specified display name.
* @param {string} displayName The display name to get user IDs from.
* @return {string[]} An array of user IDs or an empty array.
* @return {string[]} An array of user IDs or an empty array.
Copy link
Member

Choose a reason for hiding this comment

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

seems like a spurious trailing whitespace was added for no reason?

for all timelines in all timeline sets
dont just rely on member events, but just copy the member
better than braking timeline continuation
In order for the lazy loading logic not to bleed into all corners
of the JS SDK, I moved some of the state copying between timelines
over to the RoomState and EventTimeLine class.
@bwindels
Copy link
Contributor Author

want to do a general review if it's ready to merge, but all should be here for a first PR.
Note that the react SDK code won't call into lazy loading code if the feature is not enabled.

Copy link
Contributor

@krombel krombel left a comment

Choose a reason for hiding this comment

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

You need to fix the tests

*/
Room.prototype.setLazilyLoadedMembers = async function(joinedMembersPromise) {
this._membersNeedLoading = false;
const members = await joinedMembersPromise;
Copy link
Contributor

Choose a reason for hiding this comment

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

You might want to catch the case that this promise fails - e.g. when something is weird with the connection or server

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point!

this._membersNeedLoading = false;
const members = await joinedMembersPromise;
//wait 10 seconds
await new Promise((resolve) => setTimeout(resolve, 5000));
Copy link
Contributor

Choose a reason for hiding this comment

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

Why should this wait? await joinedMembersPromise should make sure that it only continues executing once it is (successfully) done.
Besides that "5000" != 10 seconds ;)

getSentinelMember now does return a member (with just the userid) when there is no corresponding member yet.
With lazy loading it's perfectly possible the member is not available, and null breaks continuation in the timeline.
@bwindels
Copy link
Contributor Author

@dbkr Right, the only edge case I can think off is when you'd back paginate before the LL members are loaded, but that's probably avoidable.

Adding support for lazy loading in back-pagination is both the plan for client and server before releasing this, see element-hq/element-web#6611 (adding this to the description here as well), so you're right we don't really need to correct any other room state but the forward, live one. I'll change it back.

Added a big XXX corners cut comment where we call /joined_members 👍

…meline

since back-paginating will also support lazy loading the state needed to display that part of the timeline, and no user interaction
is supposed to happen before the lazy loaded member are, well, loaded, applying the ll members to all timelines should not be neccessary.
when cloning the state, lazy loaded members are copied over with their rawDisplayName,
which could originate from their userId if they don't have a displayname.
the displayname algorithm would assume that the displayname is explicitly set,
and see if we'd have to disambiguate. As a fix, if the display name is the same as the id, just return the id
@bwindels
Copy link
Contributor Author

@dbkr @t3chguy ready for another look

@bwindels bwindels mentioned this pull request Jul 23, 2018
5 tasks
@dbkr
Copy link
Member

dbkr commented Jul 24, 2018

Yeah, this feels a lot safer. Once we have a /members API that can get state for any given point, it might make sense to track the membersNeedLoading per roomState so we can also load member lists for these historical states. This can come later though.

@bwindels
Copy link
Contributor Author

Just had a look at the /members endpoint, and as it returns state events, not just profile information, some of the changes here could probably be avoided. So I'll make the change as part of this PR.

This commit is a substantial change, as /members returns state events,
not profile information as /joined_members, and this allows to simplify
the implementation quite a bit. We can assume again all members have
a state event associated with it.

I also changed most of the naming of lazy loaded members to
out-of-band members to reflect that this is the relevant bit for most
of the code, that the members didn't come through /sync but through
another channel.

This commit also addresses the race condition between /(joined_)members
and /sync. /members returns the members at the point in the timeline
at a given event id. Members are loaded at the last event
in the live timeline, and all members that come in from sync
in the mean time are marked as superseding the out of band members,
so they won't be overwritten, even if the timeline is reset in the
mean time.

Members are also marked if they originate from an out-of-band channel
(/members) so they can be stored accordingly (future PR).

The loading status is kept in room state now, as this made resolving
the race condition easier. One consequence is that the status needs
to be shared across cloned instances of RoomState. When resetting
the timeline (and cloning the room state) while lazy loading is in
progress, one of the RoomStates could be left in progress indefinitely.
Though that is more for clarity than avoiding any actual bugs.
…ership

to determine where a room should show up in the room list, we need to know
our membership type. But with lazy loading, we might not have our own member
if we weren't recently active in the room. Using getSyncedMembership can be
used to fallback if the users membership is not yet available.
@bwindels bwindels changed the title Lazy load room members Lazy load room members - Part I Jul 25, 2018
@bwindels
Copy link
Contributor Author

@dbkr ready for another look. This now includes calling /members instead of /joined_members

@bwindels bwindels changed the base branch from develop to bwindels/feature_lazyloading July 25, 2018 15:19
Copy link
Member

@dbkr dbkr left a comment

Choose a reason for hiding this comment

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

OK - looks plausible: let's give it a go on the feature branch

@bwindels bwindels merged commit f9025c7 into bwindels/feature_lazyloading Jul 26, 2018
@bwindels bwindels deleted the bwindels/lazy_load_members branch July 26, 2018 15:19
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