import { Logger } from "@trigger.dev/core/logger"; import { Worker as RedisWorker } from "@trigger.dev/redis-worker"; import { z } from "zod"; import { env } from "~/env.server"; import { logger } from "~/services/logger.server"; import { singleton } from "~/utils/singleton"; import { DeliverAlertService } from "./services/alerts/deliverAlert.server"; import { DeliverErrorGroupAlertService } from "./services/alerts/deliverErrorGroupAlert.server"; import { ErrorAlertEvaluator } from "./services/alerts/errorAlertEvaluator.server"; import { PerformDeploymentAlertsService } from "./services/alerts/performDeploymentAlerts.server"; import { PerformTaskRunAlertsService } from "./services/alerts/performTaskRunAlerts.server"; function initializeWorker() { const redisOptions = { keyPrefix: "alerts:worker:", host: env.ALERTS_WORKER_REDIS_HOST, port: env.ALERTS_WORKER_REDIS_PORT, username: env.ALERTS_WORKER_REDIS_USERNAME, password: env.ALERTS_WORKER_REDIS_PASSWORD, enableAutoPipelining: true, ...(env.ALERTS_WORKER_REDIS_TLS_DISABLED === "true" ? {} : { tls: {} }), }; logger.debug(`👨‍🏭 Initializing alerts worker at host ${env.ALERTS_WORKER_REDIS_HOST}`); const worker = new RedisWorker({ name: "alerts-worker", redisOptions, catalog: { "v3.performTaskRunAlerts": { schema: z.object({ runId: z.string(), }), visibilityTimeoutMs: 60_000, retry: { maxAttempts: 3, }, logErrors: false, }, "v3.performDeploymentAlerts": { schema: z.object({ deploymentId: z.string(), }), visibilityTimeoutMs: 60_000, retry: { maxAttempts: 3, }, logErrors: false, }, "v3.deliverAlert": { schema: z.object({ alertId: z.string(), }), visibilityTimeoutMs: 60_000, retry: { maxAttempts: 3, }, logErrors: false, }, "v3.evaluateErrorAlerts": { schema: z.object({ projectId: z.string(), scheduledAt: z.number(), }), visibilityTimeoutMs: 60_000 * 5, retry: { maxAttempts: 3, }, logErrors: true, }, "v3.deliverErrorGroupAlert": { schema: z.object({ channelId: z.string(), projectId: z.string(), classification: z.enum(["new_issue", "regression", "unignored"]), error: z.object({ fingerprint: z.string(), environmentId: z.string(), environmentSlug: z.string(), environmentName: z.string(), taskIdentifier: z.string(), errorType: z.string(), errorMessage: z.string(), sampleStackTrace: z.string(), firstSeen: z.string(), lastSeen: z.string(), occurrenceCount: z.number(), }), }), visibilityTimeoutMs: 60_000, retry: { maxAttempts: 3, }, logErrors: true, }, }, concurrency: { workers: env.ALERTS_WORKER_CONCURRENCY_WORKERS, tasksPerWorker: env.ALERTS_WORKER_CONCURRENCY_TASKS_PER_WORKER, limit: env.ALERTS_WORKER_CONCURRENCY_LIMIT, }, pollIntervalMs: env.ALERTS_WORKER_POLL_INTERVAL, immediatePollIntervalMs: env.ALERTS_WORKER_IMMEDIATE_POLL_INTERVAL, shutdownTimeoutMs: env.ALERTS_WORKER_SHUTDOWN_TIMEOUT_MS, logger: new Logger("AlertsWorker", env.ALERTS_WORKER_LOG_LEVEL), jobs: { "v3.deliverAlert": async ({ payload }) => { const service = new DeliverAlertService(); await service.call(payload.alertId); }, "v3.performDeploymentAlerts": async ({ payload }) => { const service = new PerformDeploymentAlertsService(); await service.call(payload.deploymentId); }, "v3.performTaskRunAlerts": async ({ payload }) => { const service = new PerformTaskRunAlertsService(); await service.call(payload.runId); }, "v3.evaluateErrorAlerts": async ({ payload }) => { const evaluator = new ErrorAlertEvaluator(); await evaluator.evaluate(payload.projectId, payload.scheduledAt); }, "v3.deliverErrorGroupAlert": async ({ payload }) => { const service = new DeliverErrorGroupAlertService(); await service.call(payload); }, }, }); if (env.ALERTS_WORKER_ENABLED === "true") { logger.debug( `👨‍🏭 Starting alerts worker at host ${env.ALERTS_WORKER_REDIS_HOST}, pollInterval = ${env.ALERTS_WORKER_POLL_INTERVAL}, immediatePollInterval = ${env.ALERTS_WORKER_IMMEDIATE_POLL_INTERVAL}, workers = ${env.ALERTS_WORKER_CONCURRENCY_WORKERS}, tasksPerWorker = ${env.ALERTS_WORKER_CONCURRENCY_TASKS_PER_WORKER}, concurrencyLimit = ${env.ALERTS_WORKER_CONCURRENCY_LIMIT}` ); worker.start(); } return worker; } export const alertsWorker = singleton("alertsWorker", initializeWorker);