mirror of
https://github.com/screentinker/screentinker.git
synced 2026-08-13 13:53:12 -06:00
fix(#146) P1.2: band-aware download caps — serve freely when healthy
A fixed OTA_DOWNLOAD_MAX_CONCURRENT=10 throttled a legitimate coordinated rollout even on a perfectly healthy server, and a shed 503 costs a client a full ~30-min re-check cycle. Made the download guard's concurrency + rate caps band-aware: - normal -> serve FREELY (no cap): a whole-fleet rollout isn't staggered when healthy - elevated -> the configured caps engage (early backpressure) - critical -> shed 503 (the real protection, unchanged) Kill switch OTA_DOWNLOAD_GUARD_ENABLED=false disables it entirely. Tests updated: normal serves 50/50 with 0 shed; caps + shed now asserted under elevated; storm harness OTA flood runs under elevated (the loaded state). Suite green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d4b2532c9a
commit
067aebfd75
|
|
@ -182,6 +182,7 @@ module.exports = {
|
|||
// the fleet to one IP). Concurrency + rate caps + critical-band shed protect the loop
|
||||
// and IO from a download flood; the aggregate counter makes a flood VISIBLE (the old
|
||||
// per-IP-per-10min log throttle hid it under SNAT).
|
||||
otaDownloadGuardEnabled: process.env.OTA_DOWNLOAD_GUARD_ENABLED !== 'false', // #146 P1.3 kill switch
|
||||
otaDownloadMaxConcurrent: parseInt(process.env.OTA_DOWNLOAD_MAX_CONCURRENT) || 10,
|
||||
otaDownloadMaxPerWindow: parseInt(process.env.OTA_DOWNLOAD_MAX_PER_WINDOW) || 120,
|
||||
otaDownloadWindowMs: parseInt(process.env.OTA_DOWNLOAD_WINDOW_MS) || 60000,
|
||||
|
|
|
|||
|
|
@ -12,17 +12,29 @@ function newState() { return { inFlight: 0, windowStart: 0, windowCount: 0, serv
|
|||
// admit(state, band, now) -> { allow, status?, retryAfter?, summary? }
|
||||
// summary (when a window just rolled) = { served, shed } to log, else null.
|
||||
// NEVER takes an IP — admission is global by construction.
|
||||
//
|
||||
// #146 P1.2: caps are BAND-AWARE — a LOAD-TIME backstop, not a healthy-state limiter.
|
||||
// - normal : serve FREELY (no concurrency/rate cap) so a coordinated rollout of the
|
||||
// whole fleet isn't staggered while the server is perfectly healthy.
|
||||
// - elevated : the configured concurrency/rate caps engage (early backpressure).
|
||||
// - critical : shed (503) — the real protection.
|
||||
// Kill switch: OTA_DOWNLOAD_GUARD_ENABLED=false disables everything (always allow).
|
||||
function admit(state, band, now = Date.now()) {
|
||||
let summary = null;
|
||||
if (now - state.windowStart >= config.otaDownloadWindowMs) {
|
||||
if (state.served || state.shed) summary = { served: state.served, shed: state.shed, inFlight: state.inFlight };
|
||||
state.windowStart = now; state.windowCount = 0; state.served = 0; state.shed = 0;
|
||||
}
|
||||
const overGlobal = state.inFlight >= config.otaDownloadMaxConcurrent || state.windowCount >= config.otaDownloadMaxPerWindow;
|
||||
if (band === 'critical' || overGlobal) {
|
||||
state.shed++;
|
||||
return { allow: false, status: 503, retryAfter: band === 'critical' ? 30 : 10, summary };
|
||||
|
||||
if (config.otaDownloadGuardEnabled) {
|
||||
if (band === 'critical') { state.shed++; return { allow: false, status: 503, retryAfter: 30, summary }; }
|
||||
if (band === 'elevated') {
|
||||
const overGlobal = state.inFlight >= config.otaDownloadMaxConcurrent || state.windowCount >= config.otaDownloadMaxPerWindow;
|
||||
if (overGlobal) { state.shed++; return { allow: false, status: 503, retryAfter: 10, summary }; }
|
||||
}
|
||||
// band === 'normal': no cap — serve freely.
|
||||
}
|
||||
|
||||
state.inFlight++; state.windowCount++; state.served++;
|
||||
return { allow: true, summary };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,23 +34,29 @@ test('apk-cache: get() never touches the filesystem (resolution cached at boot/r
|
|||
assert.equal(calls, 0, 'get() does no fs; 1000 reads = 0 statSync');
|
||||
});
|
||||
|
||||
test('download guard: global concurrency cap -> 503 (not per-IP)', () => {
|
||||
test('band-aware: NORMAL band serves freely (no cap) — healthy rollout not staggered', () => {
|
||||
const s = guard.newState();
|
||||
assert.equal(guard.admit(s, 'normal').allow, true);
|
||||
assert.equal(guard.admit(s, 'normal').allow, true);
|
||||
assert.equal(guard.admit(s, 'normal').allow, true); // 3 in-flight = cap
|
||||
const over = guard.admit(s, 'normal');
|
||||
for (let i = 0; i < 50; i++) assert.equal(guard.admit(s, 'normal').allow, true, 'normal band never caps');
|
||||
assert.equal(s.shed, 0, 'nothing shed while healthy');
|
||||
});
|
||||
|
||||
test('download guard: ELEVATED band applies the global concurrency cap -> 503 (not per-IP)', () => {
|
||||
const s = guard.newState();
|
||||
assert.equal(guard.admit(s, 'elevated').allow, true);
|
||||
assert.equal(guard.admit(s, 'elevated').allow, true);
|
||||
assert.equal(guard.admit(s, 'elevated').allow, true); // 3 in-flight = cap
|
||||
const over = guard.admit(s, 'elevated');
|
||||
assert.equal(over.allow, false);
|
||||
assert.equal(over.status, 503);
|
||||
assert.ok(over.retryAfter > 0);
|
||||
guard.release(s); // free one slot
|
||||
assert.equal(guard.admit(s, 'normal').allow, true, 'a freed slot admits again');
|
||||
guard.release(s); // free one slot
|
||||
assert.equal(guard.admit(s, 'elevated').allow, true, 'a freed slot admits again');
|
||||
});
|
||||
|
||||
test('download guard: global per-window rate cap -> 503', () => {
|
||||
test('download guard: ELEVATED band applies the global per-window rate cap -> 503', () => {
|
||||
const s = guard.newState();
|
||||
for (let i = 0; i < 5; i++) { assert.equal(guard.admit(s, 'normal').allow, true); guard.release(s); } // 5 served this window
|
||||
const over = guard.admit(s, 'normal');
|
||||
for (let i = 0; i < 5; i++) { assert.equal(guard.admit(s, 'elevated').allow, true); guard.release(s); } // 5 served this window
|
||||
const over = guard.admit(s, 'elevated');
|
||||
assert.equal(over.allow, false, '6th in the window is shed');
|
||||
assert.equal(over.status, 503);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ test('storm: bloated-table sweep + flapper + OTA flood — loop stays responsive
|
|||
for (let round = 0; round < 300; round++) {
|
||||
for (let i = 0; i < 40; i++) {
|
||||
if (!flap.check('d:storm-flapper').allow) flapRefused++; // one hard flapper (identity-keyed, never IP)
|
||||
const a = otaGuard.admit(guardState, 'normal'); // global download admission
|
||||
const a = otaGuard.admit(guardState, 'elevated'); // under load -> band-aware caps engage
|
||||
if (a.allow) { otaServed++; otaGuard.release(guardState); } else otaShed++;
|
||||
}
|
||||
await new Promise((r) => setImmediate(r));
|
||||
|
|
|
|||
Loading…
Reference in a new issue