@camstack/system 1.2.360 → 1.2.361
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/dist/builtins/native-metrics/native-metrics.addon.d.ts +16 -0
- package/dist/builtins/native-metrics/native-metrics.addon.js +51 -13
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +51 -13
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
- package/package.json +1 -1
|
@@ -151,6 +151,22 @@ export default class NativeMetricsAddon extends BaseAddon<NativeMetricsConfig> {
|
|
|
151
151
|
* is why the retention default is six hours rather than three days.
|
|
152
152
|
*/
|
|
153
153
|
private startProcessSnapshotTimer;
|
|
154
|
+
/**
|
|
155
|
+
* Run one periodic tick so that it can NEVER become an unhandled rejection.
|
|
156
|
+
*
|
|
157
|
+
* `clearInterval` in `onShutdown` stops FUTURE ticks; it cannot recall one
|
|
158
|
+
* already in flight. A process tick awaits a `/proc` read and a
|
|
159
|
+
* `$process.list` broker call, and a graceful stop shuts this addon down
|
|
160
|
+
* (nulling `ctx`) while the agent goes on to stop its other addons and the
|
|
161
|
+
* broker — so the tick resumed with no context, its catch block reached for
|
|
162
|
+
* `this.ctx.logger`, threw again, and the rejection of the timer callback
|
|
163
|
+
* killed `docker stop CamStack-Agent` with exit code 1 (little-unraid,
|
|
164
|
+
* 2026-10-07 04:22Z). The ticks themselves now capture their context once
|
|
165
|
+
* and stand down when it is gone; this wrapper is the backstop.
|
|
166
|
+
*
|
|
167
|
+
* A tick before `initialize()` or after `shutdown()` is a no-op.
|
|
168
|
+
*/
|
|
169
|
+
private runTick;
|
|
154
170
|
protected onShutdown(): Promise<void>;
|
|
155
171
|
/**
|
|
156
172
|
* Resolve this node's short id (strips any `nodeId/addonId` suffix).
|
|
@@ -3014,7 +3014,8 @@ var NativeMetricsAddon = class NativeMetricsAddon extends require_dist.BaseAddon
|
|
|
3014
3014
|
}
|
|
3015
3015
|
this.memoryProbe = new ContainerMemoryProbe({ logger: this.ctx.logger.child("ContainerMemory") });
|
|
3016
3016
|
this.pidsProbe = new ContainerPidsProbe({ logger: this.ctx.logger.child("ContainerPids") });
|
|
3017
|
-
this.snapshotTimer
|
|
3017
|
+
if (this.snapshotTimer) clearInterval(this.snapshotTimer);
|
|
3018
|
+
this.snapshotTimer = setInterval(() => this.runTick("resources snapshot", () => this.emitResourcesSnapshot()), METRICS_SNAPSHOT_INTERVAL_MS);
|
|
3018
3019
|
this.startProcessSnapshotTimer();
|
|
3019
3020
|
this.ctx.addDisposer(this.ctx.eventBus.subscribe({ category: require_dist.EventCategory.MetricsNodeProcessesSnapshot }, (event) => this.retainSnapshot(event.data.nodeId, event.data.timestamp, event.data.processes, event.data.containerMemory)));
|
|
3020
3021
|
return [{
|
|
@@ -3179,7 +3180,33 @@ var NativeMetricsAddon = class NativeMetricsAddon extends require_dist.BaseAddon
|
|
|
3179
3180
|
*/
|
|
3180
3181
|
startProcessSnapshotTimer() {
|
|
3181
3182
|
if (this.processSnapshotTimer) clearInterval(this.processSnapshotTimer);
|
|
3182
|
-
this.processSnapshotTimer =
|
|
3183
|
+
this.processSnapshotTimer = null;
|
|
3184
|
+
if (!this.ctxIfReady) return;
|
|
3185
|
+
this.processSnapshotTimer = setInterval(() => this.runTick("process snapshot", () => this.emitProcessesSnapshot()), this.loadConfig.cadenceSec * 1e3);
|
|
3186
|
+
}
|
|
3187
|
+
/**
|
|
3188
|
+
* Run one periodic tick so that it can NEVER become an unhandled rejection.
|
|
3189
|
+
*
|
|
3190
|
+
* `clearInterval` in `onShutdown` stops FUTURE ticks; it cannot recall one
|
|
3191
|
+
* already in flight. A process tick awaits a `/proc` read and a
|
|
3192
|
+
* `$process.list` broker call, and a graceful stop shuts this addon down
|
|
3193
|
+
* (nulling `ctx`) while the agent goes on to stop its other addons and the
|
|
3194
|
+
* broker — so the tick resumed with no context, its catch block reached for
|
|
3195
|
+
* `this.ctx.logger`, threw again, and the rejection of the timer callback
|
|
3196
|
+
* killed `docker stop CamStack-Agent` with exit code 1 (little-unraid,
|
|
3197
|
+
* 2026-10-07 04:22Z). The ticks themselves now capture their context once
|
|
3198
|
+
* and stand down when it is gone; this wrapper is the backstop.
|
|
3199
|
+
*
|
|
3200
|
+
* A tick before `initialize()` or after `shutdown()` is a no-op.
|
|
3201
|
+
*/
|
|
3202
|
+
runTick(name, tick) {
|
|
3203
|
+
if (!this.ctxIfReady) return;
|
|
3204
|
+
tick().catch((err) => {
|
|
3205
|
+
this.ctxIfReady?.logger.warn("native-metrics tick failed — this interval will be missing", { meta: {
|
|
3206
|
+
tick: name,
|
|
3207
|
+
error: err instanceof Error ? err.message : String(err)
|
|
3208
|
+
} });
|
|
3209
|
+
});
|
|
3183
3210
|
}
|
|
3184
3211
|
async onShutdown() {
|
|
3185
3212
|
if (this.snapshotTimer) {
|
|
@@ -3197,9 +3224,9 @@ var NativeMetricsAddon = class NativeMetricsAddon extends require_dist.BaseAddon
|
|
|
3197
3224
|
* Resolve this node's short id (strips any `nodeId/addonId` suffix).
|
|
3198
3225
|
* Returns null when the provider or event bus isn't available yet.
|
|
3199
3226
|
*/
|
|
3200
|
-
resolveSnapshotNodeId() {
|
|
3201
|
-
if (!this.provider || !
|
|
3202
|
-
const rawNodeId =
|
|
3227
|
+
resolveSnapshotNodeId(ctx) {
|
|
3228
|
+
if (!this.provider || !ctx.eventBus) return null;
|
|
3229
|
+
const rawNodeId = ctx.kernel.localNodeId ?? ctx.id;
|
|
3203
3230
|
return rawNodeId.includes("/") ? rawNodeId.split("/")[0] : rawNodeId;
|
|
3204
3231
|
}
|
|
3205
3232
|
/**
|
|
@@ -3208,13 +3235,16 @@ var NativeMetricsAddon = class NativeMetricsAddon extends require_dist.BaseAddon
|
|
|
3208
3235
|
* runs at samplingIntervalMs). Fires on METRICS_SNAPSHOT_INTERVAL_MS.
|
|
3209
3236
|
*/
|
|
3210
3237
|
async emitResourcesSnapshot() {
|
|
3238
|
+
const ctx = this.ctxIfReady;
|
|
3239
|
+
if (!ctx) return;
|
|
3211
3240
|
const provider = this.provider;
|
|
3212
|
-
const eventBus =
|
|
3213
|
-
const nodeId = this.resolveSnapshotNodeId();
|
|
3241
|
+
const eventBus = ctx.eventBus;
|
|
3242
|
+
const nodeId = this.resolveSnapshotNodeId(ctx);
|
|
3214
3243
|
if (!provider || !eventBus || !nodeId) return;
|
|
3215
3244
|
const timestamp = Date.now();
|
|
3216
3245
|
try {
|
|
3217
3246
|
const snapshot = await provider.getCached() ?? await provider.collectSnapshot();
|
|
3247
|
+
if (this.ctxIfReady !== ctx) return;
|
|
3218
3248
|
const coarse = coarsenResourcesSnapshot(snapshot);
|
|
3219
3249
|
const prev = this.lastResourcesEmit;
|
|
3220
3250
|
const heartbeatDue = !prev || timestamp - prev.emittedAt >= METRICS_SNAPSHOT_HEARTBEAT_MS;
|
|
@@ -3247,12 +3277,18 @@ var NativeMetricsAddon = class NativeMetricsAddon extends require_dist.BaseAddon
|
|
|
3247
3277
|
* A failed scan emits nothing, which is the same signal: nobody reported.
|
|
3248
3278
|
*/
|
|
3249
3279
|
async emitProcessesSnapshot() {
|
|
3250
|
-
const
|
|
3251
|
-
|
|
3280
|
+
const ctx = this.ctxIfReady;
|
|
3281
|
+
if (!ctx) return;
|
|
3282
|
+
const eventBus = ctx.eventBus;
|
|
3283
|
+
const nodeId = this.resolveSnapshotNodeId(ctx);
|
|
3252
3284
|
if (!this.provider || !eventBus || !nodeId) return;
|
|
3253
3285
|
const timestamp = Date.now();
|
|
3254
3286
|
try {
|
|
3255
3287
|
const processes = await this.listNodeProcesses();
|
|
3288
|
+
if (this.ctxIfReady !== ctx) {
|
|
3289
|
+
ctx.logger.debug("process snapshot dropped — addon shut down mid-tick", { meta: { nodeId } });
|
|
3290
|
+
return;
|
|
3291
|
+
}
|
|
3256
3292
|
const containerMemory = this.memoryProbe?.sample() ?? null;
|
|
3257
3293
|
this.pidsProbe?.sample();
|
|
3258
3294
|
eventBus.emit(require_dist.createEvent(require_dist.EventCategory.MetricsNodeProcessesSnapshot, {
|
|
@@ -3266,20 +3302,21 @@ var NativeMetricsAddon = class NativeMetricsAddon extends require_dist.BaseAddon
|
|
|
3266
3302
|
containerMemory
|
|
3267
3303
|
}));
|
|
3268
3304
|
} catch (err) {
|
|
3269
|
-
|
|
3305
|
+
ctx.logger.warn("process snapshot skipped — this interval will be missing", { meta: {
|
|
3270
3306
|
nodeId,
|
|
3271
3307
|
error: err instanceof Error ? err.message : String(err)
|
|
3272
3308
|
} });
|
|
3273
3309
|
}
|
|
3274
3310
|
}
|
|
3275
3311
|
async onConfigChanged() {
|
|
3312
|
+
if (!this.ctxIfReady) return;
|
|
3276
3313
|
this.provider?.stopSampling();
|
|
3277
3314
|
this.provider?.startSampling(this.config.samplingIntervalMs);
|
|
3278
3315
|
this.applyLoadSeriesConfig();
|
|
3279
3316
|
this.startProcessSnapshotTimer();
|
|
3280
3317
|
}
|
|
3281
3318
|
async listWorkerInstances() {
|
|
3282
|
-
const broker = this.
|
|
3319
|
+
const broker = this.ctxIfReady?.kernel.cluster?.broker;
|
|
3283
3320
|
if (!broker) return [];
|
|
3284
3321
|
try {
|
|
3285
3322
|
return await broker.call("$process.list");
|
|
@@ -3326,6 +3363,7 @@ var NativeMetricsAddon = class NativeMetricsAddon extends require_dist.BaseAddon
|
|
|
3326
3363
|
* walk behind them — live in `process-classification.ts`.
|
|
3327
3364
|
*/
|
|
3328
3365
|
async listNodeProcesses() {
|
|
3366
|
+
const selfNodeId = this.ctx.kernel.cluster?.broker?.nodeID ?? "hub";
|
|
3329
3367
|
const ps = await this.runPs();
|
|
3330
3368
|
if (ps.length === 0) return [];
|
|
3331
3369
|
const managed = /* @__PURE__ */ new Map();
|
|
@@ -3339,7 +3377,7 @@ var NativeMetricsAddon = class NativeMetricsAddon extends require_dist.BaseAddon
|
|
|
3339
3377
|
return buildNodeProcesses({
|
|
3340
3378
|
psRows: ps,
|
|
3341
3379
|
selfPid: process.pid,
|
|
3342
|
-
selfNodeId
|
|
3380
|
+
selfNodeId,
|
|
3343
3381
|
managed,
|
|
3344
3382
|
cpuSplits
|
|
3345
3383
|
});
|
|
@@ -3355,7 +3393,7 @@ var NativeMetricsAddon = class NativeMetricsAddon extends require_dist.BaseAddon
|
|
|
3355
3393
|
try {
|
|
3356
3394
|
return await readProcessTable();
|
|
3357
3395
|
} catch (err) {
|
|
3358
|
-
this.
|
|
3396
|
+
this.ctxIfReady?.logger.warn("process table read failed", { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
3359
3397
|
return [];
|
|
3360
3398
|
}
|
|
3361
3399
|
}
|
|
@@ -3009,7 +3009,8 @@ var NativeMetricsAddon = class NativeMetricsAddon extends BaseAddon {
|
|
|
3009
3009
|
}
|
|
3010
3010
|
this.memoryProbe = new ContainerMemoryProbe({ logger: this.ctx.logger.child("ContainerMemory") });
|
|
3011
3011
|
this.pidsProbe = new ContainerPidsProbe({ logger: this.ctx.logger.child("ContainerPids") });
|
|
3012
|
-
this.snapshotTimer
|
|
3012
|
+
if (this.snapshotTimer) clearInterval(this.snapshotTimer);
|
|
3013
|
+
this.snapshotTimer = setInterval(() => this.runTick("resources snapshot", () => this.emitResourcesSnapshot()), METRICS_SNAPSHOT_INTERVAL_MS);
|
|
3013
3014
|
this.startProcessSnapshotTimer();
|
|
3014
3015
|
this.ctx.addDisposer(this.ctx.eventBus.subscribe({ category: EventCategory.MetricsNodeProcessesSnapshot }, (event) => this.retainSnapshot(event.data.nodeId, event.data.timestamp, event.data.processes, event.data.containerMemory)));
|
|
3015
3016
|
return [{
|
|
@@ -3174,7 +3175,33 @@ var NativeMetricsAddon = class NativeMetricsAddon extends BaseAddon {
|
|
|
3174
3175
|
*/
|
|
3175
3176
|
startProcessSnapshotTimer() {
|
|
3176
3177
|
if (this.processSnapshotTimer) clearInterval(this.processSnapshotTimer);
|
|
3177
|
-
this.processSnapshotTimer =
|
|
3178
|
+
this.processSnapshotTimer = null;
|
|
3179
|
+
if (!this.ctxIfReady) return;
|
|
3180
|
+
this.processSnapshotTimer = setInterval(() => this.runTick("process snapshot", () => this.emitProcessesSnapshot()), this.loadConfig.cadenceSec * 1e3);
|
|
3181
|
+
}
|
|
3182
|
+
/**
|
|
3183
|
+
* Run one periodic tick so that it can NEVER become an unhandled rejection.
|
|
3184
|
+
*
|
|
3185
|
+
* `clearInterval` in `onShutdown` stops FUTURE ticks; it cannot recall one
|
|
3186
|
+
* already in flight. A process tick awaits a `/proc` read and a
|
|
3187
|
+
* `$process.list` broker call, and a graceful stop shuts this addon down
|
|
3188
|
+
* (nulling `ctx`) while the agent goes on to stop its other addons and the
|
|
3189
|
+
* broker — so the tick resumed with no context, its catch block reached for
|
|
3190
|
+
* `this.ctx.logger`, threw again, and the rejection of the timer callback
|
|
3191
|
+
* killed `docker stop CamStack-Agent` with exit code 1 (little-unraid,
|
|
3192
|
+
* 2026-10-07 04:22Z). The ticks themselves now capture their context once
|
|
3193
|
+
* and stand down when it is gone; this wrapper is the backstop.
|
|
3194
|
+
*
|
|
3195
|
+
* A tick before `initialize()` or after `shutdown()` is a no-op.
|
|
3196
|
+
*/
|
|
3197
|
+
runTick(name, tick) {
|
|
3198
|
+
if (!this.ctxIfReady) return;
|
|
3199
|
+
tick().catch((err) => {
|
|
3200
|
+
this.ctxIfReady?.logger.warn("native-metrics tick failed — this interval will be missing", { meta: {
|
|
3201
|
+
tick: name,
|
|
3202
|
+
error: err instanceof Error ? err.message : String(err)
|
|
3203
|
+
} });
|
|
3204
|
+
});
|
|
3178
3205
|
}
|
|
3179
3206
|
async onShutdown() {
|
|
3180
3207
|
if (this.snapshotTimer) {
|
|
@@ -3192,9 +3219,9 @@ var NativeMetricsAddon = class NativeMetricsAddon extends BaseAddon {
|
|
|
3192
3219
|
* Resolve this node's short id (strips any `nodeId/addonId` suffix).
|
|
3193
3220
|
* Returns null when the provider or event bus isn't available yet.
|
|
3194
3221
|
*/
|
|
3195
|
-
resolveSnapshotNodeId() {
|
|
3196
|
-
if (!this.provider || !
|
|
3197
|
-
const rawNodeId =
|
|
3222
|
+
resolveSnapshotNodeId(ctx) {
|
|
3223
|
+
if (!this.provider || !ctx.eventBus) return null;
|
|
3224
|
+
const rawNodeId = ctx.kernel.localNodeId ?? ctx.id;
|
|
3198
3225
|
return rawNodeId.includes("/") ? rawNodeId.split("/")[0] : rawNodeId;
|
|
3199
3226
|
}
|
|
3200
3227
|
/**
|
|
@@ -3203,13 +3230,16 @@ var NativeMetricsAddon = class NativeMetricsAddon extends BaseAddon {
|
|
|
3203
3230
|
* runs at samplingIntervalMs). Fires on METRICS_SNAPSHOT_INTERVAL_MS.
|
|
3204
3231
|
*/
|
|
3205
3232
|
async emitResourcesSnapshot() {
|
|
3233
|
+
const ctx = this.ctxIfReady;
|
|
3234
|
+
if (!ctx) return;
|
|
3206
3235
|
const provider = this.provider;
|
|
3207
|
-
const eventBus =
|
|
3208
|
-
const nodeId = this.resolveSnapshotNodeId();
|
|
3236
|
+
const eventBus = ctx.eventBus;
|
|
3237
|
+
const nodeId = this.resolveSnapshotNodeId(ctx);
|
|
3209
3238
|
if (!provider || !eventBus || !nodeId) return;
|
|
3210
3239
|
const timestamp = Date.now();
|
|
3211
3240
|
try {
|
|
3212
3241
|
const snapshot = await provider.getCached() ?? await provider.collectSnapshot();
|
|
3242
|
+
if (this.ctxIfReady !== ctx) return;
|
|
3213
3243
|
const coarse = coarsenResourcesSnapshot(snapshot);
|
|
3214
3244
|
const prev = this.lastResourcesEmit;
|
|
3215
3245
|
const heartbeatDue = !prev || timestamp - prev.emittedAt >= METRICS_SNAPSHOT_HEARTBEAT_MS;
|
|
@@ -3242,12 +3272,18 @@ var NativeMetricsAddon = class NativeMetricsAddon extends BaseAddon {
|
|
|
3242
3272
|
* A failed scan emits nothing, which is the same signal: nobody reported.
|
|
3243
3273
|
*/
|
|
3244
3274
|
async emitProcessesSnapshot() {
|
|
3245
|
-
const
|
|
3246
|
-
|
|
3275
|
+
const ctx = this.ctxIfReady;
|
|
3276
|
+
if (!ctx) return;
|
|
3277
|
+
const eventBus = ctx.eventBus;
|
|
3278
|
+
const nodeId = this.resolveSnapshotNodeId(ctx);
|
|
3247
3279
|
if (!this.provider || !eventBus || !nodeId) return;
|
|
3248
3280
|
const timestamp = Date.now();
|
|
3249
3281
|
try {
|
|
3250
3282
|
const processes = await this.listNodeProcesses();
|
|
3283
|
+
if (this.ctxIfReady !== ctx) {
|
|
3284
|
+
ctx.logger.debug("process snapshot dropped — addon shut down mid-tick", { meta: { nodeId } });
|
|
3285
|
+
return;
|
|
3286
|
+
}
|
|
3251
3287
|
const containerMemory = this.memoryProbe?.sample() ?? null;
|
|
3252
3288
|
this.pidsProbe?.sample();
|
|
3253
3289
|
eventBus.emit(createEvent(EventCategory.MetricsNodeProcessesSnapshot, {
|
|
@@ -3261,20 +3297,21 @@ var NativeMetricsAddon = class NativeMetricsAddon extends BaseAddon {
|
|
|
3261
3297
|
containerMemory
|
|
3262
3298
|
}));
|
|
3263
3299
|
} catch (err) {
|
|
3264
|
-
|
|
3300
|
+
ctx.logger.warn("process snapshot skipped — this interval will be missing", { meta: {
|
|
3265
3301
|
nodeId,
|
|
3266
3302
|
error: err instanceof Error ? err.message : String(err)
|
|
3267
3303
|
} });
|
|
3268
3304
|
}
|
|
3269
3305
|
}
|
|
3270
3306
|
async onConfigChanged() {
|
|
3307
|
+
if (!this.ctxIfReady) return;
|
|
3271
3308
|
this.provider?.stopSampling();
|
|
3272
3309
|
this.provider?.startSampling(this.config.samplingIntervalMs);
|
|
3273
3310
|
this.applyLoadSeriesConfig();
|
|
3274
3311
|
this.startProcessSnapshotTimer();
|
|
3275
3312
|
}
|
|
3276
3313
|
async listWorkerInstances() {
|
|
3277
|
-
const broker = this.
|
|
3314
|
+
const broker = this.ctxIfReady?.kernel.cluster?.broker;
|
|
3278
3315
|
if (!broker) return [];
|
|
3279
3316
|
try {
|
|
3280
3317
|
return await broker.call("$process.list");
|
|
@@ -3321,6 +3358,7 @@ var NativeMetricsAddon = class NativeMetricsAddon extends BaseAddon {
|
|
|
3321
3358
|
* walk behind them — live in `process-classification.ts`.
|
|
3322
3359
|
*/
|
|
3323
3360
|
async listNodeProcesses() {
|
|
3361
|
+
const selfNodeId = this.ctx.kernel.cluster?.broker?.nodeID ?? "hub";
|
|
3324
3362
|
const ps = await this.runPs();
|
|
3325
3363
|
if (ps.length === 0) return [];
|
|
3326
3364
|
const managed = /* @__PURE__ */ new Map();
|
|
@@ -3334,7 +3372,7 @@ var NativeMetricsAddon = class NativeMetricsAddon extends BaseAddon {
|
|
|
3334
3372
|
return buildNodeProcesses({
|
|
3335
3373
|
psRows: ps,
|
|
3336
3374
|
selfPid: process.pid,
|
|
3337
|
-
selfNodeId
|
|
3375
|
+
selfNodeId,
|
|
3338
3376
|
managed,
|
|
3339
3377
|
cpuSplits
|
|
3340
3378
|
});
|
|
@@ -3350,7 +3388,7 @@ var NativeMetricsAddon = class NativeMetricsAddon extends BaseAddon {
|
|
|
3350
3388
|
try {
|
|
3351
3389
|
return await readProcessTable();
|
|
3352
3390
|
} catch (err) {
|
|
3353
|
-
this.
|
|
3391
|
+
this.ctxIfReady?.logger.warn("process table read failed", { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
3354
3392
|
return [];
|
|
3355
3393
|
}
|
|
3356
3394
|
}
|
|
@@ -3886,7 +3886,7 @@ var StorageOrchestratorAddon = class extends require_dist.BaseAddon {
|
|
|
3886
3886
|
try {
|
|
3887
3887
|
await this.pressureManager.sweep();
|
|
3888
3888
|
} catch (err) {
|
|
3889
|
-
this.
|
|
3889
|
+
this.ctxIfReady?.logger.warn("storage pressure sweep failed", { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
3890
3890
|
} finally {
|
|
3891
3891
|
this.pressureSweepInFlight = false;
|
|
3892
3892
|
}
|
|
@@ -3881,7 +3881,7 @@ var StorageOrchestratorAddon = class extends BaseAddon {
|
|
|
3881
3881
|
try {
|
|
3882
3882
|
await this.pressureManager.sweep();
|
|
3883
3883
|
} catch (err) {
|
|
3884
|
-
this.
|
|
3884
|
+
this.ctxIfReady?.logger.warn("storage pressure sweep failed", { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
3885
3885
|
} finally {
|
|
3886
3886
|
this.pressureSweepInFlight = false;
|
|
3887
3887
|
}
|