64 lines
1.7 KiB
TypeScript
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 };
|
|
}
|