On a network share the database copy and cache pre-warm run for minutes, and the listener only opened after all of it, so anyone who loaded the page during that window got a connection error. Open the port immediately after registering the static frontend, and hold every route that needs the database behind a gate that answers 503 with a machine-readable marker and the current startup phase. The SPA shell needs nothing the gate blocks, so the frontend renders a "server is starting" screen on the login page's own background, polls /health, and reloads once the server reports ready. Move the database copy out of the entrypoint: it does the same freshness check the application does, and doing it before node starts kept the port closed for the longest part of startup. Distinguish a dead server from a slow one by requiring the backend's own marker, since a proxy in front of a stopped backend still answers.
42 lines
1.2 KiB
TypeScript
42 lines
1.2 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
|
|
vi.mock('../utils/logger', () => ({
|
|
logger: { info: vi.fn(), error: vi.fn(), debug: vi.fn(), warn: vi.fn() },
|
|
}));
|
|
|
|
import { StartupState } from './StartupState';
|
|
|
|
beforeEach(() => {
|
|
StartupState.reset();
|
|
});
|
|
|
|
describe('StartupState', () => {
|
|
it('starts not ready with an initial phase', () => {
|
|
expect(StartupState.isReady()).toBe(false);
|
|
expect(StartupState.getPhase()).toBe('Starting up');
|
|
});
|
|
|
|
it('reports the current phase while starting', () => {
|
|
StartupState.setPhase('Connecting to the Flashpoint database');
|
|
|
|
expect(StartupState.getPhase()).toBe('Connecting to the Flashpoint database');
|
|
expect(StartupState.isReady()).toBe(false);
|
|
});
|
|
|
|
it('reports ready once startup completes', () => {
|
|
StartupState.setPhase('Warming up game search');
|
|
StartupState.markReady();
|
|
|
|
expect(StartupState.isReady()).toBe(true);
|
|
expect(StartupState.getPhase()).toBe('Ready');
|
|
});
|
|
|
|
it('ignores late phase updates from background work', () => {
|
|
StartupState.markReady();
|
|
StartupState.setPhase('Installing Ruffle');
|
|
|
|
expect(StartupState.isReady()).toBe(true);
|
|
expect(StartupState.getPhase()).toBe('Ready');
|
|
});
|
|
});
|