project-robius / project-robius/robrix
User profile cache can't notify: single-drain queue means only one widget ever sees an update
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 487
- Forks
- 68
- Avg merge
- 1h 22m
- Merged PRs (30d)
- 54
Description
Problem
process_user_profile_updates() drains a single global queue and returns ():
// src/profile/user_profile_cache.rs:65
static PENDING_USER_PROFILE_UPDATES: SegQueue<UserProfileUpdate> = SegQueue::new();
// src/profile/user_profile_cache.rs:205
pub fn process_user_profile_updates(_cx: &mut Cx) {
USER_PROFILE_CACHE.with_borrow_mut(|cache| {
while let Some(update) = PENDING_USER_PROFILE_UPDATES.pop() {
update.apply_to_cache(cache);
}
});
}
Three widgets pump that queue today:
src/home/navigation_tab_bar.rs:284src/home/room_screen.rs:1265src/profile/user_profile.rs:431
Because the queue is drained to empty and the function reports nothing, whichever widget pumps
first consumes every update, and no other widget can learn that anything changed. That is fine
for populating a shared cache, which is what it was built for. It does not work as a
notification: a widget that wants to react to a profile change either has to win the race, or
re-read the cache on every draw and hope.
Why it matters
Any feature that needs "this user's name or avatar just changed, refresh what I'm showing" cannot
be built on this. Concretely, it is why the invite screen resolves the inviter's profile exactly
once instead of staying current: there is no way for it to hear about a later update, so the
alternative would have been a cache lookup on every draw.
It is also a silent trap rather than a loud one. Adding a fourth pumper today works right up until
another widget happens to pump first, and then the new one just quietly stops seeing updates.
Suggested fix
Drain in one place and tell everyone what changed:
- Have
process_user_profile_updates()return the set of updated user IDs, or dispatch an action
carrying them. UserProfileUpdate::user_id()already exists for exactly this and is currently
#[allow(unused)](src/profile/user_profile_cache.rs:92).- Widgets then match on the IDs they care about instead of racing to drain.
Risk
The three current pumpers each do widget-specific work immediately after pumping, so centralising
the drain changes their ordering. That is the part that needs care, not the queue change itself.
The same shape exists in avatar_cache::process_avatar_updates(), which is pumped from six
places. It gets away with it today only because it calls cx.redraw_all() when anything landed,
so consumers repaint and re-read rather than needing to be told. Worth deciding whether both
should use one mechanism.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with src/profile/user_profile_cache.rs, especially process_user_profile_updates(), UserProfileUpdate::user_id(), and the three current pumpers in navigation_tab_bar.rs, room_screen.rs, and user_profile.rs. Trace the widget-specific work after pumping, then inspect avatar_cache::process_avatar_updates() for comparison. Done means updates are drained centrally, interested widgets can identify affected users, and existing profile refresh behavior remains correct.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- frontend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100