n8n
Version:
n8n Workflow Automation Tool
157 lines • 8.01 kB
JavaScript
;
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