mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 21:15:32 +09:00
fix(app): jitter gateway reconnects and recover status nagbar (#2439)
This commit is contained in:
1 parent
b0645300ec
commit
cc3a9c8613
3 files changed
+24
-13
No files matched your search
@@ -86,6 +86,12 @@ export function useConnectionNotice(): ConnectionNotice | null {
|
|||||||
}, BOOT_NOTICE_DELAY_MS);
|
}, BOOT_NOTICE_DELAY_MS);
|
||||||
return () => window.clearTimeout(timer);
|
return () => window.clearTimeout(timer);
|
||||||
}, [booting]);
|
}, [booting]);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!reconnecting) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
StatusPage.refreshForConnectionIssue();
|
||||||
|
}, [reconnecting]);
|
||||||
if (Nagbar.forceHideConnectionNotice) {
|
if (Nagbar.forceHideConnectionNotice) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ const GATEWAY_TIMEOUTS = {
|
|||||||
ResumeWindow: 180000,
|
ResumeWindow: 180000,
|
||||||
MinReconnect: 1000,
|
MinReconnect: 1000,
|
||||||
MaxReconnect: 60000,
|
MaxReconnect: 60000,
|
||||||
|
ReconnectSpread: 2000,
|
||||||
Hello: 20000,
|
Hello: 20000,
|
||||||
} as const;
|
} as const;
|
||||||
export const GatewayState = {
|
export const GatewayState = {
|
||||||
@@ -1034,7 +1035,7 @@ export class GatewaySocket extends EventEmitter<GatewaySocketEvents> {
|
|||||||
}
|
}
|
||||||
const allowImmediate = options.allowImmediate ?? true;
|
const allowImmediate = options.allowImmediate ?? true;
|
||||||
const wasImmediate = allowImmediate && this.shouldReconnectImmediately;
|
const wasImmediate = allowImmediate && this.shouldReconnectImmediately;
|
||||||
const delay = wasImmediate ? 0 : this.nextReconnectDelay();
|
const delay = wasImmediate ? this.reconnectSpread() : this.nextReconnectDelay();
|
||||||
this.shouldReconnectImmediately = false;
|
this.shouldReconnectImmediately = false;
|
||||||
this.log.info(`Scheduling reconnect in ${delay}ms${wasImmediate ? ' (immediate)' : ''}`);
|
this.log.info(`Scheduling reconnect in ${delay}ms${wasImmediate ? ' (immediate)' : ''}`);
|
||||||
this.reconnectTimeoutId = window.setTimeout(() => {
|
this.reconnectTimeoutId = window.setTimeout(() => {
|
||||||
@@ -1047,12 +1048,16 @@ export class GatewaySocket extends EventEmitter<GatewaySocketEvents> {
|
|||||||
}, delay);
|
}, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private reconnectSpread(): number {
|
||||||
|
return Math.floor(Math.random() * GATEWAY_TIMEOUTS.ReconnectSpread);
|
||||||
|
}
|
||||||
|
|
||||||
private nextReconnectDelay(): number {
|
private nextReconnectDelay(): number {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const elapsed = now - this.lastReconnectAt;
|
const elapsed = now - this.lastReconnectAt;
|
||||||
if (elapsed < GATEWAY_TIMEOUTS.MinReconnect) {
|
if (elapsed < GATEWAY_TIMEOUTS.MinReconnect) {
|
||||||
this.log.debug(`Last reconnect ${elapsed}ms ago, enforcing minimum delay (${GATEWAY_TIMEOUTS.MinReconnect}ms)`);
|
this.log.debug(`Last reconnect ${elapsed}ms ago, enforcing minimum delay (${GATEWAY_TIMEOUTS.MinReconnect}ms)`);
|
||||||
return GATEWAY_TIMEOUTS.MinReconnect;
|
return GATEWAY_TIMEOUTS.MinReconnect + this.reconnectSpread();
|
||||||
}
|
}
|
||||||
this.lastReconnectAt = now;
|
this.lastReconnectAt = now;
|
||||||
const delay = this.reconnectBackoff.next();
|
const delay = this.reconnectBackoff.next();
|
||||||
|
|||||||
@@ -90,7 +90,11 @@ const POLL_ACTIVE_MAINTENANCE_JITTER_MS = 15 * 1000;
|
|||||||
const POLL_AFTER_MAINTENANCE_START_MS = 5 * 1000;
|
const POLL_AFTER_MAINTENANCE_START_MS = 5 * 1000;
|
||||||
const POLL_MIN_DELAY_MS = 10 * 1000;
|
const POLL_MIN_DELAY_MS = 10 * 1000;
|
||||||
const POLL_RESUME_STALE_MS = 30 * 1000;
|
const POLL_RESUME_STALE_MS = 30 * 1000;
|
||||||
const STATUS_PAGE_FETCH_OPTIONS: RequestInit = {cache: 'no-store'};
|
const STATUS_PAGE_FETCH_TIMEOUT_MS = 10 * 1000;
|
||||||
|
|
||||||
|
function statusPageFetchOptions(): RequestInit {
|
||||||
|
return {cache: 'no-store', signal: AbortSignal.timeout(STATUS_PAGE_FETCH_TIMEOUT_MS)};
|
||||||
|
}
|
||||||
|
|
||||||
export function computePollDelay(scheduledMaintenance: StatusPageMaintenance | null): number {
|
export function computePollDelay(scheduledMaintenance: StatusPageMaintenance | null): number {
|
||||||
if (scheduledMaintenance?.status === 'in_progress') {
|
if (scheduledMaintenance?.status === 'in_progress') {
|
||||||
@@ -256,12 +260,8 @@ export class StatusPage {
|
|||||||
|
|
||||||
private async fetchIncidents(): Promise<void> {
|
private async fetchIncidents(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${ExternalUrls.SERVICE_STATUS}/summary.json`, STATUS_PAGE_FETCH_OPTIONS);
|
const response = await fetch(`${ExternalUrls.SERVICE_STATUS}/summary.json`, statusPageFetchOptions());
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
runInAction(() => {
|
|
||||||
this.incident = null;
|
|
||||||
this.scheduledMaintenance = null;
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const data: InstatusSummary = await response.json();
|
const data: InstatusSummary = await response.json();
|
||||||
@@ -296,16 +296,12 @@ export class StatusPage {
|
|||||||
});
|
});
|
||||||
} catch {
|
} catch {
|
||||||
logger.warn('Failed to fetch status page');
|
logger.warn('Failed to fetch status page');
|
||||||
runInAction(() => {
|
|
||||||
this.incident = null;
|
|
||||||
this.scheduledMaintenance = null;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async fetchComponentMaintenances(): Promise<Array<InstatusMaintenance>> {
|
private async fetchComponentMaintenances(): Promise<Array<InstatusMaintenance>> {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${ExternalUrls.SERVICE_STATUS}/components.json`, STATUS_PAGE_FETCH_OPTIONS);
|
const response = await fetch(`${ExternalUrls.SERVICE_STATUS}/components.json`, statusPageFetchOptions());
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -321,6 +317,10 @@ export class StatusPage {
|
|||||||
this.incident = null;
|
this.incident = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
refreshForConnectionIssue(): void {
|
||||||
|
this.refreshIfStale();
|
||||||
|
}
|
||||||
|
|
||||||
private async refreshAndReschedule(): Promise<void> {
|
private async refreshAndReschedule(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await this.checkIncidents();
|
await this.checkIncidents();
|
||||||
|
|||||||
Reference in new issue
Block a user