Skip to content

Conversation

@sm-sayedi
Copy link
Collaborator

Fixes: #1256

Screen recordings

First batch - Empty

Before

Empty.first.batch.-.Before.mov

After

Empty.first.batch.-.After.mov

First batch - Less than a screenful

Before

First.batch.with.few.messages.-.Before.mov

After

First.batch.with.few.messages.-.After.mov

@sm-sayedi sm-sayedi force-pushed the 1256-fetch-older-fails branch 4 times, most recently from 22e9f22 to f920082 Compare November 19, 2025 18:01
@sm-sayedi sm-sayedi force-pushed the 1256-fetch-older-fails branch from f920082 to a53cbfa Compare November 20, 2025 19:20
@sm-sayedi sm-sayedi marked this pull request as ready for review November 20, 2025 19:23
@sm-sayedi sm-sayedi force-pushed the 1256-fetch-older-fails branch from a53cbfa to ef1fcc3 Compare November 20, 2025 19:50
@sm-sayedi sm-sayedi added the maintainer review PR ready for review by Zulip maintainers label Nov 20, 2025
@sm-sayedi sm-sayedi requested a review from chrisbobbe November 20, 2025 19:51
This change is necessary when there is a need to fetch more messages
in both directions, older and newer, and when fetching in
one direction avoids fetching in another direction at the same time,
because of the `if (busyFetchingMore) return` line in
both `fetchOlder` and `fetchNewer`.

This scenario happens when a conversation is opened in its first unread,
such that the number of messages in the initial batch is so low (because
they're muted in one way or another) that it's already past the certain
point where the scroll metrics listener in the widget code triggers both
`fetchOlder` and `fetchNewer`. In 2025-11, that code first calls
`fetchOlder` then `fetchNewer`, and for the reason mentioned above,
`fetchNewer` will not fetch any new messages. But that's fine, because
as soon as older messages from `fetchOlder` arrives, there will be
a change in the scroll metrics, so `fetchNewer` will be called again,
fetching new messages.

But imagine if the number of messages in the initial batch occupies less
than a screenful, and then `fetchOlder` returns no messages or a few
messages that combined with the initial batch messages are still less
than a screenful; in that case, there will be no change in the scroll
metrics to call `fetchNewer`.

With the three fetch request types being separated, especially the two
request types for older and newer messages, each direction can fetch
more messages independently without interfering with one another.

Another benefit of this change is that if there's a backoff in one
direction, it will not affect the other one.

Fixes: zulip#1256
@sm-sayedi sm-sayedi force-pushed the 1256-fetch-older-fails branch from ef1fcc3 to 127f690 Compare November 20, 2025 20:02
Copy link
Collaborator

@chrisbobbe chrisbobbe left a comment

Choose a reason for hiding this comment

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

Thanks! Here's a review of the first three commits:

542996e msglist [nfc]: Mention fetchNewer in the MessageListView dartdoc
ce56456 msglist [nfc]: Add a new point to _MessageSequence.messages dartdoc
3c10bed msglist [nfc]: Remove one nested try block in _fetchMore

and a partial review of the fourth:

03d61ca msglist: Fetch newer messages despite previous muted batch

For that fourth commit, can you say briefly in the commit message why it's not a complete fix for the issue, to help orient the reader to what comes next?


processResult(result);
} catch (e) {
hasFetchError = true;
Copy link
Collaborator

Choose a reason for hiding this comment

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

msglist [nfc]: Remove one nested try block in `_fetchMore`

The nested `try` block doesn't seem to be making any difference,
so good to remove.

This isn't NFC: now, hasFetchError is about what happens when data is fetched and processed (with processResult), not just about what happens when data is fetched. That doesn't seem desirable, just from looking at its name.

Comment on lines +148 to +155
/// The ID of the oldest known message so far in this narrow.
///
/// This will be `null` if no messages of this narrow are fetched yet.
/// Having a non-null value for this doesn't always mean [haveOldest] is `true`.
///
/// The related message may not appear in [messages] because it
/// is muted in one way or another.
int? get oldMessageId => _oldMessageId;
Copy link
Collaborator

Choose a reason for hiding this comment

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

The ID of the oldest known message so far in this narrow.

There isn't necessarily a message with this ID in the narrow, though, right? In a quick skim, I don't see event-handling code to update _oldMessageId when the corresponding message is deleted or moved out of the narrow. We should avoid saying the message is in the narrow when it might not be.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintainer review PR ready for review by Zulip maintainers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

msglist: Fetch-older is defeated by a run of 100+ muted messages

2 participants