UNPKG

@node-ts/bus-workflow

Version:

A workflow engine for orchestrating logic flows in distributed applications.

111 lines 5.98 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WorkflowRegistry = void 0; const tslib_1 = require("tslib"); const inversify_1 = require("inversify"); const bus_core_1 = require("@node-ts/bus-core"); const bus_workflow_symbols_1 = require("../../bus-workflow-symbols"); const started_by_1 = require("../decorators/started-by"); const handles_1 = require("../decorators/handles"); const logger_core_1 = require("@node-ts/logger-core"); /** * The central workflow registry that holds all workflows managed by the application. This includes * - the list of workflows * - what messages start the workflow * - what messages are handled by each workflow */ let WorkflowRegistry = class WorkflowRegistry { constructor(handlerRegistry, persistence, startedByFactory, handlesFactory, logger) { this.handlerRegistry = handlerRegistry; this.persistence = persistence; this.startedByFactory = startedByFactory; this.handlesFactory = handlesFactory; this.logger = logger; this.workflowRegistry = []; this.isInitialized = false; this.isInitializing = false; } register(workflowConstructor, workflowDataConstructor) { if (this.isInitialized) { throw new Error(`Attempted to register workflow (${workflowConstructor.name}) after workflows have been initialized`); } const duplicateWorkflowName = this.workflowRegistry .some(r => r.workflowConstructor.name === workflowConstructor.name); if (duplicateWorkflowName) { throw new Error(`Attempted to register two workflows with the same name (${workflowConstructor.name})`); } this.workflowRegistry.push({ workflowConstructor, workflowDataConstructor }); } /** * Initialize all services that are used to support workflows. This registers all messages subscribed to * in workflows as handlers with the bus, as well as initializing the persistence service so that workflow * states can be stored. * * This should be called once as the application is starting. */ async initializeWorkflows() { if (this.isInitialized || this.isInitializing) { throw new Error('Attempted to initialize workflow registry after it has already been initialized.'); } this.isInitializing = true; this.logger.info('Initializing workflows...'); if (this.persistence.initialize) { await this.persistence.initialize(); } for (const registration of this.workflowRegistry) { const startedByHandlers = started_by_1.WorkflowStartedByMetadata.getSteps(registration.workflowConstructor); this.registerStartedBy(startedByHandlers, registration); const messageHandlers = handles_1.WorkflowHandlesMetadata.getSteps(registration.workflowConstructor); this.registerHandles(messageHandlers, registration); const messageWorkflowMappings = messageHandlers.map(s => s.messageWorkflowMapping); await this.persistence.initializeWorkflow(registration.workflowDataConstructor, messageWorkflowMappings); this.logger.debug('Workflow initialized', { workflowName: registration.workflowConstructor.name }); } this.workflowRegistry = []; this.isInitialized = true; this.isInitializing = false; this.logger.info('Workflows initialized'); } async dispose() { if (this.persistence.dispose) { await this.persistence.dispose(); } } registerStartedBy(startedByHandlers, registration) { if (!startedByHandlers.length) { throw new Error(`Workflow ${registration.workflowConstructor.name} does not have a started by step`); } startedByHandlers.forEach(step => { const messageName = new step.messageConstructor().$name; const handlerFactory = (context) => { const workflow = context.container.resolve(registration.workflowConstructor); return this.startedByFactory(registration.workflowDataConstructor, workflow[step.propertyKey].bind(workflow)); }; this.handlerRegistry.register((m) => m.$name === messageName, Symbol.for(`node-ts/bus/workflow/${registration.workflowConstructor.name}-${messageName}-started-by-proxy`), handlerFactory, step.messageConstructor); }); } registerHandles(messageHandlers, registration) { messageHandlers.forEach(step => { const messageName = new step.messageConstructor().$name; const handler = (context) => { const workflow = context.container.resolve(registration.workflowConstructor); return this.handlesFactory(workflow[step.propertyKey].bind(workflow), registration.workflowDataConstructor, step.messageWorkflowMapping); }; this.handlerRegistry.register((m) => m.$name === messageName, Symbol.for(`node-ts/bus/workflow/${registration.workflowConstructor.name}-${messageName}-handles-proxy`), handler, step.messageConstructor); }); } }; WorkflowRegistry = tslib_1.__decorate([ inversify_1.injectable(), tslib_1.__param(0, inversify_1.inject(bus_core_1.BUS_SYMBOLS.HandlerRegistry)), tslib_1.__param(1, inversify_1.inject(bus_workflow_symbols_1.BUS_WORKFLOW_SYMBOLS.Persistence)), tslib_1.__param(2, inversify_1.inject(bus_workflow_symbols_1.BUS_WORKFLOW_INTERNAL_SYMBOLS.StartedByProxy)), tslib_1.__param(3, inversify_1.inject(bus_workflow_symbols_1.BUS_WORKFLOW_INTERNAL_SYMBOLS.HandlesProxy)), tslib_1.__param(4, inversify_1.inject(logger_core_1.LOGGER_SYMBOLS.Logger)), tslib_1.__metadata("design:paramtypes", [bus_core_1.HandlerRegistry, Object, Function, Function, Object]) ], WorkflowRegistry); exports.WorkflowRegistry = WorkflowRegistry; //# sourceMappingURL=workflow-registry.js.map