Describe the bug
MessageReceiptReporter polls the local receipts table on a fixed 1-second timer for the whole
lifetime of a connected user, whatever the app is doing. The query runs even when nothing has
been enqueued since the previous pass, so an idle session with no message traffic still issues
86 400 SQLite reads per day of connected time.
In the published artifact, MessageReceiptReporter.start() launches, on the UserScope:
while (isActive) {
messageReceiptRepository.selectMessageReceipts(MAX_BATCH_SIZE) // 100
if (receipts.isNotEmpty()) api.markDelivered(receipts).execute()
delay(REPORT_INTERVAL_IN_MS) // 1000
}
start() is called from ChatClient.initializeClientWithUser, so the loop spans the entire
connected session rather than the message screen, and ChatClientConfig exposes no way to
change the interval or turn the reporter off. Only the markDelivered call is conditional; the
SELECT is not.
The SQL reaching the database is
SELECT * FROM message_receipt ORDER BY createdAt ASC LIMIT ?.
This surfaced for us through Sentry's db_query performance detectors, which filed the same
query as an issue under unrelated transactions, including screens with no chat on them. We
verified it is nominal SDK behaviour and not something our code triggers: nothing in our app
reads or writes message_receipt, we build one ChatClient per process and connect the user
once per session.
SDK version
- 7.11.0 (identical in 7.7.0; the two constants and the call site are unchanged between them)
To Reproduce
Steps to reproduce the behavior:
- Build a
ChatClient with ChatClientConfig(offlineEnabled = true).
- Connect a user with
connectUser.
- Leave the app on any screen, chat or not, and send no message.
- Watch the database queries, with Room query logging, the Android Studio profiler, or a
Sentry performance trace. A SELECT * FROM message_receipt ORDER BY createdAt ASC LIMIT ?
appears every second for as long as the user stays connected.
Expected behavior
The drain should be driven by the receipts being enqueued rather than by a fixed timer, or at
least back off while the table keeps coming back empty. Three options, in the order we would
prefer them:
- Have
MessageReceiptManager signal the reporter when it enqueues a receipt, and let the
loop wait on that signal instead of polling.
- Apply a backoff when a pass finds nothing, up to a ceiling of a few tens of seconds, and
reset it as soon as a receipt is enqueued.
- Failing either, expose the interval, and the ability to disable the reporter, in
ChatClientConfig, next to offlineEnabled and userPresence.
Device:
- Vendor and model: not device-specific, observed across the production fleet
- Android version: not version-specific, observed across the production fleet
Screenshots
Not applicable. The relevant evidence is the two constants and the call site quoted above.
Note
With offlineEnabled = false the repository is the no-op one, so no SQL reaches a database,
but the loop itself still runs on the same timer.
Describe the bug
MessageReceiptReporterpolls the local receipts table on a fixed 1-second timer for the wholelifetime of a connected user, whatever the app is doing. The query runs even when nothing has
been enqueued since the previous pass, so an idle session with no message traffic still issues
86 400 SQLite reads per day of connected time.
In the published artifact,
MessageReceiptReporter.start()launches, on theUserScope:while (isActive) {
messageReceiptRepository.selectMessageReceipts(MAX_BATCH_SIZE) // 100
if (receipts.isNotEmpty()) api.markDelivered(receipts).execute()
delay(REPORT_INTERVAL_IN_MS) // 1000
}
start()is called fromChatClient.initializeClientWithUser, so the loop spans the entireconnected session rather than the message screen, and
ChatClientConfigexposes no way tochange the interval or turn the reporter off. Only the
markDeliveredcall is conditional; theSELECTis not.The SQL reaching the database is
SELECT * FROM message_receipt ORDER BY createdAt ASC LIMIT ?.This surfaced for us through Sentry's
db_queryperformance detectors, which filed the samequery as an issue under unrelated transactions, including screens with no chat on them. We
verified it is nominal SDK behaviour and not something our code triggers: nothing in our app
reads or writes
message_receipt, we build oneChatClientper process and connect the useronce per session.
SDK version
To Reproduce
Steps to reproduce the behavior:
ChatClientwithChatClientConfig(offlineEnabled = true).connectUser.Sentry performance trace. A
SELECT * FROM message_receipt ORDER BY createdAt ASC LIMIT ?appears every second for as long as the user stays connected.
Expected behavior
The drain should be driven by the receipts being enqueued rather than by a fixed timer, or at
least back off while the table keeps coming back empty. Three options, in the order we would
prefer them:
MessageReceiptManagersignal the reporter when it enqueues a receipt, and let theloop wait on that signal instead of polling.
reset it as soon as a receipt is enqueued.
ChatClientConfig, next toofflineEnabledanduserPresence.Device:
Screenshots
Not applicable. The relevant evidence is the two constants and the call site quoted above.
Note
With
offlineEnabled = falsethe repository is the no-op one, so no SQL reaches a database,but the loop itself still runs on the same timer.