poll for messages on chat push notification

stop polling entirely in the background (resume already triggers an
immediate catch-up poll), and force an immediate poll when a chat push
notification arrives while foregrounded via a new pollNow() on the
event bus.

APP-2415

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Samuel Newman
2026-06-16 18:29:05 +03:00
parent 9dc73d2ec7
commit 6fe5ef022c
4 changed files with 32 additions and 15 deletions
+8
View File
@@ -10,6 +10,7 @@ import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher'
import {logger as notyLogger} from '#/lib/notifications/util'
import {type NavigationProp} from '#/lib/routes/types'
import {useCurrentConvoId} from '#/state/messages/current-convo-id'
import {useMaybeMessagesEventBus} from '#/state/messages/events'
import {RQKEY as RQKEY_NOTIFS} from '#/state/queries/notifications/feed'
import {invalidateCachedUnreadPage} from '#/state/queries/notifications/unread'
import {truncateAndInvalidate} from '#/state/queries/util'
@@ -114,6 +115,7 @@ export function useNotificationsHandler() {
const {onPressSwitchAccount} = useAccountSwitcher()
const navigation = useNavigation<NavigationProp>()
const {currentConvoId} = useCurrentConvoId()
const messagesBus = useMaybeMessagesEventBus()
const {setShowLoggedOut} = useLoggedOutViewControls()
const closeAllActiveElements = useCloseAllActiveElements()
const {_} = useLingui()
@@ -316,6 +318,11 @@ export function useNotificationsHandler() {
isChatNotificationPayload(payload) &&
payload.recipientDid === currentAccount?.did
) {
// A chat push means new events probably exist - force an immediate
// poll so the convo list / open convo update without waiting for the
// next scheduled tick. No-op unless the bus is actively polling.
messagesBus?.pollNow()
// chat-removed-from-group / chat-join-request-rejected always alert,
// even if the recipient is currently viewing the affected convo -
// they need to know they were removed/rejected.
@@ -425,6 +432,7 @@ export function useNotificationsHandler() {
navigation,
onPressSwitchAccount,
setShowLoggedOut,
messagesBus,
])
}
+15 -14
View File
@@ -9,10 +9,7 @@ import {
isNetworkError,
} from '#/lib/strings/errors'
import {Logger} from '#/logger'
import {
BACKGROUND_POLL_INTERVAL,
DEFAULT_POLL_INTERVAL,
} from '#/state/messages/events/const'
import {DEFAULT_POLL_INTERVAL} from '#/state/messages/events/const'
import {
type MessagesEventBusDispatch,
MessagesEventBusDispatchEvent,
@@ -56,6 +53,17 @@ export class MessagesEventBus {
}
}
/**
* Force an immediate poll and restart the interval clock from now. Only has
* an effect while we're actively polling (Ready) - the dispatched UpdatePoll
* is a no-op in other states (init/resume will poll on their own). Used when
* an external signal (a chat push notification) tells us new events probably
* exist and we don't want to wait for the next scheduled tick.
*/
pollNow() {
this.dispatch({event: MessagesEventBusDispatchEvent.UpdatePoll})
}
getLatestRev() {
return this.latestRev
}
@@ -122,7 +130,7 @@ export class MessagesEventBus {
}
case MessagesEventBusDispatchEvent.Background: {
this.status = MessagesEventBusStatus.Backgrounded
this.resetPoll()
this.stopPoll()
this.emitter.emit('event', {type: 'connect'})
break
}
@@ -142,7 +150,7 @@ export class MessagesEventBus {
switch (action.event) {
case MessagesEventBusDispatchEvent.Background: {
this.status = MessagesEventBusStatus.Backgrounded
this.resetPoll()
this.stopPoll()
break
}
case MessagesEventBusDispatchEvent.Suspend: {
@@ -181,10 +189,6 @@ export class MessagesEventBus {
this.emitter.emit('event', {type: 'error', error: action.payload})
break
}
case MessagesEventBusDispatchEvent.UpdatePoll: {
this.resetPoll()
break
}
}
break
}
@@ -197,7 +201,7 @@ export class MessagesEventBus {
}
case MessagesEventBusDispatchEvent.Background: {
this.status = MessagesEventBusStatus.Backgrounded
this.resetPoll()
this.stopPoll()
break
}
case MessagesEventBusDispatchEvent.Error: {
@@ -313,9 +317,6 @@ export class MessagesEventBus {
const lowest = Math.min(DEFAULT_POLL_INTERVAL, ...requested)
return lowest
}
case MessagesEventBusStatus.Backgrounded: {
return BACKGROUND_POLL_INTERVAL
}
default:
return DEFAULT_POLL_INTERVAL
}
-1
View File
@@ -1,2 +1 @@
export const DEFAULT_POLL_INTERVAL = 60e3
export const BACKGROUND_POLL_INTERVAL = 60e3 * 5
+9
View File
@@ -17,6 +17,15 @@ export function useMessagesEventBus() {
return ctx
}
/**
* Like useMessagesEventBus, but returns null instead of throwing when there's
* no bus (e.g. when logged out, where the provider supplies a null value).
* Use this from always-mounted consumers that may run without a session.
*/
export function useMaybeMessagesEventBus() {
return useContext(MessagesEventBusContext)
}
export function MessagesEventBusProvider({
children,
}: {