test-filius refused every ticket as from the future: its clock was 886 ms behind the dashboard's machine, with NTP still 8 ms (one ticket in 125, as a ticket carries whole seconds). F now takes a ticket signed up to 5 s ahead (TICKET_AHEAD_SECONDS); itsdangerous refuses one second, and the oracle keeps that on record. tools/live measures and accepts on a live F, with fresh projects each run: m3 (200 rooms of the largest example with pings: probe p95 37 ms), m4 (63 KB document; dragging makes an update per pointer move, 59/s), m5 (an hour through the proxy), acceptance (two browsers, 14 checks, passed three times) and clock (F's clock against ours). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
29 lines
1.2 KiB
JavaScript
29 lines
1.2 KiB
JavaScript
// How far server F's clock is from this machine's: the moment F's Date header
|
|
// turns to the next second, against our clock at that moment (the middle of
|
|
// the two requests around it). A ticket carries whole seconds, and F refuses
|
|
// one from its future, so F must not be behind the dashboard's machine.
|
|
//
|
|
// node tools/live/clock.mjs [host] [port]
|
|
import http from 'node:http';
|
|
const [host = '172.22.0.38', port = '8081'] = process.argv.slice(2);
|
|
const agent = new http.Agent({ keepAlive: true, maxSockets: 1 });
|
|
const ask = () =>
|
|
new Promise((resolve, reject) => {
|
|
const sent = Date.now();
|
|
http
|
|
.get({ host, port, path: '/healthz', agent }, (r) => {
|
|
r.resume();
|
|
r.on('end', () => resolve({ sent, got: Date.now(), date: Date.parse(r.headers.date) }));
|
|
})
|
|
.on('error', reject);
|
|
});
|
|
let last = await ask();
|
|
const offsets = [];
|
|
for (const end = Date.now() + 6000; Date.now() < end;) {
|
|
const now = await ask();
|
|
if (now.date !== last.date) offsets.push(Math.round(now.date - (last.got + now.sent) / 2) + `±${Math.ceil((now.sent - last.got) / 2)}`);
|
|
last = now;
|
|
}
|
|
agent.destroy();
|
|
console.log(`${host}:${port} clock minus ours (ms): ${offsets.join(' ')}`);
|