Reduce host capacity headroom and remove learned usage padding
This commit is contained in:
@@ -108,17 +108,17 @@ describe('measured instance capacity', () => {
|
||||
const { capacityCalibration } = await import('../../src/lib/server/hosts/calibration.js');
|
||||
expect(capacityCalibration(hostId).startup).toMatchObject({ source: 'bootstrap', cpuCores: 0.5, memoryBytes: GiB });
|
||||
const model = await learned();
|
||||
expect(model.running).toMatchObject({ source: 'host', cpuCores: 0.125, memoryBytes: GiB * 0.3125, samples: 20 });
|
||||
expect(model.startup).toMatchObject({ source: 'host', cpuCores: 0.25, memoryBytes: GiB * 0.46875, samples: 4 });
|
||||
expect(model.running).toMatchObject({ source: 'host', cpuCores: 0.1, memoryBytes: GiB / 4, samples: 20 });
|
||||
expect(model.startup).toMatchObject({ source: 'host', cpuCores: 0.2, memoryBytes: 3 * GiB / 8, samples: 4 });
|
||||
});
|
||||
it('raises allowances immediately on a measured spike, including during cold start', async () => {
|
||||
await report(0, { cpuCores: 2, memoryBytes: 2 * GiB });
|
||||
const { capacityCalibration } = await import('../../src/lib/server/hosts/calibration.js');
|
||||
expect(capacityCalibration(hostId).running).toMatchObject({ source: 'bootstrap', cpuCores: 2.5, memoryBytes: 2.5 * GiB });
|
||||
expect(capacityCalibration(hostId).running).toMatchObject({ source: 'bootstrap', cpuCores: 2, memoryBytes: 2 * GiB });
|
||||
await learned();
|
||||
await report(25, { cpuCores: 3, memoryBytes: 3 * GiB });
|
||||
expect(capacityCalibration(hostId).running).toMatchObject({ source: 'host', cpuCores: 3.75, memoryBytes: 3.75 * GiB });
|
||||
expect(capacityCalibration(hostId).startup.cpuCores).toBe(3.75);
|
||||
expect(capacityCalibration(hostId).running).toMatchObject({ source: 'host', cpuCores: 3, memoryBytes: 3 * GiB });
|
||||
expect(capacityCalibration(hostId).startup.cpuCores).toBe(3);
|
||||
});
|
||||
it('uses recent fleet evidence on new hosts and survives a database restart', async () => {
|
||||
const model = await learned();
|
||||
@@ -129,6 +129,19 @@ describe('measured instance capacity', () => {
|
||||
expect(capacityCalibration(other.id).running).toMatchObject({ ...model.running, source: 'fleet' });
|
||||
expect(capacityCalibration(hostId)).toEqual(model);
|
||||
});
|
||||
it('removes legacy cached padding once while preserving host and fleet evidence', async () => {
|
||||
const model = await learned();
|
||||
const { db, closeDb } = await import('../../src/lib/server/db/index.js');
|
||||
// Recreate the previous schema and its padded allowance values.
|
||||
db().exec('ALTER TABLE ec_resource_allowances DROP COLUMN usage_margin');
|
||||
db().exec('UPDATE ec_resource_allowances SET cpu_cores=cpu_cores*1.25, memory_bytes=memory_bytes*1.25');
|
||||
closeDb();
|
||||
const { capacityCalibration } = await import('../../src/lib/server/hosts/calibration.js');
|
||||
expect(capacityCalibration(hostId)).toEqual(model);
|
||||
expect(capacityCalibration('new-host').startup).toEqual({ ...model.startup, source: 'fleet' });
|
||||
closeDb();
|
||||
expect(capacityCalibration(hostId)).toEqual(model);
|
||||
});
|
||||
it('prefers mature local measurements when hosts have different CPU footprints', async () => {
|
||||
await learned();
|
||||
const hosts = await import('../../src/lib/server/hosts/index.js');
|
||||
@@ -137,9 +150,9 @@ describe('measured instance capacity', () => {
|
||||
await instance(other.id, 'instance-2');
|
||||
for (let minute = 25; minute < 45; minute++) await report(minute, { instanceId: 'instance-2', cpuCores: 2 }, other.id);
|
||||
const { capacityCalibration } = await import('../../src/lib/server/hosts/calibration.js');
|
||||
expect(capacityCalibration(hostId).running).toMatchObject({ source: 'host', cpuCores: 0.125 });
|
||||
expect(capacityCalibration(other.id).running).toMatchObject({ source: 'host', cpuCores: 2.5 });
|
||||
expect(capacityCalibration('new-host').running).toMatchObject({ source: 'fleet', cpuCores: 2.5 });
|
||||
expect(capacityCalibration(hostId).running).toMatchObject({ source: 'host', cpuCores: 0.1 });
|
||||
expect(capacityCalibration(other.id).running).toMatchObject({ source: 'host', cpuCores: 2 });
|
||||
expect(capacityCalibration('new-host').running).toMatchObject({ source: 'fleet', cpuCores: 2 });
|
||||
});
|
||||
it('retains minute peaks instead of treating repeated heartbeats as independent evidence', async () => {
|
||||
const { heartbeat } = await import('../../src/lib/server/hosts/index.js');
|
||||
@@ -183,12 +196,12 @@ describe('measured instance capacity', () => {
|
||||
expect(db().prepare('SELECT * FROM ec_instance_resource_samples').all()).toHaveLength(1);
|
||||
expect(capacityCalibration(hostId).running.source).toBe('bootstrap');
|
||||
});
|
||||
it('uses a running percentile and startup peaks with margin, keeping admission reads cached', async () => {
|
||||
it('uses a running percentile and startup peaks without padding, keeping admission reads cached', async () => {
|
||||
for (let minute = 0; minute < 100; minute++) await report(minute, { cpuCores: minute === 0 ? 2 : 0.1 });
|
||||
const { db } = await import('../../src/lib/server/db/index.js');
|
||||
const { capacityCalibration } = await import('../../src/lib/server/hosts/calibration.js');
|
||||
const prepare = vi.spyOn(db(), 'prepare');
|
||||
expect(capacityCalibration(hostId).running.cpuCores).toBe(0.125);
|
||||
expect(capacityCalibration(hostId).running.cpuCores).toBe(0.1);
|
||||
expect(prepare.mock.calls.some(([sql]) => sql.includes('ec_instance_resource_samples'))).toBe(false);
|
||||
prepare.mockRestore();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user