feat(config): add configurable default shutdown delay for shutdown actions

This commit is contained in:
2026-04-14 18:47:37 +00:00
parent 8dc0248763
commit 579667b3cd
13 changed files with 140 additions and 41 deletions
+39 -9
View File
@@ -12,9 +12,13 @@ import { MigrationRunner } from './migrations/index.ts';
import { formatPowerStatus, getBatteryColor, getRuntimeColor, theme } from './colors.ts';
import type { IActionConfig } from './actions/base-action.ts';
import { ActionManager } from './actions/index.ts';
import { decideUpsActionExecution, type TUpsTriggerReason } from './action-orchestration.ts';
import {
applyDefaultShutdownDelay,
decideUpsActionExecution,
type TUpsTriggerReason,
} from './action-orchestration.ts';
import { NupstHttpServer } from './http-server.ts';
import { NETWORK, PAUSE, THRESHOLDS, TIMING, UI } from './constants.ts';
import { NETWORK, PAUSE, SHUTDOWN, THRESHOLDS, TIMING, UI } from './constants.ts';
import {
analyzeConfigReload,
shouldRefreshPauseState,
@@ -97,6 +101,8 @@ export interface INupstConfig {
groups: IGroupConfig[];
/** Check interval in milliseconds */
checkInterval: number;
/** Default delay in minutes for shutdown actions without an override */
defaultShutdownDelay?: number;
/** HTTP Server configuration */
httpServer?: IHttpServerConfig;
@@ -125,6 +131,7 @@ export class NupstDaemon {
/** Default configuration */
private readonly DEFAULT_CONFIG: INupstConfig = {
version: '4.3',
defaultShutdownDelay: SHUTDOWN.DEFAULT_DELAY_MINUTES,
upsDevices: [
{
id: 'default',
@@ -155,7 +162,6 @@ export class NupstDaemon {
battery: THRESHOLDS.DEFAULT_BATTERY_PERCENT, // Shutdown when battery below 60%
runtime: THRESHOLDS.DEFAULT_RUNTIME_MINUTES, // Shutdown when runtime below 20 minutes
},
shutdownDelay: 5,
},
],
},
@@ -208,10 +214,13 @@ export class NupstDaemon {
const migrationRunner = new MigrationRunner();
const { config: migratedConfig, migrated } = await migrationRunner.run(parsedConfig);
// Save migrated config back to disk if any migrations ran
// Cast to INupstConfig since migrations ensure the output is valid
// Save migrated or normalized config back to disk when needed.
// Cast to INupstConfig since migrations ensure the output is valid.
const validConfig = migratedConfig as unknown as INupstConfig;
if (migrated) {
const normalizedShutdownDelay = this.normalizeShutdownDelay(validConfig.defaultShutdownDelay);
const shouldPersistNormalizedConfig = validConfig.defaultShutdownDelay !== normalizedShutdownDelay;
validConfig.defaultShutdownDelay = normalizedShutdownDelay;
if (migrated || shouldPersistNormalizedConfig) {
this.config = validConfig;
await this.saveConfig(this.config);
} else {
@@ -249,6 +258,7 @@ export class NupstDaemon {
upsDevices: config.upsDevices,
groups: config.groups,
checkInterval: config.checkInterval,
defaultShutdownDelay: this.normalizeShutdownDelay(config.defaultShutdownDelay),
...(config.httpServer ? { httpServer: config.httpServer } : {}),
};
@@ -280,6 +290,22 @@ export class NupstDaemon {
return this.config;
}
private normalizeShutdownDelay(delayMinutes: number | undefined): number {
if (
typeof delayMinutes !== 'number' ||
!Number.isFinite(delayMinutes) ||
delayMinutes < 0
) {
return SHUTDOWN.DEFAULT_DELAY_MINUTES;
}
return delayMinutes;
}
private getDefaultShutdownDelayMinutes(): number {
return this.normalizeShutdownDelay(this.config.defaultShutdownDelay);
}
/**
* Get the SNMP instance
*/
@@ -758,7 +784,12 @@ export class NupstDaemon {
return;
}
await ActionManager.executeActions(decision.actions, decision.context);
const actions = applyDefaultShutdownDelay(
decision.actions,
this.getDefaultShutdownDelayMinutes(),
);
await ActionManager.executeActions(actions, decision.context);
}
/**
@@ -768,8 +799,7 @@ export class NupstDaemon {
public async initiateShutdown(reason: string): Promise<void> {
logger.log(`Initiating system shutdown due to: ${reason}`);
// Set a longer delay for shutdown to allow VMs and services to close
const shutdownDelayMinutes = 5;
const shutdownDelayMinutes = this.getDefaultShutdownDelayMinutes();
try {
await this.shutdownExecutor.scheduleShutdown(shutdownDelayMinutes);