@superblocksteam/sdk 2.0.154 → 2.0.155-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/dist/dev-utils/warm-activation-forwarding.d.ts +12 -0
- package/dist/dev-utils/warm-activation-forwarding.d.ts.map +1 -0
- package/dist/dev-utils/warm-activation-forwarding.js +17 -0
- package/dist/dev-utils/warm-activation-forwarding.js.map +1 -0
- package/dist/dev-utils/warm-activation-forwarding.test.d.ts +2 -0
- package/dist/dev-utils/warm-activation-forwarding.test.d.ts.map +1 -0
- package/dist/dev-utils/warm-activation-forwarding.test.js +34 -0
- package/dist/dev-utils/warm-activation-forwarding.test.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/telemetry/memory-metrics.d.ts +28 -3
- package/dist/telemetry/memory-metrics.d.ts.map +1 -1
- package/dist/telemetry/memory-metrics.js +51 -15
- package/dist/telemetry/memory-metrics.js.map +1 -1
- package/dist/telemetry/memory-metrics.test.js +169 -22
- package/dist/telemetry/memory-metrics.test.js.map +1 -1
- package/package.json +6 -6
- package/src/dev-utils/warm-activation-forwarding.test.ts +48 -0
- package/src/dev-utils/warm-activation-forwarding.ts +29 -0
- package/src/index.ts +5 -0
- package/src/telemetry/memory-metrics.test.ts +217 -22
- package/src/telemetry/memory-metrics.ts +84 -19
- package/tsconfig.tsbuildinfo +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two values a warm pod cannot know before a live edit claims it: which
|
|
3
|
+
* live edit it now serves, and where SABS answers so Clark's events can be
|
|
4
|
+
* forwarded there. Cold-start pods receive both as environment at creation;
|
|
5
|
+
* activation is the warm path's equivalent.
|
|
6
|
+
*/
|
|
7
|
+
export type WarmActivationForwardingConfig = {
|
|
8
|
+
liveEditId?: string;
|
|
9
|
+
sabsBaseUrl?: string;
|
|
10
|
+
};
|
|
11
|
+
export declare function applyWarmActivationForwardingEnv(config: WarmActivationForwardingConfig, environment?: NodeJS.ProcessEnv): void;
|
|
12
|
+
//# sourceMappingURL=warm-activation-forwarding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warm-activation-forwarding.d.ts","sourceRoot":"","sources":["../../src/dev-utils/warm-activation-forwarding.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,8BAA8B,GAAG;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,8BAA8B,EACtC,WAAW,GAAE,MAAM,CAAC,UAAwB,GAC3C,IAAI,CAcN"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function applyWarmActivationForwardingEnv(config, environment = process.env) {
|
|
2
|
+
// Assign or clear, never leave behind: a pod that was seeded with a
|
|
3
|
+
// placeholder must not forward under the previous occupant's identity.
|
|
4
|
+
if (config.liveEditId) {
|
|
5
|
+
environment.LIVE_EDIT_ID = config.liveEditId;
|
|
6
|
+
}
|
|
7
|
+
else {
|
|
8
|
+
delete environment.LIVE_EDIT_ID;
|
|
9
|
+
}
|
|
10
|
+
if (config.sabsBaseUrl) {
|
|
11
|
+
environment.SUPERBLOCKS_SABS_BASE_URL = config.sabsBaseUrl;
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
delete environment.SUPERBLOCKS_SABS_BASE_URL;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=warm-activation-forwarding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warm-activation-forwarding.js","sourceRoot":"","sources":["../../src/dev-utils/warm-activation-forwarding.ts"],"names":[],"mappings":"AAWA,MAAM,UAAU,gCAAgC,CAC9C,MAAsC,EACtC,cAAiC,OAAO,CAAC,GAAG;IAE5C,oEAAoE;IACpE,uEAAuE;IACvE,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACtB,WAAW,CAAC,YAAY,GAAG,MAAM,CAAC,UAAU,CAAC;IAC/C,CAAC;SAAM,CAAC;QACN,OAAO,WAAW,CAAC,YAAY,CAAC;IAClC,CAAC;IAED,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QACvB,WAAW,CAAC,yBAAyB,GAAG,MAAM,CAAC,WAAW,CAAC;IAC7D,CAAC;SAAM,CAAC;QACN,OAAO,WAAW,CAAC,yBAAyB,CAAC;IAC/C,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warm-activation-forwarding.test.d.ts","sourceRoot":"","sources":["../../src/dev-utils/warm-activation-forwarding.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { applyWarmActivationForwardingEnv } from "./warm-activation-forwarding.js";
|
|
3
|
+
/**
|
|
4
|
+
* A warm pod is built before any live edit claims it, so it boots with
|
|
5
|
+
* placeholder identity. Activation is the only moment SABS can tell it which
|
|
6
|
+
* live edit it now serves and where to forward that live edit's events; a
|
|
7
|
+
* cold-start pod is handed the same two values as environment at creation.
|
|
8
|
+
*/
|
|
9
|
+
describe("warm activation forwarding config", () => {
|
|
10
|
+
it("tells the dev server which live edit it is now serving", () => {
|
|
11
|
+
const environment = {};
|
|
12
|
+
applyWarmActivationForwardingEnv({ liveEditId: "le-42", sabsBaseUrl: "http://sabs.sabs.svc:8080" }, environment);
|
|
13
|
+
expect(environment.LIVE_EDIT_ID).toBe("le-42");
|
|
14
|
+
expect(environment.SUPERBLOCKS_SABS_BASE_URL).toBe("http://sabs.sabs.svc:8080");
|
|
15
|
+
});
|
|
16
|
+
it("leaves forwarding off when the deployment does not run the push channel", () => {
|
|
17
|
+
const environment = {};
|
|
18
|
+
applyWarmActivationForwardingEnv({ liveEditId: "le-42" }, environment);
|
|
19
|
+
expect(environment.LIVE_EDIT_ID).toBe("le-42");
|
|
20
|
+
expect(environment.SUPERBLOCKS_SABS_BASE_URL).toBeUndefined();
|
|
21
|
+
});
|
|
22
|
+
it("clears a previous pod's identity rather than forwarding under it", () => {
|
|
23
|
+
// Belt and braces: a warm entrypoint that seeded a placeholder must not
|
|
24
|
+
// leave it behind for the live edit that actually claimed the pod.
|
|
25
|
+
const environment = {
|
|
26
|
+
LIVE_EDIT_ID: "stale-le",
|
|
27
|
+
SUPERBLOCKS_SABS_BASE_URL: "http://stale.svc:8080",
|
|
28
|
+
};
|
|
29
|
+
applyWarmActivationForwardingEnv({}, environment);
|
|
30
|
+
expect(environment.LIVE_EDIT_ID).toBeUndefined();
|
|
31
|
+
expect(environment.SUPERBLOCKS_SABS_BASE_URL).toBeUndefined();
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
//# sourceMappingURL=warm-activation-forwarding.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warm-activation-forwarding.test.js","sourceRoot":"","sources":["../../src/dev-utils/warm-activation-forwarding.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,gCAAgC,EAAE,MAAM,iCAAiC,CAAC;AAEnF;;;;;GAKG;AACH,QAAQ,CAAC,mCAAmC,EAAE,GAAG,EAAE;IACjD,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,WAAW,GAAsB,EAAE,CAAC;QAE1C,gCAAgC,CAC9B,EAAE,UAAU,EAAE,OAAO,EAAE,WAAW,EAAE,2BAA2B,EAAE,EACjE,WAAW,CACZ,CAAC;QAEF,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC/C,MAAM,CAAC,WAAW,CAAC,yBAAyB,CAAC,CAAC,IAAI,CAChD,2BAA2B,CAC5B,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yEAAyE,EAAE,GAAG,EAAE;QACjF,MAAM,WAAW,GAAsB,EAAE,CAAC;QAE1C,gCAAgC,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;QAEvE,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC/C,MAAM,CAAC,WAAW,CAAC,yBAAyB,CAAC,CAAC,aAAa,EAAE,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,wEAAwE;QACxE,mEAAmE;QACnE,MAAM,WAAW,GAAsB;YACrC,YAAY,EAAE,UAAU;YACxB,yBAAyB,EAAE,uBAAuB;SACnD,CAAC;QAEF,gCAAgC,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;QAElD,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,aAAa,EAAE,CAAC;QACjD,MAAM,CAAC,WAAW,CAAC,yBAAyB,CAAC,CAAC,aAAa,EAAE,CAAC;IAChE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -19,4 +19,5 @@ export { getErrorMeta, getLogger, type ErrorMeta, type Logger, } from "./telemet
|
|
|
19
19
|
export { AuthHotReloadServer, isAuthHotReloadEnabled, } from "./cli-replacement/auth-hot-reload.mjs";
|
|
20
20
|
export { configureTelemetry, deploymentType, getMeter, getTracer, isCloudPrem, } from "./telemetry/index.js";
|
|
21
21
|
export { applyStartupTraceCarrier, startupTraceCarrierFromHeaders, type StartupTraceCarrier, withStartupTraceContext, } from "./telemetry/startup-context.js";
|
|
22
|
+
export { applyWarmActivationForwardingEnv, type WarmActivationForwardingConfig, } from "./dev-utils/warm-activation-forwarding.js";
|
|
22
23
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,KAAK,eAAe,EACpB,KAAK,0BAA0B,EAC/B,KAAK,uBAAuB,EAC5B,KAAK,aAAa,EAClB,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,EAChC,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,2BAA2B,EAChC,KAAK,yCAAyC,EAC9C,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,iCAAiC,EACtC,KAAK,kCAAkC,EACvC,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,cAAc,EACd,qBAAqB,GACtB,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,KAAK,2CAA2C,EAChD,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,WAAW,GACjB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,UAAU,EACV,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,kCAAkC,EAClC,cAAc,EACd,wBAAwB,EACxB,oBAAoB,EACpB,aAAa,EACb,oBAAoB,EACpB,OAAO,EACP,IAAI,EACJ,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,uBAAuB,EACvB,gCAAgC,EAChC,sBAAsB,EACtB,SAAS,EACT,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACnB,KAAK,QAAQ,GACd,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAE/D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC/E,OAAO,EACL,gBAAgB,EAChB,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,GAC3B,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAE5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAErE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,EACb,KAAK,cAAc,GACpB,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,GAAG,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAE1E,OAAO,EACL,4BAA4B,EAC5B,mBAAmB,EACnB,6BAA6B,EAC7B,uBAAuB,EACvB,iCAAiC,EACjC,yBAAyB,EACzB,iCAAiC,EACjC,4BAA4B,EAC5B,2BAA2B,EAC3B,2BAA2B,EAC3B,KAAK,mBAAmB,EACxB,KAAK,6BAA6B,GACnC,MAAM,6CAA6C,CAAC;AAErD,OAAO,EACL,YAAY,EACZ,SAAS,EACT,KAAK,SAAS,EACd,KAAK,MAAM,GACZ,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,uCAAuC,CAAC;AAE/C,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,QAAQ,EACR,SAAS,EACT,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,wBAAwB,EACxB,8BAA8B,EAC9B,KAAK,mBAAmB,EACxB,uBAAuB,GACxB,MAAM,gCAAgC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,KAAK,eAAe,EACpB,KAAK,0BAA0B,EAC/B,KAAK,uBAAuB,EAC5B,KAAK,aAAa,EAClB,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,EAChC,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,2BAA2B,EAChC,KAAK,yCAAyC,EAC9C,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,iCAAiC,EACtC,KAAK,kCAAkC,EACvC,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,cAAc,EACd,qBAAqB,GACtB,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,KAAK,2CAA2C,EAChD,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,WAAW,GACjB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,UAAU,EACV,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,kCAAkC,EAClC,cAAc,EACd,wBAAwB,EACxB,oBAAoB,EACpB,aAAa,EACb,oBAAoB,EACpB,OAAO,EACP,IAAI,EACJ,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,uBAAuB,EACvB,gCAAgC,EAChC,sBAAsB,EACtB,SAAS,EACT,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACnB,KAAK,QAAQ,GACd,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAE/D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC/E,OAAO,EACL,gBAAgB,EAChB,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,GAC3B,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAE5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAErE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,EACb,KAAK,cAAc,GACpB,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,GAAG,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAE1E,OAAO,EACL,4BAA4B,EAC5B,mBAAmB,EACnB,6BAA6B,EAC7B,uBAAuB,EACvB,iCAAiC,EACjC,yBAAyB,EACzB,iCAAiC,EACjC,4BAA4B,EAC5B,2BAA2B,EAC3B,2BAA2B,EAC3B,KAAK,mBAAmB,EACxB,KAAK,6BAA6B,GACnC,MAAM,6CAA6C,CAAC;AAErD,OAAO,EACL,YAAY,EACZ,SAAS,EACT,KAAK,SAAS,EACd,KAAK,MAAM,GACZ,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,uCAAuC,CAAC;AAE/C,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,QAAQ,EACR,SAAS,EACT,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,wBAAwB,EACxB,8BAA8B,EAC9B,KAAK,mBAAmB,EACxB,uBAAuB,GACxB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACL,gCAAgC,EAChC,KAAK,8BAA8B,GACpC,MAAM,2CAA2C,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -18,4 +18,5 @@ export { getErrorMeta, getLogger, } from "./telemetry/logging.js";
|
|
|
18
18
|
export { AuthHotReloadServer, isAuthHotReloadEnabled, } from "./cli-replacement/auth-hot-reload.mjs";
|
|
19
19
|
export { configureTelemetry, deploymentType, getMeter, getTracer, isCloudPrem, } from "./telemetry/index.js";
|
|
20
20
|
export { applyStartupTraceCarrier, startupTraceCarrierFromHeaders, withStartupTraceContext, } from "./telemetry/startup-context.js";
|
|
21
|
+
export { applyWarmActivationForwardingEnv, } from "./dev-utils/warm-activation-forwarding.js";
|
|
21
22
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,EACL,oBAAoB,EACpB,iBAAiB,GAqBlB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,cAAc,EACd,qBAAqB,GACtB,MAAM,UAAU,CAAC;AASlB,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,UAAU,EACV,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,kCAAkC,EAClC,cAAc,EACd,wBAAwB,EACxB,oBAAoB,EACpB,aAAa,EACb,oBAAoB,EACpB,OAAO,EACP,IAAI,EACJ,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,uBAAuB,EACvB,gCAAgC,EAChC,sBAAsB,EACtB,SAAS,EACT,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,GAEpB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAE/D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC/E,OAAO,EACL,gBAAgB,GAIjB,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAE5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAErE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,GAEd,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,GAAG,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAE1E,OAAO,EACL,4BAA4B,EAC5B,mBAAmB,EACnB,6BAA6B,EAC7B,uBAAuB,EACvB,iCAAiC,EACjC,yBAAyB,EACzB,iCAAiC,EACjC,4BAA4B,EAC5B,2BAA2B,EAC3B,2BAA2B,GAG5B,MAAM,6CAA6C,CAAC;AAErD,OAAO,EACL,YAAY,EACZ,SAAS,GAGV,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,uCAAuC,CAAC;AAE/C,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,QAAQ,EACR,SAAS,EACT,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,wBAAwB,EACxB,8BAA8B,EAE9B,uBAAuB,GACxB,MAAM,gCAAgC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,EACL,oBAAoB,EACpB,iBAAiB,GAqBlB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,cAAc,EACd,qBAAqB,GACtB,MAAM,UAAU,CAAC;AASlB,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,UAAU,EACV,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,kCAAkC,EAClC,cAAc,EACd,wBAAwB,EACxB,oBAAoB,EACpB,aAAa,EACb,oBAAoB,EACpB,OAAO,EACP,IAAI,EACJ,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,uBAAuB,EACvB,gCAAgC,EAChC,sBAAsB,EACtB,SAAS,EACT,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,GAEpB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAE/D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC/E,OAAO,EACL,gBAAgB,GAIjB,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAE5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAErE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,GAEd,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,GAAG,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAE1E,OAAO,EACL,4BAA4B,EAC5B,mBAAmB,EACnB,6BAA6B,EAC7B,uBAAuB,EACvB,iCAAiC,EACjC,yBAAyB,EACzB,iCAAiC,EACjC,4BAA4B,EAC5B,2BAA2B,EAC3B,2BAA2B,GAG5B,MAAM,6CAA6C,CAAC;AAErD,OAAO,EACL,YAAY,EACZ,SAAS,GAGV,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,uCAAuC,CAAC;AAE/C,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,QAAQ,EACR,SAAS,EACT,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,wBAAwB,EACxB,8BAA8B,EAE9B,uBAAuB,GACxB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACL,gCAAgC,GAEjC,MAAM,2CAA2C,CAAC"}
|
|
@@ -1,10 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Why a limit did or did not accompany a usage reading.
|
|
3
|
+
*
|
|
4
|
+
* available A finite positive limit was read; `limitBytes` is set.
|
|
5
|
+
* unlimited The cgroup reports no limit: v2 `max`, or v1's 2^63-1 sentinel
|
|
6
|
+
* (which gVisor sandboxes always report, because the real limit
|
|
7
|
+
* is enforced on the host cgroup outside the sandbox).
|
|
8
|
+
* unreadable The limit file could not be read at all.
|
|
9
|
+
*
|
|
10
|
+
* The last two both omit `limitBytes`, so without this they are indistinguishable
|
|
11
|
+
* to a consumer -- an unreadable limit is a genuine fault worth alerting on,
|
|
12
|
+
* while an unlimited one is the normal steady state under gVisor.
|
|
13
|
+
*/
|
|
14
|
+
type CgroupLimitState = "available" | "unlimited" | "unreadable";
|
|
1
15
|
interface CgroupMemory {
|
|
2
16
|
currentBytes: number;
|
|
3
|
-
|
|
4
|
-
|
|
17
|
+
/** Set only when `limitState` is `available`. */
|
|
18
|
+
limitBytes?: number;
|
|
19
|
+
/** Absent whenever `limitBytes` is, since it is derived from it. */
|
|
20
|
+
usageRatio?: number;
|
|
21
|
+
/** Always set; see {@link CgroupLimitState}. */
|
|
22
|
+
limitState: CgroupLimitState;
|
|
23
|
+
}
|
|
24
|
+
export interface MemoryMetricsOptions {
|
|
25
|
+
/**
|
|
26
|
+
* Cgroup filesystem root to read from. Defaults to the real `/sys/fs/cgroup`;
|
|
27
|
+
* overridden only by tests, which point it at a fixture directory.
|
|
28
|
+
*/
|
|
29
|
+
cgroupRoot?: string;
|
|
5
30
|
}
|
|
6
31
|
export declare function readCgroupMemory(root?: string): CgroupMemory | undefined;
|
|
7
|
-
export declare function startMemoryMetrics(): void;
|
|
32
|
+
export declare function startMemoryMetrics(options?: MemoryMetricsOptions): void;
|
|
8
33
|
export declare function stopMemoryMetrics(): void;
|
|
9
34
|
export {};
|
|
10
35
|
//# sourceMappingURL=memory-metrics.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-metrics.d.ts","sourceRoot":"","sources":["../../src/telemetry/memory-metrics.ts"],"names":[],"mappings":"AAgBA,UAAU,YAAY;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"memory-metrics.d.ts","sourceRoot":"","sources":["../../src/telemetry/memory-metrics.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;GAYG;AACH,KAAK,gBAAgB,GAAG,WAAW,GAAG,WAAW,GAAG,YAAY,CAAC;AAEjE,UAAU,YAAY;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,UAAU,EAAE,gBAAgB,CAAC;CAC9B;AAOD,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAyDD,wBAAgB,gBAAgB,CAC9B,IAAI,SAAmB,GACtB,YAAY,GAAG,SAAS,CAuC1B;AAiBD,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,oBAAyB,GAAG,IAAI,CAyP3E;AAED,wBAAgB,iBAAiB,IAAI,IAAI,CAKxC"}
|
|
@@ -5,6 +5,11 @@ import { getMeter } from "./index.js";
|
|
|
5
5
|
let cleanupFn;
|
|
6
6
|
const NS_PER_MS = 1_000_000;
|
|
7
7
|
const US_PER_SECOND = 1_000_000;
|
|
8
|
+
/**
|
|
9
|
+
* Attribute on `nodejs.memory.cgroup_current_bytes` recording whether a limit
|
|
10
|
+
* accompanied the reading. Bounded to the three {@link CgroupLimitState} values.
|
|
11
|
+
*/
|
|
12
|
+
const ATTR_CGROUP_LIMIT_STATE = "cgroup.limit_state";
|
|
8
13
|
function finiteNonNegative(value) {
|
|
9
14
|
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
10
15
|
}
|
|
@@ -42,21 +47,37 @@ export function readCgroupMemory(root = "/sys/fs/cgroup") {
|
|
|
42
47
|
const v2Current = readCgroupNumber(`${root}/memory.current`);
|
|
43
48
|
const v2Limit = readCgroupNumber(`${root}/memory.max`);
|
|
44
49
|
const usesCgroupV2 = v2Current.exists || v2Limit.exists;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
?
|
|
50
|
-
: readCgroupNumber(`${root}/memory/memory.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
// Keep the whole CgroupNumber, not just its value: `exists` is what separates
|
|
51
|
+
// a cgroup that reports no limit from one whose limit file could not be read,
|
|
52
|
+
// and both arrive here with `value === undefined`.
|
|
53
|
+
const current = usesCgroupV2
|
|
54
|
+
? v2Current
|
|
55
|
+
: readCgroupNumber(`${root}/memory/memory.usage_in_bytes`);
|
|
56
|
+
const limit = usesCgroupV2
|
|
57
|
+
? v2Limit
|
|
58
|
+
: readCgroupNumber(`${root}/memory/memory.limit_in_bytes`);
|
|
59
|
+
const currentBytes = current.value;
|
|
60
|
+
const limitBytes = limit.value;
|
|
61
|
+
if (currentBytes === undefined) {
|
|
54
62
|
return undefined;
|
|
55
63
|
}
|
|
64
|
+
// Current usage stands on its own as a measurement. A container routinely
|
|
65
|
+
// reads its own usage while the limit is absent or unlimited: gVisor
|
|
66
|
+
// sandboxes expose cgroup v1 with `memory.limit_in_bytes` at the unlimited
|
|
67
|
+
// sentinel (2^63-1), because the real limit is enforced on the host cgroup
|
|
68
|
+
// outside the sandbox. Returning undefined here would discard a readable
|
|
69
|
+
// usage value and leave every such pod with no cgroup telemetry at all.
|
|
70
|
+
if (limitBytes === undefined || limitBytes <= 0) {
|
|
71
|
+
return {
|
|
72
|
+
currentBytes,
|
|
73
|
+
limitState: limit.exists ? "unlimited" : "unreadable",
|
|
74
|
+
};
|
|
75
|
+
}
|
|
56
76
|
return {
|
|
57
77
|
currentBytes,
|
|
58
78
|
limitBytes,
|
|
59
79
|
usageRatio: ratio(currentBytes, limitBytes),
|
|
80
|
+
limitState: "available",
|
|
60
81
|
};
|
|
61
82
|
}
|
|
62
83
|
function gcKind(kind) {
|
|
@@ -73,10 +94,11 @@ function gcKind(kind) {
|
|
|
73
94
|
return "unknown";
|
|
74
95
|
}
|
|
75
96
|
}
|
|
76
|
-
export function startMemoryMetrics() {
|
|
97
|
+
export function startMemoryMetrics(options = {}) {
|
|
77
98
|
if (cleanupFn) {
|
|
78
99
|
return;
|
|
79
100
|
}
|
|
101
|
+
const cgroupRoot = options.cgroupRoot;
|
|
80
102
|
const meter = getMeter();
|
|
81
103
|
const eventLoopDelay = monitorEventLoopDelay({ resolution: 20 });
|
|
82
104
|
let previousEventLoopUtilization = performance.eventLoopUtilization();
|
|
@@ -167,7 +189,7 @@ export function startMemoryMetrics() {
|
|
|
167
189
|
try {
|
|
168
190
|
const mem = process.memoryUsage();
|
|
169
191
|
const heap = getHeapStatistics();
|
|
170
|
-
const cgroup = readCgroupMemory();
|
|
192
|
+
const cgroup = readCgroupMemory(cgroupRoot);
|
|
171
193
|
const elu = performance.eventLoopUtilization(previousEventLoopUtilization);
|
|
172
194
|
previousEventLoopUtilization = performance.eventLoopUtilization();
|
|
173
195
|
const cpu = process.cpuUsage();
|
|
@@ -178,11 +200,25 @@ export function startMemoryMetrics() {
|
|
|
178
200
|
result.observe(arrayBuffersGauge, mem.arrayBuffers);
|
|
179
201
|
result.observe(heapLimitGauge, heap.heap_size_limit);
|
|
180
202
|
result.observe(heapUsedRatioGauge, ratio(mem.heapUsed, heap.heap_size_limit));
|
|
181
|
-
//
|
|
203
|
+
// Current usage is emitted whenever the cgroup is readable at all; the
|
|
204
|
+
// limit and its derived ratio are omitted when no usable limit could be
|
|
205
|
+
// determined. Neither may suppress current usage.
|
|
206
|
+
//
|
|
207
|
+
// This makes "current present, limit absent" a normal steady state
|
|
208
|
+
// rather than the impossible one it was before, and under gVisor it is
|
|
209
|
+
// the permanent shape. So the absence of a limit series is NOT a
|
|
210
|
+
// telemetry-failure signal, and `cgroup.limit_state` carries the reason
|
|
211
|
+
// on the usage gauge itself rather than leaving consumers to infer it
|
|
212
|
+
// from a missing series. Three bounded values; see CgroupLimitState.
|
|
182
213
|
if (cgroup) {
|
|
183
|
-
result.observe(cgroupCurrentGauge, cgroup.currentBytes
|
|
184
|
-
|
|
185
|
-
|
|
214
|
+
result.observe(cgroupCurrentGauge, cgroup.currentBytes, {
|
|
215
|
+
[ATTR_CGROUP_LIMIT_STATE]: cgroup.limitState,
|
|
216
|
+
});
|
|
217
|
+
if (cgroup.limitBytes !== undefined &&
|
|
218
|
+
cgroup.usageRatio !== undefined) {
|
|
219
|
+
result.observe(cgroupLimitGauge, cgroup.limitBytes);
|
|
220
|
+
result.observe(cgroupUsageRatioGauge, cgroup.usageRatio);
|
|
221
|
+
}
|
|
186
222
|
}
|
|
187
223
|
result.observe(eventLoopDelayMeanGauge, nsToMs(eventLoopDelay.mean));
|
|
188
224
|
result.observe(eventLoopDelayMaxGauge, nsToMs(eventLoopDelay.max));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-metrics.js","sourceRoot":"","sources":["../../src/telemetry/memory-metrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EACL,SAAS,EACT,qBAAqB,EACrB,WAAW,EACX,mBAAmB,GAEpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAI5C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,IAAI,SAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"memory-metrics.js","sourceRoot":"","sources":["../../src/telemetry/memory-metrics.ts"],"names":[],"mappings":"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"}
|
|
@@ -94,26 +94,40 @@ function observeAll() {
|
|
|
94
94
|
});
|
|
95
95
|
return observations;
|
|
96
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Reset every piece of shared harness state.
|
|
99
|
+
*
|
|
100
|
+
* Any describe block that calls `startMemoryMetrics` must run this: the batch
|
|
101
|
+
* callback dereferences the mocked `performance.eventLoopUtilization()` result,
|
|
102
|
+
* so a block that leaves `h.elu` unconfigured throws
|
|
103
|
+
* `Cannot read properties of undefined (reading 'utilization')` the moment it
|
|
104
|
+
* observes — an obscure failure unrelated to whatever it was asserting. Sharing
|
|
105
|
+
* one reset keeps blocks independent of declaration order, `.only`, and
|
|
106
|
+
* `sequence.shuffle`.
|
|
107
|
+
*/
|
|
108
|
+
function resetHarness() {
|
|
109
|
+
vi.resetModules();
|
|
110
|
+
h.gauges.length = 0;
|
|
111
|
+
h.observableCounters.length = 0;
|
|
112
|
+
h.counters.length = 0;
|
|
113
|
+
h.histograms.length = 0;
|
|
114
|
+
h.throwOnGaugeName = undefined;
|
|
115
|
+
h.delayMonitor.enable.mockClear();
|
|
116
|
+
h.delayMonitor.disable.mockClear();
|
|
117
|
+
h.delayMonitor.reset.mockClear();
|
|
118
|
+
h.delayMonitor.percentile.mockClear();
|
|
119
|
+
h.gcCallback = undefined;
|
|
120
|
+
h.elu.mockReset();
|
|
121
|
+
h.elu
|
|
122
|
+
.mockReturnValueOnce({ idle: 0, active: 0, utilization: 0 })
|
|
123
|
+
.mockReturnValueOnce({ idle: 25, active: 75, utilization: 0.75 })
|
|
124
|
+
.mockReturnValue({ idle: 100, active: 200, utilization: 0.67 });
|
|
125
|
+
h.addBatchObservableCallback.mockClear();
|
|
126
|
+
h.removeBatchObservableCallback.mockClear();
|
|
127
|
+
}
|
|
97
128
|
describe("memory metrics", () => {
|
|
98
|
-
beforeEach(
|
|
99
|
-
|
|
100
|
-
h.gauges.length = 0;
|
|
101
|
-
h.observableCounters.length = 0;
|
|
102
|
-
h.counters.length = 0;
|
|
103
|
-
h.histograms.length = 0;
|
|
104
|
-
h.throwOnGaugeName = undefined;
|
|
105
|
-
h.delayMonitor.enable.mockClear();
|
|
106
|
-
h.delayMonitor.disable.mockClear();
|
|
107
|
-
h.delayMonitor.reset.mockClear();
|
|
108
|
-
h.delayMonitor.percentile.mockClear();
|
|
109
|
-
h.gcCallback = undefined;
|
|
110
|
-
h.elu.mockReset();
|
|
111
|
-
h.elu
|
|
112
|
-
.mockReturnValueOnce({ idle: 0, active: 0, utilization: 0 })
|
|
113
|
-
.mockReturnValueOnce({ idle: 25, active: 75, utilization: 0.75 })
|
|
114
|
-
.mockReturnValue({ idle: 100, active: 200, utilization: 0.67 });
|
|
115
|
-
h.addBatchObservableCallback.mockClear();
|
|
116
|
-
h.removeBatchObservableCallback.mockClear();
|
|
129
|
+
beforeEach(() => {
|
|
130
|
+
resetHarness();
|
|
117
131
|
});
|
|
118
132
|
it("observes event-loop, V8 heap, and memory-pressure gauges", async () => {
|
|
119
133
|
const { startMemoryMetrics, stopMemoryMetrics } = await import("./memory-metrics.js");
|
|
@@ -222,15 +236,19 @@ describe("readCgroupMemory", () => {
|
|
|
222
236
|
currentBytes: 50,
|
|
223
237
|
limitBytes: 200,
|
|
224
238
|
usageRatio: 0.25,
|
|
239
|
+
limitState: "available",
|
|
225
240
|
});
|
|
226
241
|
});
|
|
227
|
-
it("returns undefined when cgroup files are absent
|
|
242
|
+
it("returns undefined when cgroup files are absent, and usage alone when unlimited", async () => {
|
|
228
243
|
const root = mkdtempSync(path.join(tmpdir(), "sb-cgroup-"));
|
|
229
244
|
const { readCgroupMemory } = await import("./memory-metrics.js");
|
|
230
245
|
expect(readCgroupMemory(root)).toBeUndefined();
|
|
231
246
|
writeFileSync(path.join(root, "memory.current"), "50\n");
|
|
232
247
|
writeFileSync(path.join(root, "memory.max"), "max\n");
|
|
233
|
-
expect(readCgroupMemory(root)).
|
|
248
|
+
expect(readCgroupMemory(root)).toEqual({
|
|
249
|
+
currentBytes: 50,
|
|
250
|
+
limitState: "unlimited",
|
|
251
|
+
});
|
|
234
252
|
});
|
|
235
253
|
it("does not combine v2 usage with v1 limits", async () => {
|
|
236
254
|
const root = mkdtempSync(path.join(tmpdir(), "sb-cgroup-"));
|
|
@@ -241,7 +259,12 @@ describe("readCgroupMemory", () => {
|
|
|
241
259
|
writeFileSync(path.join(memoryRoot, "memory.usage_in_bytes"), "60\n");
|
|
242
260
|
writeFileSync(path.join(memoryRoot, "memory.limit_in_bytes"), "200\n");
|
|
243
261
|
const { readCgroupMemory } = await import("./memory-metrics.js");
|
|
244
|
-
|
|
262
|
+
// v2 is detected, so the v1 limit of 200 must not be adopted: the result
|
|
263
|
+
// carries the v2 usage of 50 and no limit at all.
|
|
264
|
+
expect(readCgroupMemory(root)).toEqual({
|
|
265
|
+
currentBytes: 50,
|
|
266
|
+
limitState: "unlimited",
|
|
267
|
+
});
|
|
245
268
|
});
|
|
246
269
|
it("treats cgroup v1 sentinel limits as unlimited", async () => {
|
|
247
270
|
const root = mkdtempSync(path.join(tmpdir(), "sb-cgroup-"));
|
|
@@ -250,7 +273,131 @@ describe("readCgroupMemory", () => {
|
|
|
250
273
|
writeFileSync(path.join(memoryRoot, "memory.usage_in_bytes"), "50\n");
|
|
251
274
|
writeFileSync(path.join(memoryRoot, "memory.limit_in_bytes"), "9223372036854771712\n");
|
|
252
275
|
const { readCgroupMemory } = await import("./memory-metrics.js");
|
|
276
|
+
expect(readCgroupMemory(root)).toEqual({
|
|
277
|
+
currentBytes: 50,
|
|
278
|
+
limitState: "unlimited",
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
describe("readCgroupMemory without a readable limit", () => {
|
|
283
|
+
beforeEach(() => {
|
|
284
|
+
vi.resetModules();
|
|
285
|
+
});
|
|
286
|
+
it("still reports current usage when the v1 limit is the unlimited sentinel", async () => {
|
|
287
|
+
const root = mkdtempSync(path.join(tmpdir(), "sb-cgroup-"));
|
|
288
|
+
const memoryRoot = path.join(root, "memory");
|
|
289
|
+
mkdirSync(memoryRoot);
|
|
290
|
+
writeFileSync(path.join(memoryRoot, "memory.usage_in_bytes"), "50\n");
|
|
291
|
+
writeFileSync(path.join(memoryRoot, "memory.limit_in_bytes"), "9223372036854775807\n");
|
|
292
|
+
const { readCgroupMemory } = await import("./memory-metrics.js");
|
|
293
|
+
const cgroup = readCgroupMemory(root);
|
|
294
|
+
expect(cgroup?.currentBytes).toBe(50);
|
|
295
|
+
expect(cgroup?.limitBytes).toBeUndefined();
|
|
296
|
+
expect(cgroup?.usageRatio).toBeUndefined();
|
|
297
|
+
});
|
|
298
|
+
it("still reports current usage when the v2 limit is max", async () => {
|
|
299
|
+
const root = mkdtempSync(path.join(tmpdir(), "sb-cgroup-"));
|
|
300
|
+
writeFileSync(path.join(root, "memory.current"), "50\n");
|
|
301
|
+
writeFileSync(path.join(root, "memory.max"), "max\n");
|
|
302
|
+
const { readCgroupMemory } = await import("./memory-metrics.js");
|
|
303
|
+
const cgroup = readCgroupMemory(root);
|
|
304
|
+
expect(cgroup?.currentBytes).toBe(50);
|
|
305
|
+
expect(cgroup?.limitBytes).toBeUndefined();
|
|
306
|
+
});
|
|
307
|
+
it("returns undefined when current usage itself is unreadable", async () => {
|
|
308
|
+
const root = mkdtempSync(path.join(tmpdir(), "sb-cgroup-"));
|
|
309
|
+
writeFileSync(path.join(root, "memory.max"), "200\n");
|
|
310
|
+
const { readCgroupMemory } = await import("./memory-metrics.js");
|
|
253
311
|
expect(readCgroupMemory(root)).toBeUndefined();
|
|
254
312
|
});
|
|
255
313
|
});
|
|
314
|
+
describe("cgroup limit state", () => {
|
|
315
|
+
beforeEach(() => {
|
|
316
|
+
vi.resetModules();
|
|
317
|
+
});
|
|
318
|
+
it("reports an unlimited cgroup distinctly from an unreadable limit", async () => {
|
|
319
|
+
const unlimited = mkdtempSync(path.join(tmpdir(), "sb-cgroup-"));
|
|
320
|
+
writeFileSync(path.join(unlimited, "memory.current"), "50\n");
|
|
321
|
+
writeFileSync(path.join(unlimited, "memory.max"), "max\n");
|
|
322
|
+
// memory.current is readable, memory.max is absent: the limit read fails
|
|
323
|
+
// rather than reporting "no limit", and the two must not look alike.
|
|
324
|
+
const unreadable = mkdtempSync(path.join(tmpdir(), "sb-cgroup-"));
|
|
325
|
+
writeFileSync(path.join(unreadable, "memory.current"), "50\n");
|
|
326
|
+
const { readCgroupMemory } = await import("./memory-metrics.js");
|
|
327
|
+
expect(readCgroupMemory(unlimited)?.limitState).toBe("unlimited");
|
|
328
|
+
expect(readCgroupMemory(unreadable)?.limitState).toBe("unreadable");
|
|
329
|
+
});
|
|
330
|
+
it("reports the v1 unlimited sentinel as unlimited, not unreadable", async () => {
|
|
331
|
+
const root = mkdtempSync(path.join(tmpdir(), "sb-cgroup-"));
|
|
332
|
+
const memoryRoot = path.join(root, "memory");
|
|
333
|
+
mkdirSync(memoryRoot);
|
|
334
|
+
writeFileSync(path.join(memoryRoot, "memory.usage_in_bytes"), "50\n");
|
|
335
|
+
writeFileSync(path.join(memoryRoot, "memory.limit_in_bytes"), "9223372036854775807\n");
|
|
336
|
+
const { readCgroupMemory } = await import("./memory-metrics.js");
|
|
337
|
+
expect(readCgroupMemory(root)?.limitState).toBe("unlimited");
|
|
338
|
+
});
|
|
339
|
+
it("reports a readable limit as available", async () => {
|
|
340
|
+
const root = mkdtempSync(path.join(tmpdir(), "sb-cgroup-"));
|
|
341
|
+
writeFileSync(path.join(root, "memory.current"), "50\n");
|
|
342
|
+
writeFileSync(path.join(root, "memory.max"), "200\n");
|
|
343
|
+
const { readCgroupMemory } = await import("./memory-metrics.js");
|
|
344
|
+
expect(readCgroupMemory(root)?.limitState).toBe("available");
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
describe("cgroup gauge emission", () => {
|
|
348
|
+
beforeEach(() => {
|
|
349
|
+
resetHarness();
|
|
350
|
+
});
|
|
351
|
+
it("emits current usage but omits limit and ratio when the cgroup is unlimited", async () => {
|
|
352
|
+
const root = mkdtempSync(path.join(tmpdir(), "sb-cgroup-"));
|
|
353
|
+
writeFileSync(path.join(root, "memory.current"), "2041380864\n");
|
|
354
|
+
writeFileSync(path.join(root, "memory.max"), "max\n");
|
|
355
|
+
const { startMemoryMetrics, stopMemoryMetrics } = await import("./memory-metrics.js");
|
|
356
|
+
startMemoryMetrics({ cgroupRoot: root });
|
|
357
|
+
const observations = observeAll();
|
|
358
|
+
stopMemoryMetrics();
|
|
359
|
+
const names = observations.map((o) => o.name);
|
|
360
|
+
expect(names).toContain("nodejs.memory.cgroup_current_bytes");
|
|
361
|
+
expect(names).not.toContain("nodejs.memory.cgroup_limit_bytes");
|
|
362
|
+
expect(names).not.toContain("nodejs.memory.cgroup_usage_ratio");
|
|
363
|
+
expect(observations.find((o) => o.name === "nodejs.memory.cgroup_current_bytes")
|
|
364
|
+
?.value).toBe(2041380864);
|
|
365
|
+
});
|
|
366
|
+
it("emits all three gauges when the cgroup limit is readable", async () => {
|
|
367
|
+
const root = mkdtempSync(path.join(tmpdir(), "sb-cgroup-"));
|
|
368
|
+
writeFileSync(path.join(root, "memory.current"), "50\n");
|
|
369
|
+
writeFileSync(path.join(root, "memory.max"), "200\n");
|
|
370
|
+
const { startMemoryMetrics, stopMemoryMetrics } = await import("./memory-metrics.js");
|
|
371
|
+
startMemoryMetrics({ cgroupRoot: root });
|
|
372
|
+
const observations = observeAll();
|
|
373
|
+
stopMemoryMetrics();
|
|
374
|
+
const names = observations.map((o) => o.name);
|
|
375
|
+
expect(names).toContain("nodejs.memory.cgroup_current_bytes");
|
|
376
|
+
expect(names).toContain("nodejs.memory.cgroup_limit_bytes");
|
|
377
|
+
expect(observations.find((o) => o.name === "nodejs.memory.cgroup_usage_ratio")
|
|
378
|
+
?.value).toBe(0.25);
|
|
379
|
+
});
|
|
380
|
+
it("labels current usage with the limit state so the no-limit case is filterable", async () => {
|
|
381
|
+
const root = mkdtempSync(path.join(tmpdir(), "sb-cgroup-"));
|
|
382
|
+
writeFileSync(path.join(root, "memory.current"), "2041380864\n");
|
|
383
|
+
writeFileSync(path.join(root, "memory.max"), "max\n");
|
|
384
|
+
const { startMemoryMetrics, stopMemoryMetrics } = await import("./memory-metrics.js");
|
|
385
|
+
startMemoryMetrics({ cgroupRoot: root });
|
|
386
|
+
const observations = observeAll();
|
|
387
|
+
stopMemoryMetrics();
|
|
388
|
+
expect(observations.find((o) => o.name === "nodejs.memory.cgroup_current_bytes")
|
|
389
|
+
?.attrs).toEqual({ "cgroup.limit_state": "unlimited" });
|
|
390
|
+
});
|
|
391
|
+
it("labels current usage as available when a real limit is present", async () => {
|
|
392
|
+
const root = mkdtempSync(path.join(tmpdir(), "sb-cgroup-"));
|
|
393
|
+
writeFileSync(path.join(root, "memory.current"), "50\n");
|
|
394
|
+
writeFileSync(path.join(root, "memory.max"), "200\n");
|
|
395
|
+
const { startMemoryMetrics, stopMemoryMetrics } = await import("./memory-metrics.js");
|
|
396
|
+
startMemoryMetrics({ cgroupRoot: root });
|
|
397
|
+
const observations = observeAll();
|
|
398
|
+
stopMemoryMetrics();
|
|
399
|
+
expect(observations.find((o) => o.name === "nodejs.memory.cgroup_current_bytes")
|
|
400
|
+
?.attrs).toEqual({ "cgroup.limit_state": "available" });
|
|
401
|
+
});
|
|
402
|
+
});
|
|
256
403
|
//# sourceMappingURL=memory-metrics.test.js.map
|