mirror of
https://github.com/Crosstalk-Solutions/project-nomad.git
synced 2026-10-16 21:00:03 +02:00
Benchmarks execute as a BullMQ job in the queue worker, but /api/benchmark/status and the 409 double-run guards read the web process's in-memory BenchmarkService, which never sees the run. Status always read idle, and a second POST /api/benchmark/run was accepted mid-flight and queued behind the first. Status now comes from the queue, the one place both processes can see. The worker publishes each stage on its job via job.updateProgress(), and resolveBenchmarkStatus() reports the active job's stage, "starting" for a job still queued, or the local status for a sync=true run. The status endpoint and all three run guards read it. If the queue can't be read they fall back to the local status, as before. Closes #1326
39 lines
1.8 KiB
TypeScript
39 lines
1.8 KiB
TypeScript
import type { BenchmarkStatus } from '../../types/benchmark.js'
|
|
|
|
/** A benchmark job still in the queue, as RunBenchmarkJob.getInFlight() reports it. */
|
|
export interface InFlightBenchmark {
|
|
state: 'active' | 'waiting' | 'delayed'
|
|
benchmarkId: string | null
|
|
/** The job's BullMQ progress; the worker writes `{ status }` into it at every stage. */
|
|
progress: unknown
|
|
}
|
|
|
|
const NOT_RUNNING: ReadonlySet<BenchmarkStatus> = new Set(['idle', 'completed', 'error'])
|
|
|
|
/**
|
|
* Decide the current benchmark status from the queue.
|
|
*
|
|
* Benchmarks run in the queue worker, so the web process's BenchmarkService
|
|
* never sees them and its in-memory status always reads idle (#1326). The queue
|
|
* is the one place both processes can see: a job that is active or still
|
|
* waiting means a run is in flight, and the worker reports its stage through
|
|
* the job's progress. `local` is the web process's own status, which is only
|
|
* ever non-idle for a `sync=true` run executing in this process.
|
|
*/
|
|
export function resolveBenchmarkStatus(
|
|
inFlight: InFlightBenchmark[],
|
|
local: { status: BenchmarkStatus; benchmarkId: string | null }
|
|
): { status: BenchmarkStatus; benchmarkId: string | null } {
|
|
const active = inFlight.find((j) => j.state === 'active')
|
|
if (active) {
|
|
const reported = (active.progress as { status?: BenchmarkStatus } | null)?.status
|
|
// Before the worker's first stage update, or in the moment between it reporting
|
|
// `completed` and the job leaving the active set, the run is still in flight
|
|
const status = reported && !NOT_RUNNING.has(reported) ? reported : 'starting'
|
|
return { status, benchmarkId: active.benchmarkId }
|
|
}
|
|
const queued = inFlight.find((j) => j.state === 'waiting' || j.state === 'delayed')
|
|
if (queued) return { status: 'starting', benchmarkId: queued.benchmarkId }
|
|
return local
|
|
}
|