UNPKG

every-plugin

Version:
82 lines (73 loc) 2.78 kB
import { Effect, Exit, Ref, Scope } from "effect"; import type { AnyPlugin, InitializedPlugin } from "../../types"; import { toPluginRuntimeError } from "../errors"; export class PluginLifecycleService extends Effect.Service<PluginLifecycleService>()( "PluginLifecycleService", { effect: Effect.gen(function* () { const activePlugins = yield* Ref.make(new Set<InitializedPlugin<AnyPlugin>>()); return { register: <T extends AnyPlugin>(plugin: InitializedPlugin<T>) => Ref.update(activePlugins, (plugins) => new Set(plugins).add(plugin as InitializedPlugin<AnyPlugin>), ), unregister: (plugin: InitializedPlugin<AnyPlugin>) => Ref.update(activePlugins, (plugins) => { const newSet = new Set(plugins); newSet.delete(plugin); return newSet; }), shutdown: (plugin: InitializedPlugin<AnyPlugin>) => Effect.gen(function* () { // Remove from active plugins yield* Ref.update(activePlugins, (plugins) => { const newSet = new Set(plugins); newSet.delete(plugin); return newSet; }); // Shutdown the plugin yield* plugin.plugin .shutdown() .pipe( Effect.mapError((error) => toPluginRuntimeError( error, plugin.plugin.id, undefined, "shutdown-plugin", false, ), ), ); }), cleanup: () => Effect.gen(function* () { const plugins = yield* Ref.get(activePlugins); yield* Effect.forEach( plugins, (plugin) => Effect.gen(function* () { yield* plugin.plugin .shutdown() .pipe( Effect.catchAll((error) => Effect.logWarning(`Failed to shutdown plugin ${plugin.plugin.id}`, error), ), ); yield* Scope.close(plugin.scope, Exit.succeed(undefined)).pipe( Effect.catchAll((error) => Effect.logWarning( `Failed to close scope for plugin ${plugin.plugin.id}`, error, ), ), ); }), { concurrency: "unbounded" }, ); yield* Ref.set(activePlugins, new Set()); }).pipe(Effect.catchAll((error) => Effect.logWarning("Plugin cleanup failed", error))), }; }), }, ) {}