UNPKG

n8n

Version:

n8n Workflow Automation Tool

184 lines 8.79 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); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.PrometheusSchedulerMetricsService = void 0; const config_1 = require("@n8n/config"); const constants_1 = require("@n8n/constants"); const db_1 = require("@n8n/db"); const di_1 = require("@n8n/di"); const n8n_core_1 = require("n8n-core"); const prom_client_1 = __importDefault(require("prom-client")); const cache_service_1 = require("../../services/cache/cache.service"); const cached_metric_query_1 = require("./cached-metric-query"); const constant_1 = require("./constant"); const SNAPSHOT_CACHE_KEY = 'metrics:scheduler:snapshot:v1'; let PrometheusSchedulerMetricsService = class PrometheusSchedulerMetricsService { constructor(config, instanceSettings, cacheService, taskRepository) { this.config = config; this.instanceSettings = instanceSettings; this.cacheService = cacheService; this.taskRepository = taskRepository; this.initialized = false; } get enabled() { return this.config.includeSchedulerMetrics && this.instanceSettings.instanceType === 'main'; } init() { this.initPushMetrics(); this.initSnapshotGauges(); this.initialized = true; } initPushMetrics() { const prefix = this.config.prefix; this.tasksDispatched = new prom_client_1.default.Counter({ name: `${prefix}scheduler_tasks_dispatched_total`, help: 'Total number of scheduler tasks dispatched to a handler by task type.', labelNames: ['task_type'], }); this.tasksCompleted = new prom_client_1.default.Counter({ name: `${prefix}scheduler_tasks_completed_total`, help: 'Total number of scheduler tasks that finished firing by task type and result.', labelNames: ['task_type', 'result'], }); this.taskRetries = new prom_client_1.default.Counter({ name: `${prefix}scheduler_task_retries_total`, help: 'Total number of scheduler task retries by task type.', labelNames: ['task_type'], }); this.occurrencesMaterialized = new prom_client_1.default.Counter({ name: `${prefix}scheduler_occurrences_materialized_total`, help: 'Total number of occurrences materialized from job schedules.', }); this.jobsDeferred = new prom_client_1.default.Counter({ name: `${prefix}scheduler_jobs_deferred_total`, help: 'Total number of jobs deferred for retry during materialization.', }); this.tasksReclaimed = new prom_client_1.default.Counter({ name: `${prefix}scheduler_tasks_reclaimed_total`, help: 'Total number of expired scheduler tasks reclaimed by the reaper.', }); this.tasksDeadLettered = new prom_client_1.default.Counter({ name: `${prefix}scheduler_tasks_dead_lettered_total`, help: 'Total number of scheduler tasks dead-lettered after exhausting their attempts, from either path: a terminal handler failure or the reaper recovering an expired lease.', }); this.tasksPruned = new prom_client_1.default.Counter({ name: `${prefix}scheduler_tasks_pruned_total`, help: 'Total number of finished scheduler tasks deleted by retention.', }); this.dispatchLagSeconds = new prom_client_1.default.Histogram({ name: `${prefix}scheduler_dispatch_lag_seconds`, help: 'Delay in seconds between a task becoming due and being dispatched, by task type.', labelNames: ['task_type'], buckets: constant_1.DURATION_BUCKETS_SECONDS, }); this.occurrencesMaterialized.inc(0); this.jobsDeferred.inc(0); this.tasksReclaimed.inc(0); this.tasksDeadLettered.inc(0); this.tasksPruned.inc(0); } initSnapshotGauges() { const repository = this.taskRepository; const prefix = this.config.prefix; const ttlMs = this.config.schedulerMetricsInterval * constants_1.Time.seconds.toMilliseconds; const query = new cached_metric_query_1.CachedMetricQuery({ cacheService: this.cacheService, cacheKey: SNAPSHOT_CACHE_KEY, ttlMs, query: async () => await repository.getMetricSnapshot(), }); new prom_client_1.default.Gauge({ name: `${prefix}scheduler_tasks_pending`, help: 'Number of pending scheduler tasks awaiting dispatch. Cluster-wide snapshot, identical on every main; aggregate with max/avg, not sum.', async collect() { const snapshot = await query.get(); this.set(snapshot.pending); }, }); new prom_client_1.default.Gauge({ name: `${prefix}scheduler_tasks_due`, help: 'Number of pending scheduler tasks already due for dispatch. Cluster-wide snapshot, identical on every main; aggregate with max/avg, not sum.', async collect() { const snapshot = await query.get(); this.set(snapshot.due); }, }); new prom_client_1.default.Gauge({ name: `${prefix}scheduler_tasks_running`, help: 'Number of scheduler tasks currently claimed and in flight. Cluster-wide snapshot, identical on every main; aggregate with max/avg, not sum.', async collect() { const snapshot = await query.get(); this.set(snapshot.running); }, }); new prom_client_1.default.Gauge({ name: `${prefix}scheduler_oldest_pending_age_seconds`, help: 'Age in seconds of the oldest due pending scheduler task; 0 means no due backlog (not a task 0s late). Cluster-wide snapshot, identical on every main; aggregate with max/avg, not sum.', async collect() { const snapshot = await query.get(); this.set(snapshot.oldestPendingAgeMs !== null ? snapshot.oldestPendingAgeMs * constants_1.Time.milliseconds.toSeconds : 0); }, }); } recordDispatch(taskType) { if (this.initialized) { this.tasksDispatched.inc({ task_type: taskType }, 1); } } recordFireOutcome(taskType, result) { if (this.initialized) { this.tasksCompleted.inc({ task_type: taskType, result }, 1); } } recordRetry(taskType) { if (this.initialized) { this.taskRetries.inc({ task_type: taskType }, 1); } } observeDispatchLagSeconds(taskType, seconds) { if (this.initialized) { this.dispatchLagSeconds.observe({ task_type: taskType }, seconds); } } recordMaterialized(occurrences, deferredJobs) { if (this.initialized) { this.occurrencesMaterialized.inc(occurrences); this.jobsDeferred.inc(deferredJobs); } } recordReaped(reclaimed, deadLettered) { if (this.initialized) { this.tasksReclaimed.inc(reclaimed); this.tasksDeadLettered.inc(deadLettered); } } recordDeadLettered() { if (this.initialized) { this.tasksDeadLettered.inc(1); } } recordPruned(deleted) { if (this.initialized) { this.tasksPruned.inc(deleted); } } }; exports.PrometheusSchedulerMetricsService = PrometheusSchedulerMetricsService; exports.PrometheusSchedulerMetricsService = PrometheusSchedulerMetricsService = __decorate([ (0, di_1.Service)(), __metadata("design:paramtypes", [config_1.PrometheusMetricsConfig, n8n_core_1.InstanceSettings, cache_service_1.CacheService, db_1.ScheduledTaskRepository]) ], PrometheusSchedulerMetricsService); //# sourceMappingURL=scheduler-metrics.service.js.map