123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- import config from "config";
- import {
- RedisClientOptions,
- RedisClientType,
- RedisDefaultModules,
- RedisFunctions,
- RedisModules,
- RedisScripts,
- createClient
- } from "redis";
- import { forEachIn } from "@common/utils/forEachIn";
- import BaseModule, { ModuleStatus } from "@/BaseModule";
- export class CacheModule extends BaseModule {
- private _redisClient?: RedisClientType<
- RedisDefaultModules & RedisModules,
- RedisFunctions,
- RedisScripts
- >;
- /**
- * Cache Module
- */
- public constructor() {
- super("cache");
- }
- /**
- * startup - Startup cache module
- */
- public override async startup() {
- await super.startup();
- this._redisClient = createClient({
- ...config.get<RedisClientOptions>("redis"),
- socket: {
- reconnectStrategy: (retries: number, error) => {
- if (
- retries >= 10 ||
- ![ModuleStatus.STARTING, ModuleStatus.STARTED].includes(
- this.getStatus()
- )
- )
- return false;
- this.log({
- type: "debug",
- message: `Redis reconnect attempt ${retries}`,
- data: error
- });
- return Math.min(retries * 50, 500);
- }
- }
- });
- this._redisClient.on("error", error => {
- this.log({ type: "error", message: error.message, data: error });
- this.setStatus(ModuleStatus.ERROR);
- });
- this._redisClient.on("ready", () => {
- this.log({ type: "debug", message: "Redis connection ready" });
- if (this.getStatus() === ModuleStatus.ERROR)
- this.setStatus(ModuleStatus.STARTED);
- });
- await this._redisClient.connect();
- const redisConfigResponse = await this._redisClient.sendCommand([
- "CONFIG",
- "GET",
- "notify-keyspace-events"
- ]);
- if (
- !(
- Array.isArray(redisConfigResponse) &&
- redisConfigResponse[1] === "xE"
- )
- )
- throw new Error(
- `notify-keyspace-events is NOT configured correctly! It is set to: ${
- (Array.isArray(redisConfigResponse) &&
- redisConfigResponse[1]) ||
- "unknown"
- }`
- );
- await super._started();
- }
- /**
- * shutdown - Shutdown cache module
- */
- public override async shutdown() {
- await super.shutdown();
- if (this._redisClient) await this._redisClient.quit();
- await this._stopped();
- }
- public canRunJobs(): boolean {
- return this._redisClient?.isReady === true && super.canRunJobs();
- }
- public async getKeys(pattern: string) {
- return this._redisClient!.KEYS(pattern);
- }
- public async get(key: string) {
- const value = await this._redisClient!.GET(key);
- return value === null ? null : JSON.parse(value);
- }
- public async set(key: string, value: any, ttl?: number) {
- await this._redisClient!.SET(key, JSON.stringify(value), { EX: ttl });
- }
- public async remove(key: string) {
- await this._redisClient!.DEL(key);
- }
- public async removeMany(keys: string | string[]) {
- await forEachIn(Array.isArray(keys) ? keys : [keys], async pattern => {
- for await (const key of this._redisClient!.scanIterator({
- MATCH: pattern
- })) {
- await this.remove(key);
- }
- });
- }
- public async getTtl(key: string) {
- return this._redisClient!.TTL(key);
- }
- public async getTable(key: string) {
- return this._redisClient!.HGETALL(key);
- }
- public async getTableItem(table: string, key: string) {
- return this._redisClient!.HGET(table, key);
- }
- public async setTableItem(table: string, key: string, value: any) {
- return this._redisClient!.HSET(table, key, value);
- }
- public async removeTableItem(table: string, key: string) {
- return this._redisClient!.HDEL(table, key);
- }
- }
- export default new CacheModule();
|