Skip to content

chore: cache inbox message opened#656

Merged
mrehan27 merged 4 commits intofeature/message-inbox-mvpfrom
mbl-1548-cache-opened
Feb 18, 2026
Merged

chore: cache inbox message opened#656
mrehan27 merged 4 commits intofeature/message-inbox-mvpfrom
mbl-1548-cache-opened

Conversation

@mrehan27
Copy link
Contributor

@mrehan27 mrehan27 commented Feb 16, 2026

closes: MBL-1548

Summary

Prevents inbox messages from reverting to "unread" when 304 responses contain stale cached data by caching user's opened status locally and applying it on 304 responses, while clearing cache on fresh 200 responses.

Changes

  • Updated 304 response handling to keep status code as 304 instead of converting to 200 for better handling
  • Added explicit handling for 200 (fresh) vs 304 (cached) responses in Queue.fetchUserMessages()
  • Added fromCache parameter to handleSuccessfulFetch() to distinguish response types
  • Cache locally opened status when user marks message opened/unopened (logOpenedStatus)
  • Apply cached opened status when processing 304 responses to preserve user's recent changes
  • Clear cached status when processing 200 responses (prefer server state)
  • Clear cached status when message is deleted (logDeleted)
  • Updated GistQueue, Queue, and InAppPreferenceStore to internal (removed from public API)

How to Test

Before

  • Mark an inbox message as read
  • Wait for 10 seconds for polling to fetch messages from server or relaunch app
  • The message shows as unread again (if server returned 304)

After

  • Mark an inbox message as read
  • Wait for 10 seconds for polling to fetch messages from server or relaunch app
  • The message still shows as read (even if server returned 304)

Note

Medium Risk
Touches message fetching and state reconciliation around HTTP caching (304 handling), so mistakes could cause incorrect inbox read/unread state or stale overrides persisting.

Overview
Prevents inbox messages from reverting to unread when the message poll returns cached data by caching per-message opened state locally and reapplying it when responses are served from cache.

Queue.fetchUserMessages() now tags 304-derived responses (via a custom header after converting 304->200 for Retrofit), distinguishes cached vs fresh fetches, and on cached fetches overlays the locally stored opened flag onto mapped InboxMessages; on fresh 200s it clears the local override. Open/unopen actions persist the override to preferences, and deletions clear it. Public API surface is reduced by making GistQueue/Queue and InAppPreferenceStore internal (reflected in messaginginapp.api), and new preference-store behavior is covered by added unit tests.

Written by Cursor Bugbot for commit dab9009. This will update automatically on new commits. Configure here.

@mrehan27 mrehan27 self-assigned this Feb 16, 2026
@mrehan27 mrehan27 requested a review from a team as a code owner February 16, 2026 10:34
@github-actions
Copy link

github-actions bot commented Feb 16, 2026

Sample app builds 📱

Below you will find the list of the latest versions of the sample apps. It's recommended to always download the latest builds of the sample apps to accurately test the pull request.


Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

@codecov
Copy link

codecov bot commented Feb 16, 2026

Codecov Report

❌ Patch coverage is 43.47826% with 13 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (feature/message-inbox-mvp@70d9831). Learn more about missing BASE report.

Files with missing lines Patch % Lines
...stomer/messaginginapp/gist/data/listeners/Queue.kt 13.33% 12 Missing and 1 partial ⚠️
Additional details and impacted files
@@                     Coverage Diff                      @@
##             feature/message-inbox-mvp     #656   +/-   ##
============================================================
  Coverage                             ?   68.88%           
  Complexity                           ?      819           
============================================================
  Files                                ?      148           
  Lines                                ?     4580           
  Branches                             ?      616           
============================================================
  Hits                                 ?     3155           
  Misses                               ?     1195           
  Partials                             ?      230           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions
Copy link

  • java_layout: mbl-1548-cache-opened (1771238158)

@github-actions
Copy link

  • kotlin_compose: mbl-1548-cache-opened (1771238150)

@github-actions
Copy link

github-actions bot commented Feb 16, 2026

📏 SDK Binary Size Comparison Report

Module Last Recorded Size Current Size Change in Size
core 29.85 KB 29.85 KB ✅ No Change
datapipelines 38.88 KB 38.88 KB ✅ No Change
messagingpush 30.25 KB 30.25 KB ✅ No Change
messaginginapp 120.04 KB 120.80 KB ⬆️ +0.76KB
tracking-migration 22.89 KB 22.89 KB ✅ No Change

@github-actions
Copy link

Build available to test
Version: mbl-1548-cache-opened-SNAPSHOT
Repository: https://s01.oss.sonatype.org/content/repositories/snapshots/

@github-actions
Copy link

  • java_layout: mbl-1548-cache-opened (1771238866)

@github-actions
Copy link

  • kotlin_compose: mbl-1548-cache-opened (1771238856)

@github-actions
Copy link

  • java_layout: mbl-1548-cache-opened (1771239571)

@github-actions
Copy link

  • kotlin_compose: mbl-1548-cache-opened (1771239572)

try {
logger.debug("Updating inbox message ${message.toLogString()} opened status to: $opened")
// Cache the opened status locally for 304 responses
inAppPreferenceStore.saveInboxMessageOpenedStatus(message.queueId, opened)
Copy link
Contributor

Choose a reason for hiding this comment

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

Cache is updated before the API call. If the network call fails, the cache reflects a state the server never acknowledged?. Also the iOS PR does the opposite, cache is only written inside the success callback (response.statusCode == 200). We should do the similar here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated to cache after successful api call only

when {
(code == 204 || code == 304) -> handleNoContent(code)
latestMessagesResponse.isSuccessful -> handleSuccessfulFetch(latestMessagesResponse.body())
latestMessagesResponse.isSuccessful -> handleSuccessfulFetch(
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we add Queue-level tests for:

  1. fromCache=true applies cached opened status
  2. fromCache=false clears cached opened status and uses server value
  3. network failure on log calls does not mutate cache (if fix above is applied)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately there's no coverage for Queue at the moment either. I'll add coverage for this in later PRs.

@github-actions
Copy link

  • java_layout: mbl-1548-cache-opened (1771418177)

@github-actions
Copy link

  • kotlin_compose: mbl-1548-cache-opened (1771418183)

@mrehan27 mrehan27 merged commit eb1c650 into feature/message-inbox-mvp Feb 18, 2026
37 checks passed
@mrehan27 mrehan27 deleted the mbl-1548-cache-opened branch February 18, 2026 12:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants