Files
stack/apps/gateway/src/reload/reload.service.ts
Jarvis 774b76447d
Some checks failed
ci/woodpecker/pr/ci Pipeline failed
ci/woodpecker/push/ci Pipeline failed
fix: rename all packages from @mosaic/* to @mosaicstack/*
- Updated all package.json name fields and dependency references
- Updated all TypeScript/JavaScript imports
- Updated .woodpecker/publish.yml filters and registry paths
- Updated tools/install.sh scope default
- Updated .npmrc registry paths (worktree + host)
- Enhanced update-checker.ts with checkForAllUpdates() multi-package support
- Updated CLI update command to show table of all packages
- Added KNOWN_PACKAGES, formatAllPackagesTable, getInstallAllCommand
- Marked checkForUpdate() with @deprecated JSDoc

Closes #391
2026-04-04 21:43:23 -05:00

93 lines
2.8 KiB
TypeScript

import {
Inject,
Injectable,
Logger,
type OnApplicationBootstrap,
type OnApplicationShutdown,
} from '@nestjs/common';
import type { SystemReloadPayload } from '@mosaicstack/types';
import { CommandRegistryService } from '../commands/command-registry.service.js';
import { isMosaicPlugin } from './mosaic-plugin.interface.js';
@Injectable()
export class ReloadService implements OnApplicationBootstrap, OnApplicationShutdown {
private readonly logger = new Logger(ReloadService.name);
private readonly plugins: Map<string, unknown> = new Map();
private shutdownHandlerAttached = false;
constructor(
@Inject(CommandRegistryService) private readonly commandRegistry: CommandRegistryService,
) {}
onApplicationBootstrap(): void {
if (!this.shutdownHandlerAttached) {
process.on('SIGHUP', () => {
this.logger.log('SIGHUP received — triggering soft reload');
this.reload('sighup').catch((err: unknown) => {
this.logger.error(`SIGHUP reload failed: ${err}`);
});
});
this.shutdownHandlerAttached = true;
}
}
onApplicationShutdown(): void {
process.removeAllListeners('SIGHUP');
}
registerPlugin(name: string, plugin: unknown): void {
this.plugins.set(name, plugin);
this.logger.log(`Plugin registered: ${name}`);
}
/**
* Soft reload — unload plugins, reload plugins, broadcast.
* Does NOT restart the HTTP server or drop connections.
*/
async reload(
trigger: 'command' | 'rest' | 'sighup' | 'file-watch',
): Promise<SystemReloadPayload> {
this.logger.log(`Soft reload triggered by: ${trigger}`);
const reloaded: string[] = [];
const errors: string[] = [];
// 1. Unload all registered MosaicPlugin instances
for (const [name, plugin] of this.plugins) {
if (isMosaicPlugin(plugin)) {
try {
await plugin.onUnload();
reloaded.push(name);
} catch (err) {
errors.push(`${name}: unload failed — ${err}`);
}
}
}
// 2. Reload all MosaicPlugin instances
for (const [name, plugin] of this.plugins) {
if (isMosaicPlugin(plugin)) {
try {
await plugin.onLoad();
} catch (err) {
errors.push(`${name}: load failed — ${err}`);
}
}
}
const manifest = this.commandRegistry.getManifest();
const errorSuffix = errors.length > 0 ? ` Errors: ${errors.join(', ')}` : '';
const payload: SystemReloadPayload = {
commands: manifest.commands,
skills: manifest.skills,
providers: [],
message: `Reload complete (trigger=${trigger}). Plugins reloaded: [${reloaded.join(', ')}].${errorSuffix}`,
};
this.logger.log(
`Reload complete. Reloaded: [${reloaded.join(', ')}]. Errors: ${errors.length}`,
);
return payload;
}
}