Files

91 lines
2.3 KiB
TypeScript

import Redis from "ioredis";
let sharedClient: Redis | undefined;
let sharedConnection: Promise<Redis> | undefined;
function redisUrl(): string {
const value = process.env.REDIS_URL;
if (!value) throw new Error("REDIS_URL is required for Redis-backed features.");
return value;
}
export function createRedisClient(connectionName: string): Redis {
const client = new Redis(redisUrl(), {
connectionName,
enableOfflineQueue: false,
lazyConnect: true,
maxRetriesPerRequest: 2,
});
client.on("error", () => undefined);
return client;
}
export async function connectRedisClient(client: Redis): Promise<Redis> {
if (client.status === "ready") return client;
if (client.status === "wait") {
await client.connect();
return client;
}
await new Promise<void>((resolve, reject) => {
const ready = () => {
cleanup();
resolve();
};
const error = (cause: Error) => {
cleanup();
reject(cause);
};
const cleanup = () => {
client.off("ready", ready);
client.off("error", error);
};
client.once("ready", ready);
client.once("error", error);
});
return client;
}
export async function getRedisClient(): Promise<Redis> {
if (!sharedClient) {
sharedClient = createRedisClient("buzz-sheet-shared");
}
if (!sharedConnection) {
sharedConnection = connectRedisClient(sharedClient).catch((cause) => {
sharedClient?.disconnect();
sharedClient = undefined;
sharedConnection = undefined;
throw cause;
});
}
return sharedConnection;
}
export async function closeRedisClient(): Promise<void> {
const client = sharedClient;
sharedClient = undefined;
sharedConnection = undefined;
if (!client) return;
if (client.status === "wait" || client.status === "end") {
client.disconnect();
return;
}
await client.quit().catch(() => client.disconnect());
}
export function redisCachePrefix(): string {
return process.env.REDIS_CACHE_PREFIX || "buzz:next-cache";
}
export function redisCacheTagStateKey(): string {
return `${redisCachePrefix()}:tag-timestamps`;
}
export function redisEventPrefix(): string {
return process.env.REDIS_EVENT_PREFIX || "buzz:events";
}
export function redisEventChannel(topic: string): string {
return `${redisEventPrefix()}:${topic}`;
}