diff --git a/app-shell-odd/src/notifications/deserialize.ts b/app-shell-odd/src/notifications/deserialize.ts index 01fd4bc933b..5a154ebee5f 100644 --- a/app-shell-odd/src/notifications/deserialize.ts +++ b/app-shell-odd/src/notifications/deserialize.ts @@ -31,6 +31,10 @@ export function sendDeserialized( } catch {} // Prevents shell erroring during app shutdown event. } +export function sendDeserializedRefetch(topic: NotifyTopic): void { + sendDeserialized(topic, { refetch: true }) +} + export function sendDeserializedGenericError(topic: NotifyTopic): void { sendDeserialized(topic, FAILURE_STATUSES.ECONNFAILED) } diff --git a/app-shell-odd/src/notifications/subscribe.ts b/app-shell-odd/src/notifications/subscribe.ts index 6e334cb89c9..4db9e3dbf9a 100644 --- a/app-shell-odd/src/notifications/subscribe.ts +++ b/app-shell-odd/src/notifications/subscribe.ts @@ -1,7 +1,11 @@ import mqtt from 'mqtt' import { connectionStore } from './store' -import { sendDeserialized, sendDeserializedGenericError } from './deserialize' +import { + sendDeserialized, + sendDeserializedGenericError, + sendDeserializedRefetch, +} from './deserialize' import { notifyLog } from './notifyLog' import type { NotifyTopic } from '@opentrons/app/src/redux/shell/types' @@ -30,8 +34,8 @@ export function subscribe(topic: NotifyTopic): Promise { if (client == null) { return Promise.reject(new Error('Expected hostData, received null.')) } - - if ( + // The first time the client wants to subscribe on a robot to a particular topic. + else if ( !connectionStore.isActiveSub(topic) && !connectionStore.isPendingSub(topic) ) { @@ -44,13 +48,15 @@ export function subscribe(topic: NotifyTopic): Promise { }) ) .catch((error: Error) => notifyLog.debug(error.message)) - } else { - void waitUntilActiveOrErrored('subscription', topic).catch( - (error: Error) => { + } + // The client is either already subscribed or the subscription is currently pending. + else { + void waitUntilActiveOrErrored('subscription', topic) + .then(() => sendDeserializedRefetch(topic)) + .catch((error: Error) => { notifyLog.debug(error.message) sendDeserializedGenericError(topic) - } - ) + }) } }) .catch((error: Error) => { @@ -74,6 +80,8 @@ export function subscribe(topic: NotifyTopic): Promise { connectionStore .setSubStatus(topic, 'subscribed') .catch((error: Error) => notifyLog.debug(error.message)) + + sendDeserializedRefetch(topic) } } } diff --git a/app-shell/src/notifications/deserialize.ts b/app-shell/src/notifications/deserialize.ts index 53752b32a0f..9743f1c3e5c 100644 --- a/app-shell/src/notifications/deserialize.ts +++ b/app-shell/src/notifications/deserialize.ts @@ -33,6 +33,14 @@ export function sendDeserialized({ } catch {} // Prevents shell erroring during app shutdown event. } +export function sendDeserializedRefetch(ip: string, topic: NotifyTopic): void { + sendDeserialized({ + ip, + topic, + message: { refetch: true }, + }) +} + export function sendDeserializedGenericError( ip: string, topic: NotifyTopic diff --git a/app-shell/src/notifications/subscribe.ts b/app-shell/src/notifications/subscribe.ts index 895a010406e..54ee43d92c6 100644 --- a/app-shell/src/notifications/subscribe.ts +++ b/app-shell/src/notifications/subscribe.ts @@ -1,7 +1,11 @@ import mqtt from 'mqtt' import { connectionStore } from './store' -import { sendDeserialized, sendDeserializedGenericError } from './deserialize' +import { + sendDeserialized, + sendDeserializedGenericError, + sendDeserializedRefetch, +} from './deserialize' import { notifyLog } from './notifyLog' import type { NotifyTopic } from '@opentrons/app/src/redux/shell/types' @@ -36,8 +40,8 @@ export function subscribe(ip: string, topic: NotifyTopic): Promise { if (client == null) { return Promise.reject(new Error('Expected hostData, received null.')) } - - if ( + // The first time the client wants to subscribe on a robot to a particular topic. + else if ( !connectionStore.isActiveSub(robotName, topic) && !connectionStore.isPendingSub(robotName, topic) ) { @@ -50,16 +54,20 @@ export function subscribe(ip: string, topic: NotifyTopic): Promise { }) ) .catch((error: Error) => notifyLog.debug(error.message)) - } else { + } + // The client is either already subscribed or the subscription is currently pending. + else { void waitUntilActiveOrErrored({ connection: 'subscription', ip, robotName, topic, - }).catch((error: Error) => { - notifyLog.debug(error.message) - sendDeserializedGenericError(ip, topic) }) + .then(() => sendDeserializedRefetch(ip, topic)) + .catch((error: Error) => { + notifyLog.debug(error.message) + sendDeserializedGenericError(ip, topic) + }) } }) .catch((error: Error) => { @@ -81,6 +89,8 @@ export function subscribe(ip: string, topic: NotifyTopic): Promise { connectionStore .setSubStatus(ip, topic, 'subscribed') .catch((error: Error) => notifyLog.debug(error.message)) + + sendDeserializedRefetch(ip, topic) } } } diff --git a/app/src/resources/useNotifyService.ts b/app/src/resources/useNotifyService.ts index d8422ba786f..619b797e527 100644 --- a/app/src/resources/useNotifyService.ts +++ b/app/src/resources/useNotifyService.ts @@ -51,7 +51,7 @@ export function useNotifyService({ React.useEffect(() => { if (shouldUseNotifications) { - // Always fetch on initial mount. + // Always fetch on initial mount to keep latency as low as possible. setRefetch('once') appShellListener({ hostname,