41 lines
1.3 KiB
TypeScript
41 lines
1.3 KiB
TypeScript
|
|
import { Valkey } from "iovalkey";
|
||
|
|
|
||
|
|
const PREFIX = "mancala:cache:";
|
||
|
|
|
||
|
|
// Short-lived cache of JSON values. Never fails: errors count as a miss, so callers just compute the value.
|
||
|
|
export interface Cache {
|
||
|
|
getJson<T>(key: string): Promise<T | undefined>;
|
||
|
|
setJson(key: string, value: unknown, ttlSeconds: number): Promise<void>;
|
||
|
|
delete(...keys: string[]): Promise<void>;
|
||
|
|
}
|
||
|
|
|
||
|
|
export class ValkeyCache implements Cache {
|
||
|
|
constructor(private readonly client: Valkey) { }
|
||
|
|
|
||
|
|
async getJson<T>(key: string): Promise<T | undefined> {
|
||
|
|
try {
|
||
|
|
const value = await this.client.get(PREFIX + key);
|
||
|
|
return value === null ? undefined : JSON.parse(value) as T;
|
||
|
|
} catch (err) {
|
||
|
|
return undefined;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
async setJson(key: string, value: unknown, ttlSeconds: number): Promise<void> {
|
||
|
|
try {
|
||
|
|
await this.client.set(PREFIX + key, JSON.stringify(value), "EX", ttlSeconds);
|
||
|
|
} catch (err) {
|
||
|
|
// A missing cache entry only costs a database query.
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
async delete(...keys: string[]): Promise<void> {
|
||
|
|
if (keys.length === 0) return;
|
||
|
|
try {
|
||
|
|
await this.client.del(...keys.map((key) => PREFIX + key));
|
||
|
|
} catch (err) {
|
||
|
|
// Entries expire on their own.
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|