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
text/typescript
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);
}
}