auto-read after the rebase: results through usable / failureText, issuesError notice kept, scheduler 'accounts' (no credentials word in the webview), fixtures and generated tables for health_issue
This commit is contained in:
parent
0fb4ce0001
commit
7b05e4b396
8 changed files with 34 additions and 27 deletions
|
|
@ -36,7 +36,7 @@ const flush = async () => { for (let i = 0; i < 10; i++) await Promise.resolve()
|
|||
function controlled() {
|
||||
const runs: { key: string; done: (v: unknown) => void; fail: (e: unknown) => void }[] = [];
|
||||
const task = (key: string, o: Partial<ReadTask<unknown>> = {}): ReadTask<unknown> => ({
|
||||
key, lanes: ['apple'], credentials: ['apple:k1'], priority: 2, ...o,
|
||||
key, lanes: ['apple'], accounts: ['apple:k1'], priority: 2, ...o,
|
||||
run: () => new Promise((done, fail) => { runs.push({ key, done, fail }); }),
|
||||
});
|
||||
return { runs, task };
|
||||
|
|
@ -48,8 +48,8 @@ describe('ReadScheduler', () => {
|
|||
const s = new ReadScheduler({ clock, spacingMs: 0, limits: { apple: 2, play: 1 } });
|
||||
const { runs, task } = controlled();
|
||||
for (const k of ['a', 'b', 'c', 'd']) s.enqueue(task(k)).catch(() => {});
|
||||
s.enqueue(task('p1', { lanes: ['play'], credentials: ['play:k'] })).catch(() => {});
|
||||
s.enqueue(task('p2', { lanes: ['play'], credentials: ['play:k'] })).catch(() => {});
|
||||
s.enqueue(task('p1', { lanes: ['play'], accounts: ['play:k'] })).catch(() => {});
|
||||
s.enqueue(task('p2', { lanes: ['play'], accounts: ['play:k'] })).catch(() => {});
|
||||
await clock.advance(0);
|
||||
expect(runs.map(r => r.key)).toEqual(['a', 'b', 'p1']);
|
||||
expect(s.stats()).toMatchObject({ running: 3, queued: 3, total: 6 });
|
||||
|
|
@ -60,8 +60,8 @@ describe('ReadScheduler', () => {
|
|||
const both = new ReadScheduler({ clock, spacingMs: 0, limits: { apple: 1, play: 1 } });
|
||||
const c2 = controlled();
|
||||
both.enqueue(c2.task('apple-only')).catch(() => {});
|
||||
both.enqueue(c2.task('both', { lanes: ['apple', 'play'], credentials: [] })).catch(() => {});
|
||||
both.enqueue(c2.task('play-only', { lanes: ['play'], credentials: [] })).catch(() => {});
|
||||
both.enqueue(c2.task('both', { lanes: ['apple', 'play'], accounts: [] })).catch(() => {});
|
||||
both.enqueue(c2.task('play-only', { lanes: ['play'], accounts: [] })).catch(() => {});
|
||||
await clock.advance(0);
|
||||
expect(c2.runs.map(r => r.key)).toEqual(['apple-only', 'play-only']);
|
||||
});
|
||||
|
|
@ -100,12 +100,12 @@ describe('ReadScheduler', () => {
|
|||
expect(runs).toHaveLength(2);
|
||||
});
|
||||
|
||||
test('starts on one credential are spaced; other credentials are not held up', async () => {
|
||||
test('starts on one credential are spaced; other accounts are not held up', async () => {
|
||||
const clock = new FakeClock();
|
||||
const s = new ReadScheduler({ clock, spacingMs: 400, limits: { apple: 8 } });
|
||||
const { runs, task } = controlled();
|
||||
for (const k of ['a', 'b', 'c']) s.enqueue(task(k)).catch(() => {});
|
||||
s.enqueue(task('other', { credentials: ['apple:k2'] })).catch(() => {});
|
||||
s.enqueue(task('other', { accounts: ['apple:k2'] })).catch(() => {});
|
||||
await clock.advance(0);
|
||||
expect(runs.map(r => r.key)).toEqual(['a', 'other']);
|
||||
await clock.advance(399);
|
||||
|
|
@ -122,10 +122,10 @@ describe('ReadScheduler', () => {
|
|||
const classify = (r: unknown): Outcome => ({ throttled: (r as { status: number }).status === 429 });
|
||||
const s = new ReadScheduler({ clock, spacingMs: 0, backoffBaseMs: 1000, backoffMaxMs: 60_000, maxAttempts: 4, classify });
|
||||
const starts: number[] = [];
|
||||
const p = s.enqueue({ key: 'x', lanes: ['play'], credentials: ['play:k'], priority: 0, run: async () => { starts.push(clock.now()); attempts++; return { status: attempts < 3 ? 429 : 200 }; } });
|
||||
const p = s.enqueue({ key: 'x', lanes: ['play'], accounts: ['play:k'], priority: 0, run: async () => { starts.push(clock.now()); attempts++; return { status: attempts < 3 ? 429 : 200 }; } });
|
||||
let other = false;
|
||||
await clock.advance(0);
|
||||
s.enqueue({ key: 'y', lanes: ['play'], credentials: ['play:k'], priority: 2, run: async () => { other = true; return { status: 200 }; } }).catch(() => {});
|
||||
s.enqueue({ key: 'y', lanes: ['play'], accounts: ['play:k'], priority: 2, run: async () => { other = true; return { status: 200 }; } }).catch(() => {});
|
||||
await clock.advance(0);
|
||||
// first try at 0; jitter (rand 0.5) -> 0.75 x the exponential step: 750 ms, then 1500 ms
|
||||
expect(starts).toEqual([0]);
|
||||
|
|
@ -143,7 +143,7 @@ describe('ReadScheduler', () => {
|
|||
// always 429: resolved with the last answer after maxAttempts, counted as failed
|
||||
const s2 = new ReadScheduler({ clock, spacingMs: 0, backoffBaseMs: 10, maxAttempts: 3, classify });
|
||||
let n = 0;
|
||||
const q = s2.enqueue({ key: 'z', lanes: ['play'], credentials: ['play:k'], priority: 0, run: async () => { n++; return { status: 429 }; } });
|
||||
const q = s2.enqueue({ key: 'z', lanes: ['play'], accounts: ['play:k'], priority: 0, run: async () => { n++; return { status: 429 }; } });
|
||||
await clock.advance(1000);
|
||||
expect(await q).toEqual({ status: 429 });
|
||||
expect(n).toBe(3);
|
||||
|
|
@ -152,11 +152,11 @@ describe('ReadScheduler', () => {
|
|||
test('App Store Connect quota: spreads the rest of the hour when it runs low, pauses at the reserve', async () => {
|
||||
const clock = new FakeClock();
|
||||
let remaining = 3412;
|
||||
const classify = (_r: unknown, _e: unknown, t: ReadTask<unknown>): Outcome => ({ quota: { credential: t.credentials[0]!, limit: 3600, remaining } });
|
||||
const classify = (_r: unknown, _e: unknown, t: ReadTask<unknown>): Outcome => ({ quota: { credential: t.accounts[0]!, limit: 3600, remaining } });
|
||||
const s = new ReadScheduler({ clock, spacingMs: 100, reserve: 100, slowBelow: 0.2, pauseMs: 600_000, limits: { apple: 4 }, classify });
|
||||
const starts: number[] = [];
|
||||
const run = async () => { starts.push(clock.now()); return {}; };
|
||||
const add = (k: string) => s.enqueue({ key: k, lanes: ['apple'], credentials: ['apple:k1'], priority: 2, run }).catch(() => {});
|
||||
const add = (k: string) => s.enqueue({ key: k, lanes: ['apple'], accounts: ['apple:k1'], priority: 2, run }).catch(() => {});
|
||||
add('a'); add('b');
|
||||
await clock.advance(0);
|
||||
await clock.advance(100);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue