Report the running build's version to the master
The version is the checkout's HEAD commit (short hash + commit time), read once at startup — updates arrive as `git pull`, so there is no release number to bump. It rides on the socket hello, socket reports, and the HTTP report fallback; the field is optional in the protocol so older masters ignore it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
c493796602
commit
38a9c6c1b7
@@ -101,6 +101,13 @@ instance does two things with them: it reports its firm and account counts every
|
||||
30 seconds, and it holds a WebSocket open to `<url>/ws/instance` so the master
|
||||
can drive it.
|
||||
|
||||
Every report also carries this checkout's version — the HEAD commit and its
|
||||
time, since updates arrive as `git pull` and there is no release number to
|
||||
bump. The master shows it in a **Version** column and flags any machine running
|
||||
something older than the newest build in the fleet, which is how you check at a
|
||||
glance that every machine took the last update. An instance showing *old build*
|
||||
predates version reporting entirely.
|
||||
|
||||
What the master can trigger here:
|
||||
|
||||
| | |
|
||||
|
||||
@@ -20,6 +20,7 @@ import { runTrade, startScheduler, stopScheduler, getSchedulerStatus } from './a
|
||||
import { FIRMS, automationKey } from './automations';
|
||||
import { POINT_VALUES } from './trading-logic';
|
||||
import { queueRun } from './queue-run';
|
||||
import { getBuildVersion } from './version';
|
||||
import type {
|
||||
Command,
|
||||
InstanceCapabilities,
|
||||
@@ -161,6 +162,7 @@ export function pushReport(firms: unknown[], scheduler: unknown): boolean {
|
||||
firms: firms as never,
|
||||
scheduler: scheduler as never,
|
||||
capabilities: collectCapabilities(),
|
||||
version: getBuildVersion() ?? undefined,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -226,6 +228,7 @@ function connect() {
|
||||
instance,
|
||||
id: instanceId || undefined,
|
||||
capabilities: collectCapabilities(),
|
||||
version: getBuildVersion() ?? undefined,
|
||||
} satisfies InstanceMessage));
|
||||
});
|
||||
|
||||
|
||||
+10
-2
@@ -87,6 +87,14 @@ export interface SchedulerState {
|
||||
sessionOpenDelayMin?: number;
|
||||
}
|
||||
|
||||
/** The build this instance is running — its checkout's HEAD commit. The
|
||||
* commit time is what orders two different versions. Optional in every
|
||||
* message so an older instance or master simply ignores it. */
|
||||
export interface BuildVersion {
|
||||
commit: string;
|
||||
time: string;
|
||||
}
|
||||
|
||||
export interface AutomationSummary {
|
||||
key: string;
|
||||
label: string;
|
||||
@@ -200,6 +208,6 @@ export type MasterMessage =
|
||||
| { type: 'command'; id: string; command: Command };
|
||||
|
||||
export type InstanceMessage =
|
||||
| { type: 'hello'; instance: string; id?: string; capabilities: InstanceCapabilities }
|
||||
| { type: 'report'; firms: FirmStats[]; scheduler: SchedulerState; capabilities?: InstanceCapabilities }
|
||||
| { type: 'hello'; instance: string; id?: string; capabilities: InstanceCapabilities; version?: BuildVersion }
|
||||
| { type: 'report'; firms: FirmStats[]; scheduler: SchedulerState; capabilities?: InstanceCapabilities; version?: BuildVersion }
|
||||
| { type: 'ack'; id: string; ok: boolean; result?: unknown; error?: string };
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
import { getSetting } from './db';
|
||||
import { pushReport } from './master-link';
|
||||
import { getBuildVersion } from './version';
|
||||
import { getClients } from './clients';
|
||||
import { getTradableFirms } from './firm-catalog';
|
||||
import { getAccountConfig } from './account-type-resolver';
|
||||
@@ -292,6 +293,7 @@ export async function sendReport(): Promise<void> {
|
||||
id: getSetting('instance_id') || undefined,
|
||||
firms,
|
||||
scheduler,
|
||||
version: getBuildVersion() ?? undefined,
|
||||
}),
|
||||
});
|
||||
} catch {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* The version of the running build.
|
||||
*
|
||||
* Updates arrive as `git pull` (scripts/update-check.mjs), so the checkout's
|
||||
* HEAD commit *is* the version — there is no release number to bump and
|
||||
* nothing for anyone to forget. The commit time rides along because hashes
|
||||
* don't order: it is what lets the master say which of two different
|
||||
* versions is the stale one.
|
||||
*
|
||||
* Read once and cached: the update task restarts the process after every
|
||||
* pull, so HEAD cannot move under a running build — and when it briefly does
|
||||
* (pull landed, restart pending), the cached value still describes the code
|
||||
* that is actually executing.
|
||||
*/
|
||||
|
||||
import { execFileSync } from 'node:child_process';
|
||||
|
||||
export interface BuildVersion {
|
||||
/** Short commit hash of HEAD, e.g. "c493796". */
|
||||
commit: string;
|
||||
/** ISO commit time of HEAD — orders versions, which hashes cannot. */
|
||||
time: string;
|
||||
}
|
||||
|
||||
let cached: BuildVersion | null | undefined;
|
||||
|
||||
/** null when this isn't a git checkout or git isn't installed — both mean
|
||||
* "no version to report", and the master shows the machine as an old build. */
|
||||
export function getBuildVersion(): BuildVersion | null {
|
||||
if (cached !== undefined) return cached;
|
||||
try {
|
||||
const out = execFileSync('git', ['log', '-1', '--format=%h %cI'], {
|
||||
cwd: process.cwd(),
|
||||
encoding: 'utf8',
|
||||
stdio: ['ignore', 'pipe', 'ignore'],
|
||||
}).trim();
|
||||
const [commit, time] = out.split(' ');
|
||||
cached = commit && time ? { commit, time } : null;
|
||||
} catch {
|
||||
cached = null;
|
||||
}
|
||||
return cached;
|
||||
}
|
||||
Reference in New Issue
Block a user