Private
Public Access
Trigger update checks off WS reconnect, not just the hourly poll (#42)
A backend restart during a deploy kills every open WebSocket, and the chat socket's existing reconnect-with-backoff already re-fires onopen within seconds -- reuse that as a reliable "the server just restarted" signal to check for a new service worker version, instead of waiting up to an hour for UpdateBanner's poll. The hourly poll stays as a fallback. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { useRegisterSW } from 'virtual:pwa-register/react'
|
||||
import { checkForUpdate, setSwRegistration } from '../lib/swUpdate'
|
||||
import './UpdateBanner.css'
|
||||
|
||||
// The service worker (registerType: 'prompt', sw.ts) already installs and
|
||||
@@ -6,7 +7,11 @@ import './UpdateBanner.css'
|
||||
// never navigates, and a page only checks for a new SW on navigation by
|
||||
// default, so a tab left open for hours could sit on a stale check
|
||||
// indefinitely. This polls explicitly so "reload available" shows up
|
||||
// without the user having to close and reopen the app first.
|
||||
// without the user having to close and reopen the app first. It's now a
|
||||
// fallback, not the primary trigger -- useChatSocket.ts also calls
|
||||
// checkForUpdate() on every WS reconnect, which reliably fires within
|
||||
// seconds of a deploy (the backend restart that ships a new version also
|
||||
// kills every open WS connection) rather than waiting up to an hour.
|
||||
const UPDATE_CHECK_INTERVAL_MS = 60 * 60 * 1000
|
||||
|
||||
export function UpdateBanner() {
|
||||
@@ -16,7 +21,8 @@ export function UpdateBanner() {
|
||||
} = useRegisterSW({
|
||||
onRegisteredSW(_url, registration) {
|
||||
if (!registration) return
|
||||
setInterval(() => registration.update(), UPDATE_CHECK_INTERVAL_MS)
|
||||
setSwRegistration(registration)
|
||||
setInterval(checkForUpdate, UPDATE_CHECK_INTERVAL_MS)
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// Bridges the service worker registration (owned by UpdateBanner, which
|
||||
// mounts outside ChatSocketProvider -- see App.tsx) out to code that has no
|
||||
// other way to reach it, namely useChatSocket.ts's reconnect handler, which
|
||||
// wants to trigger an update check whenever the WS reconnects (a reliable
|
||||
// signal the backend just restarted, i.e. a deploy happened).
|
||||
let registration: ServiceWorkerRegistration | null = null
|
||||
|
||||
export function setSwRegistration(reg: ServiceWorkerRegistration): void {
|
||||
registration = reg
|
||||
}
|
||||
|
||||
export function checkForUpdate(): void {
|
||||
void registration?.update()
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { checkForUpdate } from '../lib/swUpdate'
|
||||
import type { ServerEnvelope } from '../types'
|
||||
|
||||
interface UseChatSocketOptions {
|
||||
@@ -42,6 +43,13 @@ export function useChatSocket({ onUnauthenticated }: UseChatSocketOptions) {
|
||||
let stopped = false
|
||||
let reconnectDelay = RECONNECT_BASE_DELAY_MS
|
||||
let reconnectTimer: ReturnType<typeof setTimeout> | null = null
|
||||
// False only for the very first connect() of this effect's lifetime --
|
||||
// every connect() after that was triggered by onclose's retry logic,
|
||||
// i.e. this is a genuine reconnect. A reconnect reliably means the
|
||||
// backend process just restarted (a deploy kills every open WS), so
|
||||
// it's used as the trigger for an out-of-band SW update check instead
|
||||
// of waiting on UpdateBanner's hourly poll -- see lib/swUpdate.ts.
|
||||
let hasConnectedBefore = false
|
||||
|
||||
function connect() {
|
||||
const protocol = location.protocol === 'https:' ? 'wss' : 'ws'
|
||||
@@ -56,6 +64,8 @@ export function useChatSocket({ onUnauthenticated }: UseChatSocketOptions) {
|
||||
// socket's callbacks can stomp on state that the second (real)
|
||||
// socket already owns.
|
||||
if (socketRef.current !== ws) return
|
||||
if (hasConnectedBefore) checkForUpdate()
|
||||
hasConnectedBefore = true
|
||||
reconnectDelay = RECONNECT_BASE_DELAY_MS
|
||||
setConnected(true)
|
||||
// Re-join whatever rooms were joined before a reconnect -- the
|
||||
|
||||
Reference in New Issue
Block a user