UNPKG

mastercache

Version:

Multi-tier cache module for Node.js. Redis, Upstash, CloudfareKV, File, in-memory and others drivers

107 lines (89 loc) 2.98 kB
import lodash from 'lodash'; import { Bus } from '../../bus/bus'; import { LocalCache } from '../facades/local-cache'; import { RemoteCache } from '../facades/remote-cache'; import { BaseDriver } from '../../drivers/base-driver'; import { JsonSerializer } from '../../serializers/json'; import type { MasterCacheOptions } from '../../mastercache-options'; import { CacheEntryOptions } from '../cache-entry/cache-entry-options'; import type { BusDriver, BusOptions, CacheEvent, CacheStackDrivers, CacheBusMessage, Logger, } from '../../types/main'; export class CacheStack extends BaseDriver { #serializer = new JsonSerializer(); l1?: LocalCache; l2?: RemoteCache; bus?: Bus; defaultOptions: CacheEntryOptions; logger: Logger; #busDriver?: BusDriver; #busOptions?: BusOptions; #namespaceCache: Map<string, CacheStack> = new Map(); constructor( public name: string, public options: MasterCacheOptions, drivers: CacheStackDrivers, bus?: Bus, ) { super(options); this.logger = options.logger.child({ cache: this.name }); if (drivers.l1Driver) this.l1 = new LocalCache(drivers.l1Driver, this.logger); if (drivers.l2Driver) this.l2 = new RemoteCache(drivers.l2Driver, this.logger); this.bus = bus ? bus : this.#createBus(drivers.busDriver, drivers.busOptions); if (this.l1) this.bus?.manageCache(this.prefix, this.l1); this.defaultOptions = new CacheEntryOptions(options); } get emitter() { return this.options.emitter; } #createBus(busDriver?: BusDriver, busOptions?: BusOptions) { if (!busDriver) return; this.#busDriver = busDriver; this.#busOptions = lodash.merge( { retryQueue: { enabled: true, maxSize: undefined } }, busOptions, ); const newBus = new Bus(this.name, this.#busDriver, this.logger, this.emitter, this.#busOptions); return newBus; } namespace(namespace: string): CacheStack { if (!this.#namespaceCache.has(namespace)) { this.#namespaceCache.set( namespace, new CacheStack( this.name, this.options.cloneWith({ prefix: this.createNamespacePrefix(namespace) }), { l1Driver: this.l1?.namespace(namespace), l2Driver: this.l2?.namespace(namespace), }, this.bus, ), ); } return <CacheStack>this.#namespaceCache.get(namespace); } /** * Publish a message to the bus channel * * @returns true if the message was published, false if not * and undefined if a bus is not part of the stack */ async publish(message: CacheBusMessage): Promise<boolean | undefined> { return this.bus?.publish({ ...message, namespace: this.prefix }); } emit(event: CacheEvent) { return this.emitter.emit(event.name, event.toJSON()); } serialize(value: any) { return this.#serializer.serialize(value); } deserialize(value: string) { return this.#serializer.deserialize(value); } }