91 lines
2.3 KiB
TypeScript
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}`;
|
|
}
|