mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
fix(ci): use one heap snapshot for JavaScript admission (#6081)
Read the V8 limit and used heap together for initial admission, checkpoint decode and remaining result capacity. Remove the duplicated second heap/RSS observation while preserving every reserve and ceiling. Make the controlled parent-capacity fixture internally consistent and test both unchanged usage and a later one-MiB collection. Real worker/transfer coverage still retains static/module facts and declines only the large graph. Assisted-by: Reimu (gensokyo-skills:reimu-incident-triage) Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing)
This commit is contained in:
1 parent
d8a9673fc4
commit
01ee6551b4
2 files changed
+31
-20
No files matched your search
@@ -218,6 +218,12 @@ export class JavaScriptAnalysisWorker {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Keep the limit and usage in one V8 observation for every admission path. */
|
||||
#remainingParentHeapBytes(): number {
|
||||
const { heap_size_limit, used_heap_size } = getHeapStatistics();
|
||||
return heap_size_limit - used_heap_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserve host-side control, schema/Evidence work, and a maximum record's
|
||||
* transient copies. Admission also accounts for retained earlier files.
|
||||
@@ -226,8 +232,7 @@ export class JavaScriptAnalysisWorker {
|
||||
this.#resultBudgetBytes = Math.max(
|
||||
0,
|
||||
Math.floor(
|
||||
(getHeapStatistics().heap_size_limit -
|
||||
process.memoryUsage().heapUsed -
|
||||
(this.#remainingParentHeapBytes() -
|
||||
24 * JAVASCRIPT_ANALYSIS_TRANSFER_RECORD_BYTES) /
|
||||
2,
|
||||
),
|
||||
@@ -674,12 +679,7 @@ export class JavaScriptAnalysisWorker {
|
||||
OPERATION,
|
||||
"JavaScript static checkpoint byte count exceeds or differs from its declared budget",
|
||||
);
|
||||
if (
|
||||
bytes * 16 + 4 * MIB >
|
||||
getHeapStatistics().heap_size_limit -
|
||||
process.memoryUsage().heapUsed -
|
||||
64 * MIB
|
||||
)
|
||||
if (bytes * 16 + 4 * MIB > this.#remainingParentHeapBytes() - 64 * MIB)
|
||||
throw new AnalysisResourceConstraintError(
|
||||
OPERATION,
|
||||
"memory",
|
||||
@@ -778,8 +778,7 @@ export class JavaScriptAnalysisWorker {
|
||||
0,
|
||||
Math.min(
|
||||
this.#resultBudgetBytes - this.#estimatedRetainedBytes,
|
||||
getHeapStatistics().heap_size_limit -
|
||||
process.memoryUsage().heapUsed -
|
||||
this.#remainingParentHeapBytes() -
|
||||
24 * JAVASCRIPT_ANALYSIS_TRANSFER_RECORD_BYTES,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { createHash } from "node:crypto";
|
||||
import { afterAll, expect, it, vi } from "vitest";
|
||||
|
||||
const heapObservation = vi.hoisted(() => ({ reclaimedBytes: 0 }));
|
||||
|
||||
// Give the parent a stable 64 MiB result envelope after its transfer reserve.
|
||||
// The child analyzer remains a real separately owned Node process with its
|
||||
// normal heap and real transfer files/descriptors.
|
||||
@@ -8,10 +10,17 @@ vi.mock("node:v8", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("node:v8")>();
|
||||
return {
|
||||
...actual,
|
||||
getHeapStatistics: () => ({
|
||||
...actual.getHeapStatistics(),
|
||||
heap_size_limit: process.memoryUsage().heapUsed + 320 * 1024 * 1024,
|
||||
}),
|
||||
getHeapStatistics: () => {
|
||||
const snapshot = actual.getHeapStatistics();
|
||||
// A separate later memoryUsage() read can observe a collection. Keep the
|
||||
// limit and usage in this earlier snapshot consistent with each other.
|
||||
const used = snapshot.used_heap_size + heapObservation.reclaimedBytes;
|
||||
return {
|
||||
...snapshot,
|
||||
used_heap_size: used,
|
||||
heap_size_limit: used + 320 * 1024 * 1024,
|
||||
};
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@@ -24,7 +33,8 @@ afterAll(() => {
|
||||
vi.resetModules();
|
||||
});
|
||||
|
||||
it("retains module facts and declines only the graph when its real transfer exceeds parent admission", async () => {
|
||||
async function verifyParentAdmission(reclaimedBytes: number) {
|
||||
heapObservation.reclaimedBytes = reclaimedBytes;
|
||||
const methodsCount = 600;
|
||||
const text = Array.from(
|
||||
{ length: methodsCount },
|
||||
@@ -74,10 +84,7 @@ it("retains module facts and declines only the graph when its real transfer exce
|
||||
const limits = error.reportedLimits;
|
||||
if (limits === null)
|
||||
throw new Error("Parent admission omitted its measured limits");
|
||||
expect(limits.parent_result_budget_bytes).toBeLessThanOrEqual(
|
||||
64 * 1024 * 1024,
|
||||
);
|
||||
expect(limits.parent_result_budget_bytes).toBeGreaterThan(0);
|
||||
expect(limits.parent_result_budget_bytes).toBe(64 * 1024 * 1024);
|
||||
const moduleEstimate = limits.module_retention_estimate_bytes;
|
||||
const graphEstimate = limits.graph_retention_estimate_bytes;
|
||||
const available = limits.parent_available_result_budget_bytes;
|
||||
@@ -97,4 +104,9 @@ it("retains module facts and declines only the graph when its real transfer exce
|
||||
} finally {
|
||||
await worker.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
it.each([0, 1024 * 1024])(
|
||||
"retains module facts and declines only the graph with %i bytes reclaimed between heap observations",
|
||||
verifyParentAdmission,
|
||||
);
|
||||
Reference in new issue
Block a user