Files

64 lines
1.7 KiB
TypeScript

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<DeploymentStatus, number> = {
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<DeploymentStatusEvent | null> {
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 };
}