RocketChat / RocketChat/Rocket.Chat.ReactNative

bug: Performance issue in getUsersPresence due to unbatched WatermelonDB writes and race condition

Open
#7,032 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

🐛 bug type: bug
Dominant language
TypeScript
Stars
2.4k
Forks
1.5k
Avg merge
1d 18h
Merged PRs (30d)
90

Description

Describe the Bug

While reviewing app/lib/methods/getUsersPresence.ts
I noticed a performance bottleneck and a race condition.

Right now, when the app gets presence updates, it runs db.write() inside an asynchronous users.forEach loop. WatermelonDB explicitly warns against this because it spins up hundreds of concurrent writer processes instead of batching them, which causes massive UI stuttering on slower phones.

Also, the usersBatch array isn't deduplicated. If the app asks for the same user's presence multiple times rapidly, it processes the same ID concurrently. This causes a race condition where both processes try to create() the user at the exact same time, throwing a native SQLite Unique Constraint violation (which ends up as a silent Unhandled Promise Rejection that kills the sync).

Steps to Reproduce
  1. Open a channel with a lot of active users where presence updates are firing rapidly.
  2. Rapid [getUserPresence(uid)] calls end up pushing duplicate uids into the usersBatch array.
  3. When [getUsersPresence] fires, it attempts to process these duplicates.
  4. The users.forEach(async ...) loop spins up dozens of concurrent db.write() operations.
  5. SQLite Unique Constraint tracking fails for the duplicate IDs, causing an unhandled promise rejection in the background.
  6. The UI stutters and drops frames heavily due to all the unbatched SQLite writers trying to run at once.
Expected Behavior
  • We should deduplicate usersBatch before processing it (e.g. [...new Set(usersBatch)]).
  • We should use WatermelonDB's Q.oneOf() to bulk-fetch all records at once.
  • We should queue up prepareUpdate and prepareCreate operations and execute them in a single, atomic db.batch() call to fix the crashes and improve performance.
  • usersBatch allows duplicates.
  • Calling db.write() inside a forEach loop kills performance.
  • Concurrent writes for the exact same uid trigger SQLite unique constraint crashes (Unhandled Promise Rejections).
Actual Behavior

No response

Rocket.Chat Server Version

8.2.0

Rocket.Chat App Version

4.70.0.9999999999

Device Name

Realme 12+

OS Version

Android 15

Additional Context

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with app/lib/methods/getUsersPresence.ts and trace how rapid getUserPresence(uid) calls populate usersBatch. Reproduce the rapid duplicate-presence scenario on the described Android setup; done means duplicate IDs no longer cause SQLite unique-constraint failures, writes are batched, and UI stuttering is reduced.

Written by the indexing model from the issue text.

Assessment

Tech stack
react-native, sqlite, typescript
Domain
database, mobile, performance
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.