From 2330d4910cda55b1b797c6437fac117ffa445e4b Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 23 May 2024 15:50:43 -0500 Subject: [PATCH] Polling backoff timers for active convos --- src/state/messages/convo/agent.ts | 40 +++++++++++++++++++++++++++--- src/state/messages/convo/const.ts | 31 +++++++++++++++++++++-- src/state/messages/events/agent.ts | 18 +++++++------- 3 files changed, 75 insertions(+), 14 deletions(-) diff --git a/src/state/messages/convo/agent.ts b/src/state/messages/convo/agent.ts index 71b0b6f2d3..5ebaa97f8d 100644 --- a/src/state/messages/convo/agent.ts +++ b/src/state/messages/convo/agent.ts @@ -15,6 +15,8 @@ import {isNative} from '#/platform/detection' import { ACTIVE_POLL_INTERVAL, BACKGROUND_POLL_INTERVAL, + EXPIRED_TIMEOUT, + INACTIVE_POLL_INTERVAL, INACTIVE_TIMEOUT, NETWORK_FAILURE_STATUSES, } from '#/state/messages/convo/const' @@ -102,6 +104,8 @@ export class Convo { } private commit() { + this.refreshInactiveTimeout() + this.updateLastActiveTimestamp() this.snapshot = undefined this.subscribers.forEach(subscriber => subscriber()) } @@ -381,7 +385,6 @@ export class Convo { logger.DebugContext.convo, ) - this.updateLastActiveTimestamp() this.commit() } @@ -486,7 +489,38 @@ export class Convo { } /** - * Called on any state transition, like when the chat is backgrounded. This + * In `Ready` status, marks the chat as inactive and reduces polling. + */ + private inactiveTimeout: NodeJS.Timeout | undefined + + /** + * Called on every commit. If we're in ready state, it ensures we continue + * active polling, and sets up a timeout to back-off polling after a period + * of inactivity. + */ + private refreshInactiveTimeout() { + // clears either primary or secondary timeout + if (this.inactiveTimeout) { + clearTimeout(this.inactiveTimeout) + } + + if (this.status === ConvoStatus.Ready) { + this.requestPollInterval(ACTIVE_POLL_INTERVAL) + + // initial timeout, move to inactive + this.inactiveTimeout = setTimeout(() => { + this.requestPollInterval(INACTIVE_POLL_INTERVAL) + + // secondary timeout, move to background + this.inactiveTimeout = setTimeout(() => { + this.requestPollInterval(BACKGROUND_POLL_INTERVAL) + }, INACTIVE_TIMEOUT) + }, INACTIVE_TIMEOUT) + } + } + + /** + * Called on any commit, like when the chat is backgrounded. This * value is then checked on background -> foreground transitions. */ private updateLastActiveTimestamp() { @@ -494,7 +528,7 @@ export class Convo { } private wasChatInactive() { if (!this.lastActiveTimestamp) return true - return Date.now() - this.lastActiveTimestamp > INACTIVE_TIMEOUT + return Date.now() - this.lastActiveTimestamp > EXPIRED_TIMEOUT } private requestedPollInterval: (() => void) | undefined diff --git a/src/state/messages/convo/const.ts b/src/state/messages/convo/const.ts index 6ce100d11e..2cbca84bf3 100644 --- a/src/state/messages/convo/const.ts +++ b/src/state/messages/convo/const.ts @@ -1,7 +1,34 @@ +/** + * Interval for when the user is actively using the chat. + */ export const ACTIVE_POLL_INTERVAL = 1e3 -export const BACKGROUND_POLL_INTERVAL = 5e3 -export const INACTIVE_TIMEOUT = 60e3 * 5 +/** + * Interval for when the user is not actively using the chat, but could still + * be on the screen. + */ +export const INACTIVE_POLL_INTERVAL = 5e3 + +/** + * Interval for when the chat is not visible to the user, or the user has not + * interacted with the chat in some time. + */ +export const BACKGROUND_POLL_INTERVAL = 20e3 + +/** + * Timeout after which we consider the chat to be inactive, and we can slow + * polling. + */ +export const INACTIVE_TIMEOUT = 60e3 + +/** + * Timeout after which we consider the chat stale and in need of a full reset. + */ +export const EXPIRED_TIMEOUT = 60e3 * 5 + +/** + * Retryable error statuses + */ export const NETWORK_FAILURE_STATUSES = [ 1, 408, 425, 429, 500, 502, 503, 504, 522, 524, ] diff --git a/src/state/messages/events/agent.ts b/src/state/messages/events/agent.ts index 0389c77f58..d31720028e 100644 --- a/src/state/messages/events/agent.ts +++ b/src/state/messages/events/agent.ts @@ -322,15 +322,15 @@ export class MessagesEventBus { this.isPolling = true - // logger.debug( - // `${LOGGER_CONTEXT}: poll`, - // { - // requestedPollIntervals: Array.from( - // this.requestedPollIntervals.values(), - // ), - // }, - // logger.DebugContext.convo, - // ) + logger.debug( + `${LOGGER_CONTEXT}: poll`, + { + requestedPollIntervals: Array.from( + this.requestedPollIntervals.values(), + ), + }, + logger.DebugContext.convo, + ) try { const response = await networkRetry(2, () => {