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

The snapshot store's bounded-retry test proves the deadline by attempts, not by 40 ms of wall-clock slack #3148

Merged opened this

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

Merged

scout/forge:scout/3143-the-snapshot-store-s-bounded-retry-test → main 1 commit fork

  • Merged. scout/3143-the-snapshot-store-s-bounded-retry-test was merged into main as 5919148.

Review

Sign in to review this change.
1 file changed +33 −12
test/snapshot-store.test.ts +33 −12
@@ -190,19 +190,40 @@ describe("the snapshot store, inside a budget", () => {
190190 };
191191 };
192192
193 test("a stalled get with 300 ms left fails within them, not after 5 × 10 s", async () => {
194 const s = stalled();
195 const store = withRetries(s.store, { attempts: 5, baseMs: 10, deadlineMs: 10_000 });
196 const start = performance.now();
197 const until = start + 300;
198 await expect(store.bounded!(() => until - performance.now()).get("snapshots/x/forge.db")).rejects.toThrow(
199 /get snapshots\/x\/forge\.db failed after 5 attempts: no answer in \d+ ms/,
193 test("a stalled get with 300 ms left makes 5 attempts, each within an even share", async () => {
194 // A fake clock the waits advance: nothing here depends on the scheduler.
195 let now = 0;
196 const left: number[] = [];
197 const inner: Store = {
198 ...stalled().store,
199 get: () => {
200 left.push(300 - now);
201 return new Promise<never>(() => {});
202 },
203 };
204 const store = withRetries(inner, {
205 attempts: 5,
206 baseMs: 10,
207 deadlineMs: 10_000,
208 sleep: async (ms) => {
209 now += ms;
210 },
211 });
212 const error = await store
213 .bounded!(() => 300 - now)
214 .get("snapshots/x/forge.db")
215 .catch((e: Error) => e);
216 expect((error as Error).message).toMatch(
217 /^get snapshots\/x\/forge\.db failed after 5 attempts: no answer in \d+ ms$/,
200218 );
201 const took = performance.now() - start;
202 expect(took).toBeLessThan(300 + 40);
203 // Each attempt had an even share: (300 − 150 ms of waits) / 5 ≈ 30 ms.
204 expect(took).toBeGreaterThan(150);
205 expect(s.began.length).toBe(5);
219 expect(left.length).toBe(5);
220 // Waits are 10, 20, 40, 80 ms; attempt n's share is (left − waits to come) / (5 − n).
221 expect(left).toEqual([300, 290, 270, 230, 150]);
222 const waitsAfter = [150, 140, 120, 80, 0];
223 const shares = left.map((l, n) => Math.floor((l - waitsAfter[n]!) / (5 - n)));
224 expect(shares).toEqual([30, 37, 50, 75, 150]);
225 // The last attempt's deadline is the one the error names.
226 expect((error as Error).message).toContain("no answer in 150 ms");
206227 });
207228
208229 test("with nothing left no attempt is made", async () => {

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs