Answer the review: send the worker one request at a time, keep only the latest, and never wait for a dead one
The adversarial review confirmed three defects in this PR, all reproduced in the browser. 1. Superseded graphs queued up in front of routes. The worker answers messages one at a time and cannot drop one it has started. With the jump-link layer on, every pause on the range slider posted a full graph build, seconds of work at 6-8 pc. Answers no longer wanted were thrown away only once built. A route asked for afterwards waited behind every one of them: a one-jump route took 44 s. RoutingClient now holds requests and sends them one at a time. While one is out, only the latest of each kind waits: a newer graph replaces an older one before it is ever built, and the older promise is rejected with SupersededRequest. Routes go ahead of graphs. The same question asked again while outstanding shares the answer rather than being worked twice, as when the layer is turned off and on during a build. The same scenario in the browser (layer on, range stepped 5 -> 8 pc with 400 ms pauses, then Sol to Proxima): the route came back in 110 ms. The worker was sent "links 3, links 5, route, links 8"; 6 and 7 were never built. 2. A worker that failed left the panel stuck. With no error handling, a worker that failed to load (a 404 on its chunk after a redeploy) or threw left "Plotting…" and a disabled button for good, and a graph at a range could not be asked for again. The worker now answers an exception with a 'failed' message, which rejects that request. A worker that fails to load or dies is abandoned, and what it left outstanding, and everything asked afterwards, is answered in place. The scene releases the panel when a route fails, and forgets a graph range that was never drawn so it can be asked for again. 3. Nothing type-checked the worker. The application builder never reads webWorkerTsConfig, and bundles the worker with esbuild, which strips types without checking them. tsconfig.app.json leaves the file out. A type error in the worker shipped. `npm run worker:typecheck` (tsc -p tsconfig.worker.json) now runs in CI beside the other project checks. webWorkerTsConfig is removed from angular.json, since it only suggested that something checked the worker. Tests with a fake worker cover one request at a time, a waiting graph replaced and a route sent ahead of it, a question shared, a failure rejected and the next request sent, and a failed worker's requests answered in place. A scene test covers the panel released after a failed route. Negative controls, each caught: several requests sent at once, a waiting graph kept, graphs ahead of routes, a question asked twice, a failure answered as a success, a failed worker waited on, the panel left pending, and a type error in the worker (caught by worker:typecheck). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jxMkwA2rbicdGxHosecYi
This commit is contained in:
@@ -294,6 +294,23 @@ describe('GalaxySystemSceneComponent camera-flight transitions', () => {
|
||||
expect(component.routePending()).toBe(false);
|
||||
});
|
||||
|
||||
it('releases the routes panel when a route cannot be worked out, so it can be tried again', async () => {
|
||||
const component = fixture.componentInstance as unknown as {
|
||||
routing: { route(): Promise<never>; links(): Promise<Float32Array>; dispose(): void };
|
||||
routePending(): boolean;
|
||||
onRouteRequested(request: { fromId: number; toId: number; rangePc: number }): void;
|
||||
};
|
||||
const logged = vi.spyOn(console, 'error').mockImplementation(() => undefined);
|
||||
component.routing = { route: () => Promise.reject(new Error('worker gone')), links: () => Promise.resolve(new Float32Array(0)), dispose: () => undefined };
|
||||
|
||||
component.onRouteRequested({ fromId: SUN.id, toId: PROXIMA.id, rangePc: 2 });
|
||||
await flushAsync();
|
||||
|
||||
expect(component.routePending()).toBe(false);
|
||||
expect(logged).toHaveBeenCalled();
|
||||
logged.mockRestore();
|
||||
});
|
||||
|
||||
it('asks for no more label candidates once the last label it will show is placed', () => {
|
||||
// Near the Sun a label candidate past the fifteenth can sit at the far end of the catalogue's
|
||||
// brightness order, so asking for one more than is used can cost a walk of the whole order.
|
||||
|
||||
Reference in New Issue
Block a user