feat(daemon): Persist desired process states and add daemon restart command
This commit is contained in:
@@ -25,6 +25,8 @@ export class ProcessManager extends EventEmitter {
|
||||
public processInfo: Map<string, IProcessInfo> = new Map();
|
||||
private config: TspmConfig;
|
||||
private configStorageKey = 'processes';
|
||||
private desiredStateStorageKey = 'desiredStates';
|
||||
private desiredStates: Map<string, IProcessInfo['status']> = new Map();
|
||||
private logger: Logger;
|
||||
|
||||
constructor() {
|
||||
@@ -32,6 +34,7 @@ export class ProcessManager extends EventEmitter {
|
||||
this.logger = new Logger('Tspm');
|
||||
this.config = new TspmConfig();
|
||||
this.loadProcessConfigs();
|
||||
this.loadDesiredStates();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,6 +70,7 @@ export class ProcessManager extends EventEmitter {
|
||||
});
|
||||
|
||||
await this.saveProcessConfigs();
|
||||
await this.setDesiredState(config.id, 'stopped');
|
||||
return config.id;
|
||||
}
|
||||
|
||||
@@ -279,6 +283,7 @@ export class ProcessManager extends EventEmitter {
|
||||
|
||||
// Save updated configs
|
||||
await this.saveProcessConfigs();
|
||||
await this.removeDesiredState(id);
|
||||
|
||||
this.logger.info(`Successfully deleted process with id '${id}'`);
|
||||
} catch (error: Error | unknown) {
|
||||
@@ -288,6 +293,7 @@ export class ProcessManager extends EventEmitter {
|
||||
this.processConfigs.delete(id);
|
||||
this.processInfo.delete(id);
|
||||
await this.saveProcessConfigs();
|
||||
await this.removeDesiredState(id);
|
||||
|
||||
this.logger.info(
|
||||
`Successfully deleted process with id '${id}' after stopping failure`,
|
||||
@@ -415,6 +421,80 @@ export class ProcessManager extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
// === Desired state persistence ===
|
||||
private async saveDesiredStates(): Promise<void> {
|
||||
try {
|
||||
const obj: Record<string, IProcessInfo['status']> = {};
|
||||
for (const [id, state] of this.desiredStates.entries()) {
|
||||
obj[id] = state;
|
||||
}
|
||||
await this.config.writeKey(
|
||||
this.desiredStateStorageKey,
|
||||
JSON.stringify(obj),
|
||||
);
|
||||
} catch (error: any) {
|
||||
this.logger.warn(
|
||||
`Failed to save desired states: ${error?.message || String(error)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public async loadDesiredStates(): Promise<void> {
|
||||
try {
|
||||
const raw = await this.config.readKey(this.desiredStateStorageKey);
|
||||
if (raw) {
|
||||
const obj = JSON.parse(raw) as Record<string, IProcessInfo['status']>;
|
||||
this.desiredStates = new Map(Object.entries(obj));
|
||||
this.logger.debug(
|
||||
`Loaded desired states for ${this.desiredStates.size} processes`,
|
||||
);
|
||||
}
|
||||
} catch (error: any) {
|
||||
this.logger.warn(
|
||||
`Failed to load desired states: ${error?.message || String(error)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public async setDesiredState(
|
||||
id: string,
|
||||
state: IProcessInfo['status'],
|
||||
): Promise<void> {
|
||||
this.desiredStates.set(id, state);
|
||||
await this.saveDesiredStates();
|
||||
}
|
||||
|
||||
public async removeDesiredState(id: string): Promise<void> {
|
||||
this.desiredStates.delete(id);
|
||||
await this.saveDesiredStates();
|
||||
}
|
||||
|
||||
public async setDesiredStateForAll(
|
||||
state: IProcessInfo['status'],
|
||||
): Promise<void> {
|
||||
for (const id of this.processConfigs.keys()) {
|
||||
this.desiredStates.set(id, state);
|
||||
}
|
||||
await this.saveDesiredStates();
|
||||
}
|
||||
|
||||
public async startDesired(): Promise<void> {
|
||||
for (const [id, config] of this.processConfigs.entries()) {
|
||||
const desired = this.desiredStates.get(id);
|
||||
if (desired === 'online' && !this.processes.has(id)) {
|
||||
try {
|
||||
await this.start(config);
|
||||
} catch (e) {
|
||||
this.logger.warn(
|
||||
`Failed to start desired process ${id}: ${
|
||||
(e as Error)?.message || String(e)
|
||||
}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load process configurations from config storage
|
||||
*/
|
||||
@@ -499,10 +579,12 @@ export class ProcessManager extends EventEmitter {
|
||||
this.processes.clear();
|
||||
this.processInfo.clear();
|
||||
this.processConfigs.clear();
|
||||
this.desiredStates.clear();
|
||||
|
||||
// Remove persisted configs
|
||||
try {
|
||||
await this.config.deleteKey(this.configStorageKey);
|
||||
await this.config.deleteKey(this.desiredStateStorageKey).catch(() => {});
|
||||
this.logger.debug('Cleared persisted process configurations');
|
||||
} catch (error) {
|
||||
// Fallback: write empty list if deleteKey fails for any reason
|
||||
|
Reference in New Issue
Block a user