renovate
Version:
Automated dependency updates. Flexible so you don't need to be.
118 lines (117 loc) • 3.45 kB
JavaScript
import { regEx } from "../../../regex.js";
import { logger } from "../../../../logger/index.js";
import { parseUrl } from "../../../url.js";
import { compressToBase64, decompressFromBase64 } from "../../../compress.js";
import { PackageCacheBase } from "./base.js";
import { DateTime } from "luxon";
import { createClient, createCluster } from "@redis/client";
//#region lib/util/cache/package/impl/redis.ts
function normalizeRedisUrl(url) {
return url.replace(regEx(/^(rediss?)\+cluster:\/\//), "$1://");
}
var PackageCacheRedis = class PackageCacheRedis extends PackageCacheBase {
static async create(url, prefix) {
const rprefix = prefix ?? "";
logger.debug("Redis cache init");
const rewrittenUrl = normalizeRedisUrl(url);
const clusteredMode = rewrittenUrl !== url;
const config = {
url: rewrittenUrl,
socket: { reconnectStrategy: (retries) => Math.min(retries * 100, 3e3) },
pingInterval: 3e4
};
let client;
if (clusteredMode) {
const clusterConfig = { rootNodes: [config] };
const parsedUrl = parseUrl(rewrittenUrl);
if (parsedUrl?.username) clusterConfig.defaults = { username: parsedUrl.username };
if (parsedUrl?.password) {
clusterConfig.defaults ??= {};
clusterConfig.defaults.password = parsedUrl.password;
}
client = createCluster(clusterConfig);
} else client = createClient(config);
await client.connect();
logger.debug("Redis cache connected");
return new PackageCacheRedis(client, rprefix);
}
client;
rprefix;
constructor(client, rprefix) {
super();
this.client = client;
this.rprefix = rprefix;
}
getKey(namespace, key) {
return `${this.rprefix}${namespace}-${key}`;
}
async get(namespace, key) {
logger.trace(`cache.get(${namespace}, ${key})`);
try {
const raw = await this.client.get(this.getKey(namespace, key));
if (!raw) return;
const cached = JSON.parse(raw);
const expiry = DateTime.fromISO(cached.expiry);
if (!expiry.isValid || DateTime.local() >= expiry) {
await this.rm(namespace, key);
return;
}
logger.trace({
rprefix: this.rprefix,
namespace,
key
}, "Returning cached value");
const json = await decompressFromBase64(cached.value);
return JSON.parse(json);
} catch {
logger.trace({
rprefix: this.rprefix,
namespace,
key
}, "Cache miss");
}
}
async set(namespace, key, value, hardTtlMinutes) {
logger.trace({
rprefix: this.rprefix,
namespace,
key,
hardTtlMinutes
}, "Saving cached value");
const ttlSeconds = Math.floor(hardTtlMinutes * 60);
try {
if (ttlSeconds <= 0) {
await this.rm(namespace, key);
return;
}
const compressedValue = await compressToBase64(JSON.stringify(value));
const expiry = DateTime.local().plus({ minutes: hardTtlMinutes });
const payload = JSON.stringify({
value: compressedValue,
expiry
});
await this.client.set(this.getKey(namespace, key), payload, { EX: ttlSeconds });
} catch (err) {
logger.once.warn({ err }, "Error while setting Redis cache value");
}
}
destroy() {
try {
this.client.destroy();
} catch (err) {
logger.warn({ err }, "Redis cache destroy failed");
}
return Promise.resolve();
}
async rm(namespace, key) {
logger.trace({
rprefix: this.rprefix,
namespace,
key
}, "Removing cache entry");
await this.client.del(this.getKey(namespace, key));
}
};
//#endregion
export { PackageCacheRedis };
//# sourceMappingURL=redis.js.map