import "server-only"; import type { DeploymentStatus, DeploymentStatusEvent, } from "./status"; import { parseDeploymentStatusEvent } from "./status"; import { getRedisClient, redisEventChannel, redisEventPrefix, } from "@/lib/redis/client"; export const DEPLOYMENT_EVENT_TOPIC = "deployments"; const statusKey = () => `${redisEventPrefix()}:deployments:latest`; const STATUS_TTL_SECONDS: Record = { deploying: 60 * 60, ready: 10 * 60, failed: 10 * 60, }; const publishScript = ` if ARGV[2] ~= "deploying" then local current = redis.call("GET", KEYS[1]) if not current then return 0 end local ok, decoded = pcall(cjson.decode, current) if not ok or decoded.deploymentId ~= ARGV[3] then return 0 end end redis.call("SET", KEYS[1], ARGV[1], "EX", ARGV[4]) redis.call("PUBLISH", KEYS[2], ARGV[1]) return 1 `; export async function getLatestDeploymentStatus(): Promise { const redis = await getRedisClient(); const value = await redis.get(statusKey()); return value ? parseDeploymentStatusEvent(value) : null; } export async function publishDeploymentStatus( deploymentId: string, status: DeploymentStatus, ): Promise<{ accepted: boolean; event: DeploymentStatusEvent }> { const event: DeploymentStatusEvent = { deploymentId, status, updatedAt: new Date().toISOString(), }; const payload = JSON.stringify(event); const redis = await getRedisClient(); const accepted = await redis.eval( publishScript, 2, statusKey(), redisEventChannel(DEPLOYMENT_EVENT_TOPIC), payload, status, deploymentId, STATUS_TTL_SECONDS[status], ); return { accepted: accepted === 1, event }; }