50 lines
1.7 KiB
JavaScript
50 lines
1.7 KiB
JavaScript
import { PlatformError } from './errors.mjs';
|
|
|
|
export class LifecycleManager {
|
|
#state = 'created';
|
|
#hooks = [];
|
|
|
|
register({ id, order = 100, start = async () => {}, stop = async () => {} }) {
|
|
if (!id || this.#hooks.some(hook => hook.id === id)) {
|
|
throw new PlatformError(`Ungültiger oder doppelter Lifecycle-Hook: ${id}`, { code: 'LIFECYCLE_HOOK_INVALID' });
|
|
}
|
|
this.#hooks.push({ id: String(id), order: Number(order) || 100, start, stop, state: 'registered' });
|
|
}
|
|
|
|
async start(context) {
|
|
if (!['created', 'stopped'].includes(this.#state)) throw new PlatformError(`Kernel kann aus Zustand ${this.#state} nicht starten.`, { code: 'LIFECYCLE_STATE_INVALID' });
|
|
this.#state = 'starting';
|
|
const started = [];
|
|
try {
|
|
for (const hook of [...this.#hooks].sort((a, b) => a.order - b.order)) {
|
|
hook.state = 'starting';
|
|
await hook.start(context);
|
|
hook.state = 'running';
|
|
started.push(hook);
|
|
}
|
|
this.#state = 'running';
|
|
} catch (error) {
|
|
for (const hook of started.reverse()) {
|
|
try { await hook.stop({ ...context, rollback: true }); } catch {}
|
|
hook.state = 'stopped';
|
|
}
|
|
this.#state = 'failed';
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async stop(context) {
|
|
if (!['running', 'starting'].includes(this.#state)) return;
|
|
this.#state = 'stopping';
|
|
for (const hook of [...this.#hooks].sort((a, b) => b.order - a.order)) {
|
|
if (hook.state !== 'running') continue;
|
|
try { await hook.stop(context); } finally { hook.state = 'stopped'; }
|
|
}
|
|
this.#state = 'stopped';
|
|
}
|
|
|
|
snapshot() {
|
|
return { state: this.#state, hooks: this.#hooks.map(({ start: _s, stop: _t, ...hook }) => ({ ...hook })) };
|
|
}
|
|
}
|