UNPKG

n8n

Version:

n8n Workflow Automation Tool

177 lines • 7.89 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.N8NCheckpointStorage = void 0; const agents_1 = require("@n8n/agents"); 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 n8n_core_1 = require("n8n-core"); const n8n_workflow_1 = require("n8n-workflow"); const node_assert_1 = require("node:assert"); const agent_checkpoint_repository_1 = require("../repositories/agent-checkpoint.repository"); function stripStateFileData(state) { if (!state.messageList) return state; return { ...state, messageList: { ...state.messageList, messages: state.messageList.messages.map(agents_1.stripHydratedFileData), }, }; } let N8NCheckpointStorage = class N8NCheckpointStorage { constructor(instanceSettings, agentCheckpointRepository, logger, agentsConfig, moduleRegistry) { this.instanceSettings = instanceSettings; this.agentCheckpointRepository = agentCheckpointRepository; this.logger = logger; this.agentsConfig = agentsConfig; this.moduleRegistry = moduleRegistry; this.isStopping = false; this.isInitialized = false; this.logger = this.logger.scoped('agents'); this.isInitialized = this.moduleRegistry.isActive('agents'); } getStorage(agentId) { return { save: async (key, state) => await this.save(key, state, agentId), load: async (key) => await this.load(key, agentId), claimForResume: async (key, state) => await this.claimForResume(key, state, agentId), delete: async (key) => await this.delete(key, agentId), }; } init() { (0, node_assert_1.strict)(this.instanceSettings.instanceRole !== 'unset', 'Instance role is not set'); if (this.instanceSettings.isLeader) this.startPruning(); } async save(key, checkpointState, agentId) { const state = stripStateFileData(checkpointState); const existing = await this.agentCheckpointRepository.findByRunId(key); if (existing) { if (existing.agentId !== agentId) { throw new n8n_workflow_1.UnexpectedError('Agent checkpoint is owned by a different agent'); } existing.state = JSON.stringify(state); existing.expired = false; await this.agentCheckpointRepository.save(existing); } else { const checkpoint = this.agentCheckpointRepository.create({ runId: key, agentId, state: JSON.stringify(state), expired: false, }); await this.agentCheckpointRepository.save(checkpoint); } } async load(key, agentId) { const checkpoint = await this.agentCheckpointRepository.findByRunIdAndAgentId(key, agentId); if (!checkpoint) return undefined; if (checkpoint.expired || checkpoint.state === null) { throw new n8n_workflow_1.UserError('This action has expired and cannot be resumed'); } const state = (0, n8n_workflow_1.jsonParse)(checkpoint.state); if (state.status !== 'suspended') { throw new n8n_workflow_1.UserError('This action has already been handled'); } return state; } async claimForResume(key, checkpointState, agentId) { const state = stripStateFileData(checkpointState); return await this.agentCheckpointRepository.claimForResume(key, agentId, JSON.stringify(state), JSON.stringify({ ...state, status: 'running' })); } async cancelSuspended(key, state, agentId) { if (state.status !== 'suspended') return false; return await this.agentCheckpointRepository.cancelSuspended(key, agentId, JSON.stringify(state)); } async getStatus(key, agentId) { const checkpoint = await this.agentCheckpointRepository.findByRunIdAndAgentId(key, agentId); if (!checkpoint) return { status: 'not-found' }; if (checkpoint.state === null) return { status: 'expired' }; const state = (0, n8n_workflow_1.jsonParse)(checkpoint.state); if (checkpoint.expired) return { status: 'expired', checkpoint: state }; return { status: 'active', checkpoint: state }; } async delete(key, agentId) { await this.agentCheckpointRepository.expireByRunIdAndAgentId(key, agentId); } startPruning() { this.isStopping = false; this.scheduleNextPrune(0); } stopPruning() { clearTimeout(this.pruneTimeout); this.pruneTimeout = undefined; } shutdown() { this.isStopping = true; this.stopPruning(); } scheduleNextPrune(delayMs = constants_1.Time.hours.toMilliseconds) { if (this.isStopping || !this.isInitialized) return; this.pruneTimeout = setTimeout(async () => { await this.pruneStaleSuspensions(); }, delayMs); } async pruneStaleSuspensions() { const ttlMs = this.agentsConfig.checkpointTtlSeconds * constants_1.Time.seconds.toMilliseconds; const cutoffDate = new Date(Date.now() - ttlMs); try { const count = await this.agentCheckpointRepository.markExpired(cutoffDate); if (count > 0) { this.logger.info('Marked stale agent checkpoints as expired', { count }); } else { this.logger.debug('No stale agent checkpoints to expire'); } this.scheduleNextPrune(); } catch (error) { this.logger.warn('Failed to expire stale agent checkpoints', { error }); this.scheduleNextPrune(constants_1.Time.seconds.toMilliseconds * 30); } } }; exports.N8NCheckpointStorage = N8NCheckpointStorage; __decorate([ (0, decorators_1.OnLeaderTakeover)(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", void 0) ], N8NCheckpointStorage.prototype, "startPruning", null); __decorate([ (0, decorators_1.OnLeaderStepdown)(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", void 0) ], N8NCheckpointStorage.prototype, "stopPruning", null); __decorate([ (0, decorators_1.OnShutdown)(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", void 0) ], N8NCheckpointStorage.prototype, "shutdown", null); exports.N8NCheckpointStorage = N8NCheckpointStorage = __decorate([ (0, di_1.Service)(), __metadata("design:paramtypes", [n8n_core_1.InstanceSettings, agent_checkpoint_repository_1.AgentCheckpointRepository, backend_common_1.Logger, config_1.AgentsConfig, backend_common_1.ModuleRegistry]) ], N8NCheckpointStorage); //# sourceMappingURL=n8n-checkpoint-storage.js.map