Skip to content

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

@Yaddalapalli-Charan-Kumar-Naidu

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions