feat: F5.6c measured and accepted on test-filius; tickets up to 5 s ahead of F's clock
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>
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
// M5 on a live server F: does a WebSocket through the openresty hold an hour?
|
||||
// One person in a fresh project, with /sync (the document) and /sim (the
|
||||
// room) open and nothing to say — the proxy's limit is between two bytes,
|
||||
// so only the pings of F (/sim, 30 s) and Hocuspocus (/sync) keep them. Every
|
||||
// five minutes a line; at the end a probe through /sim and a change through
|
||||
// /sync, to show that both still carry.
|
||||
//
|
||||
// npx vite-node tools/live/m5.ts [minutes]
|
||||
|
||||
import { cleanUp, joinDoc, newProject, openRoom, signIn } from './lib.js';
|
||||
|
||||
const minutes = Number(process.argv[2] ?? 65);
|
||||
const started = Date.now();
|
||||
const elapsed = () => `${((Date.now() - started) / 60_000).toFixed(1)} min`;
|
||||
try {
|
||||
const project = await newProject();
|
||||
const cookie = await signIn(project, { name: 'Dauer' });
|
||||
const shared = await joinDoc(project, cookie);
|
||||
const room = await openRoom(project, cookie);
|
||||
let syncClosed = '';
|
||||
shared.provider.on('close', ({ event }: { event: { code: number; reason: string } }) => (syncClosed ||= `${event.code} ${event.reason} at ${elapsed()}`));
|
||||
let simClosed = '';
|
||||
void room.closed.then((reason) => (simClosed = `${reason} at ${elapsed()}`));
|
||||
console.log(`open: /sync and /sim, holding ${minutes} min`);
|
||||
for (let minute = 5; minute <= minutes; minute += 5) {
|
||||
await new Promise((resolve) => setTimeout(resolve, Math.min(5, minutes - minute + 5) * 60_000));
|
||||
console.log(`${elapsed()}: /sync ${syncClosed || 'open'}, /sim ${simClosed || 'open'}`);
|
||||
}
|
||||
room.send({ kind: 'input', node: 'probe', app: 'terminal', action: 'enter', args: { line: '' }, reqId: 'last' });
|
||||
const answer = await room
|
||||
.waitFor((message) => message.reqId === 'last', 10_000)
|
||||
.then(
|
||||
() => 'answered',
|
||||
() => 'no answer',
|
||||
);
|
||||
shared.doc.getMap('meta').set('m5', Date.now());
|
||||
const stored = await new Promise<string>((resolve) => {
|
||||
const end = Date.now() + 10_000;
|
||||
const look = () => (shared.provider.unsyncedChanges === 0 ? resolve('stored') : Date.now() > end ? resolve('not stored') : setTimeout(look, 50));
|
||||
look();
|
||||
});
|
||||
console.log(`after ${elapsed()}: /sim probe ${answer}, /sync change ${stored}; closed: /sync ${syncClosed || 'never'}, /sim ${simClosed || 'never'}`);
|
||||
room.close();
|
||||
shared.close();
|
||||
} finally {
|
||||
await cleanUp();
|
||||
}
|
||||
Reference in New Issue
Block a user