From c6c4428f7d4abc64626e65c96a3899b69b7498aa Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 15 Jul 2026 14:55:18 +0200 Subject: [PATCH] Revert "fix(docker): report current CPU usage instead of the lifetime average" (#6357) --- packages/request-handler/src/docker.ts | 21 ++++--------------- .../request-handler/src/test/docker.spec.ts | 20 ------------------ 2 files changed, 4 insertions(+), 37 deletions(-) diff --git a/packages/request-handler/src/docker.ts b/packages/request-handler/src/docker.ts index a238b4a3c..12a78c05a 100644 --- a/packages/request-handler/src/docker.ts +++ b/packages/request-handler/src/docker.ts @@ -300,10 +300,7 @@ async function getContainersWithStatsAsync() { const stats = await instance .getContainer(container.Id) - // Not in one-shot mode: the daemon then includes precpu_stats (the - // previous reading), which is required to compute the current CPU usage - // as a delta. One-shot omits it and would only expose lifetime totals. - .stats({ stream: false }) + .stats({ stream: false, "one-shot": true }) .catch( () => ({ @@ -339,22 +336,12 @@ export function calculateCpuUsage(stats: ContainerStats): number { } const numberOfCpus = stats.cpu_stats.online_cpus; - - // Docker's own formula for the current (instantaneous) CPU usage: it compares - // the latest reading against the previous one (precpu_stats). Dividing the - // cumulative total_usage by the cumulative system_cpu_usage instead would - // report the container's lifetime average, which stays high long after a load - // spike has ended. precpu_stats is only present when the stats are NOT fetched - // in one-shot mode; when it is absent (e.g. Podman) the deltas fall back to the - // cumulative totals, matching the previous behaviour. - const cpuDelta = stats.cpu_stats.cpu_usage.total_usage - (stats.precpu_stats?.cpu_usage?.total_usage ?? 0); - const systemDelta = (stats.cpu_stats.system_cpu_usage ?? 0) - (stats.precpu_stats?.system_cpu_usage ?? 0); - - if (systemDelta <= 0 || cpuDelta < 0) { + const usage = stats.cpu_stats.system_cpu_usage; + if (!usage || usage === 0) { return 0; } - return (cpuDelta / systemDelta) * numberOfCpus * 100; + return (stats.cpu_stats.cpu_usage.total_usage / usage) * numberOfCpus * 100; } export function calculateMemoryUsage(stats: ContainerStats): number { diff --git a/packages/request-handler/src/test/docker.spec.ts b/packages/request-handler/src/test/docker.spec.ts index 12dbb347b..b4e34f816 100644 --- a/packages/request-handler/src/test/docker.spec.ts +++ b/packages/request-handler/src/test/docker.spec.ts @@ -75,26 +75,6 @@ describe("calculateCpuUsage", () => { // (500 / 100000) * 2 * 100 = 1 expect(calculateCpuUsage(stats)).toBe(1); }); - - test("should use the delta against precpu_stats for the current usage", () => { - const stats = createStats({ - cpu_stats: { online_cpus: 4, cpu_usage: { total_usage: 1_002_000 }, system_cpu_usage: 20_000 }, - precpu_stats: { cpu_usage: { total_usage: 1_000_000 }, system_cpu_usage: 10_000 }, - }); - // Despite a large lifetime total_usage, only the recent delta counts: - // (2000 / 10000) * 4 * 100 = 80 - expect(calculateCpuUsage(stats)).toBe(80); - }); - - test("should report 0 for a container that was busy over its lifetime but is idle now", () => { - const stats = createStats({ - cpu_stats: { online_cpus: 4, cpu_usage: { total_usage: 1_000_000 }, system_cpu_usage: 20_000 }, - precpu_stats: { cpu_usage: { total_usage: 1_000_000 }, system_cpu_usage: 10_000 }, - }); - // No CPU delta since the last reading -> current usage is 0, even though the - // lifetime average would be high. This is the regression the fix addresses. - expect(calculateCpuUsage(stats)).toBe(0); - }); }); describe("calculateMemoryUsage", () => {