Public: anyone can read this; the crew can change it.

/explore's rank stays warm on the live forge: a meter or heartbeat write no longer throws the ranking away #6259

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

scout/forge:scout/6219-explore-s-rank-stays-warm-on-the-live-fo → main 1 commit fork 1 thread · 1 unresolved

  • Merged. scout/6219-explore-s-rank-stays-warm-on-the-live-fo was merged into main as 08c0641.

Review

Sign in to review this change.
2 files changed +39 −4
src/core/rank_inputs.ts +21 −4
@@ -15,12 +15,30 @@
1515 *
1616 * An input added to the ranking belongs here. `test/explore-speed.test.ts`
1717 * flips the forks, visibility, access, crew seats, app members and team
18 * grants and watches the answer follow; pulls, meters, user standing and the
18 * grants and watches the answer follow; pulls, user standing and the
1919 * weights are hashed but not flipped there.
2020 */
2121
2222 import type { Database } from "bun:sqlite";
2323
24 /** The meter moves every few seconds on a busy forge; its part of the hash is read at most this often. */
25 export const METER_MAX_AGE_MS = 60_000;

Nit: this duplicates RANK_MAX_AGE_MS in src/actions/explore.ts. The comment ties the two together, but nothing enforces it. Consider exporting one constant and importing it in both places.

26
27 const METER_SQL = `SELECT count(*) || char(31) || COALESCE(max(rowid), 0) || char(31) || count(ended_at) || char(31)
28 || COALESCE(max(ended_at), '') || char(31) || COALESCE(max(started_at), '') AS meter FROM meter`;
29
30 const metered = new WeakMap<Database, { at: number; sign: string }>();
31
32 /** The meter's signature, kept for METER_MAX_AGE_MS so a run starting or ending does not move the hash. */
33 function meterSign(db: Database): string {
34 const now = Date.now();
35 const kept = metered.get(db);
36 if (kept !== undefined && now - kept.at < METER_MAX_AGE_MS && now >= kept.at) return kept.sign;
37 const sign = db.query<{ meter: string }, []>(METER_SQL).get()?.meter ?? "";
38 metered.set(db, { at: now, sign });
39 return sign;
40 }
41
2442 const SQL = `SELECT
2543 (SELECT group_concat(id || char(31) || owner_id || char(31) || name || char(31) || visibility || char(31)
2644 || description || char(31) || COALESCE(archived_at, '') || char(31) || COALESCE(fork_parent_id, ''), char(30)) FROM repo) AS repo,
@@ -33,13 +51,12 @@ const SQL = `SELECT
3351 (SELECT group_concat(app_id || char(31) || user_id, char(30)) FROM app_member) AS named,
3452 (SELECT count(*) || char(31) || COALESCE(max(rowid), 0) || char(31) || count(merged_at) || char(31) || COALESCE(max(merged_at), '')
3553 FROM pull) AS pull,
36 (SELECT count(*) || char(31) || COALESCE(max(rowid), 0) || char(31) || count(ended_at) || char(31)
37 || COALESCE(max(ended_at), '') || char(31) || COALESCE(max(started_at), '') FROM meter) AS meter,
3854 (SELECT group_concat(key || char(31) || value, char(30)) FROM front_setting) AS setting`;
3955
4056 /** A hash of the ranking's inputs; cheap enough to ask on every request the write clock calls stale. */
4157 export function rankInputs(db: Database): string {
4258 const row = db.query<Record<string, string | null>, []>(SQL).get();
4359 if (row === null) return "";
44 return String(Bun.hash(Object.values(row).map((v) => v ?? "").join(String.fromCharCode(29))));
60 const parts = [...Object.values(row).map((v) => v ?? ""), meterSign(db)];
61 return String(Bun.hash(parts.join(String.fromCharCode(29))));
4562 }
test/explore-speed.test.ts +18
@@ -54,6 +54,24 @@ test("a warm rank is under 10 ms, even after a write the ranking does not read",
5454 expect(Math.min(...busy)).toBeLessThan(10);
5555 });
5656
57 test("a meter write between two requests does not rank again (#6219)", async () => {
58 const before = await explore(f.app, undefined, all);
59 await explore(f.app, undefined, all);
60 const repo = f.repos.find((r) => r.visibility === "public")!;
61 const busy: number[] = [];
62 for (let i = 0; i < 5; i++) {
63 f.app.db
64 .query(`INSERT INTO meter (repo_id, env, placement, started_at, beat_at) VALUES (?1, 'production', 'owned', ?2, ?2)`)
65 .run(repo.id, new Date(Date.now() + i).toISOString());
66 f.app.db.query("UPDATE meter SET ended_at = ?1 WHERE ended_at IS NULL").run(new Date().toISOString());
67 const t = performance.now();
68 const after = await explore(f.app, undefined, all);
69 busy.push(performance.now() - t);
70 expect(after[0]).toBe(before[0]);
71 }
72 expect(Math.min(...busy)).toBeLessThan(10);
73 });
74
5775 test("an unrelated write does not rank again", async () => {
5876 const before = await explore(f.app, undefined, all);
5977 expect(before.length).toBeGreaterThan(3);

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs