UNPKG

n8n

Version:

n8n Workflow Automation Tool

157 lines • 8.01 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AgentRuntimeCacheService = void 0; const backend_common_1 = require("@n8n/backend-common"); const config_1 = require("@n8n/config"); const constants_1 = require("@n8n/constants"); const decorators_1 = require("@n8n/decorators"); const di_1 = require("@n8n/di"); const credentials_service_1 = require("../../credentials/credentials.service"); const not_found_error_1 = require("../../errors/response-errors/not-found.error"); const publisher_service_1 = require("../../scaling/pubsub/publisher.service"); const ttl_map_1 = require("../../utils/ttl-map"); const agent_telemetry_1 = require("./agent-telemetry"); const agent_runtime_reconstruction_service_1 = require("./agent-runtime-reconstruction.service"); const agent_repository_1 = require("./repositories/agent.repository"); const agent_credential_provider_1 = require("./utils/agent-credential-provider"); const agent_published_snapshot_1 = require("./utils/agent-published-snapshot"); let AgentRuntimeCacheService = class AgentRuntimeCacheService { constructor(logger, agentRepository, publisher, globalConfig, agentRuntimeReconstructionService, credentialsService) { this.logger = logger; this.agentRepository = agentRepository; this.publisher = publisher; this.globalConfig = globalConfig; this.agentRuntimeReconstructionService = agentRuntimeReconstructionService; this.credentialsService = credentialsService; this.runtimes = new ttl_map_1.TtlMap(30 * constants_1.Time.minutes.toMilliseconds); this.runtimeInitializations = new Map(); } computeRuntimeCacheKey(params) { if (params.usePublishedVersion) { const parts = [params.agentId, 'published']; if (params.integrationType) parts.push(params.integrationType); return parts.join(':'); } const parts = [params.agentId, 'draft']; if (params.integrationType) parts.push(params.integrationType); if (params.user) parts.push(`user:${params.user.id}`); return parts.join(':'); } isRuntimeCacheKeyForAgent(key, agentId) { return key === agentId || key.startsWith(`${agentId}:`); } clearRuntimes(agentId, options = {}) { for (const key of this.runtimes.keys()) { if (this.isRuntimeCacheKeyForAgent(key, agentId)) { const entry = this.runtimes.get(key); this.runtimes.delete(key); if (entry) this.closeAgentResources(entry.agent, agentId); } } for (const key of this.runtimeInitializations.keys()) { if (this.isRuntimeCacheKeyForAgent(key, agentId)) { this.runtimeInitializations.delete(key); } } if (options.skipBroadcast) return; if (!this.globalConfig.multiMainSetup.enabled) return; void this.publisher .publishCommand({ command: 'agent-config-changed', payload: { agentId }, }) .catch((error) => { this.logger.warn(`[AgentRuntimeCacheService] Failed to publish agent-config-changed for ${agentId}`, { error: error instanceof Error ? error.message : String(error), }); }); } handleAgentConfigChanged(payload) { this.clearRuntimes(payload.agentId, { skipBroadcast: true }); } closeAgentResources(agent, agentId) { agent.close().catch((error) => { this.logger.warn('[AgentRuntimeCacheService] Failed to close agent resources on eviction', { agentId, error: error instanceof Error ? error.message : String(error), }); }); } async getRuntime(params) { const cacheKey = this.computeRuntimeCacheKey(params); const cached = this.runtimes.get(cacheKey); if (cached) return cached; const initialization = this.runtimeInitializations.get(cacheKey); if (initialization) return await initialization.promise; const token = Symbol(cacheKey); const runtimeInitialization = { token, promise: (async () => { const runtime = await this.reconstructRuntime(params); if (this.runtimeInitializations.get(cacheKey)?.token !== token) { this.closeAgentResources(runtime.agent, params.agentId); throw new Error(`Agent ${params.agentId} runtime initialization was invalidated`); } this.runtimes.set(cacheKey, runtime); const cachedRuntime = this.runtimes.get(cacheKey); if (!cachedRuntime) throw new Error(`Agent ${params.agentId} failed to reconstruct`); return cachedRuntime; })(), }; runtimeInitialization.promise = runtimeInitialization.promise.finally(() => { if (this.runtimeInitializations.get(cacheKey)?.token === token) { this.runtimeInitializations.delete(cacheKey); } }); this.runtimeInitializations.set(cacheKey, runtimeInitialization); return await runtimeInitialization.promise; } async reconstructRuntime(params) { const { agentId, projectId, integrationType, usePublishedVersion, user } = params; const agentEntity = await this.agentRepository.findByIdAndProjectId(agentId, projectId); if (!agentEntity) throw new not_found_error_1.NotFoundError(`Agent ${agentId} not found`); const agentData = usePublishedVersion ? (0, agent_published_snapshot_1.getPublishedAgentSnapshot)(agentEntity) : agentEntity; const credentialProvider = (0, agent_credential_provider_1.createAgentCredentialProvider)(this.credentialsService, projectId, user); const { agent: agentInstance, toolRegistry } = await this.agentRuntimeReconstructionService.reconstructFromAgentEntity(agentData, credentialProvider, integrationType, user); return { agent: agentInstance, agentId, toolRegistry, projectId, telemetryConfiguration: (0, agent_telemetry_1.buildAgentConfigurationTelemetry)(agentData), }; } }; exports.AgentRuntimeCacheService = AgentRuntimeCacheService; __decorate([ (0, decorators_1.OnPubSubEvent)('agent-config-changed', { instanceType: 'main' }), __metadata("design:type", Function), __metadata("design:paramtypes", [Object]), __metadata("design:returntype", void 0) ], AgentRuntimeCacheService.prototype, "handleAgentConfigChanged", null); exports.AgentRuntimeCacheService = AgentRuntimeCacheService = __decorate([ (0, di_1.Service)(), __metadata("design:paramtypes", [backend_common_1.Logger, agent_repository_1.AgentRepository, publisher_service_1.Publisher, config_1.GlobalConfig, agent_runtime_reconstruction_service_1.AgentRuntimeReconstructionService, credentials_service_1.CredentialsService]) ], AgentRuntimeCacheService); //# sourceMappingURL=agent-runtime-cache.service.js.map