1.0.41 • Published 4 months ago

johny-cache v1.0.41

Weekly downloads
-
License
MIT
Repository
github
Last release
4 months ago

johny-cache

Caching can be hard. Let’s keep it simple!

johny-cache is a lightweight, framework‐agnostic TypeScript library for caching and distributed locking. It combines local in‐memory caching and Redis‐based remote caching in one easy‐to‐use service. Simply provide a Redis connection string and let johny-cache handle the rest—no need to manually juggle Redis clients, memory caches, or distributed locks.

FYI - Some of the code is inspired from https://github.com/multiversx/mx-sdk-nestjs.


Motivation

Caching can be deceptively complex. You might use both a Redis cache and an in-memory (local) cache, but as soon as you scale out horizontally - running multiple app instances - your data can become inconsistent across each instance’s local cache and the shared Redis cache. Keeping them all synchronized can feel like a never-ending headache.

johny-cache aims to solve that headache. By providing a simple, unified API, it handles local caching, remote caching, and cross-instance synchronization for you. All you need to do is define your desired cache settings, and the library takes care of the rest.

Features

  • Simple Initialization: Just pass in your Redis URL.
  • Local + Remote Caching: Seamlessly store data in both an in‐memory cache (fast lookups) and Redis (shared/distributed cache).
  • TTL & Auto‐Refresh: Specify TTL (time‐to‐live) for each cache entry and optionally auto‐refresh remote TTL.
  • Distributed Locking: Built‐in support for Redlock to handle concurrency.
  • Pub/Sub Invalidation: Refresh or invalidate cache across multiple instances using Redis Pub/Sub.
  • NestJS Friendly: Works great in NestJS or any Node.js environment.

Installation

npm install johny-cache

Quick Start

Instalation

npm install johny-cache

Import and Initialize

import { JohnyCacheService } from 'johny-cache';

const redisUrl = 'redis://localhost:6379';
const cacheService = new JohnyCacheService(redisUrl);

Define Your Cache Settings

import { JohnyCacheService, CacheSetting, Constants } from 'johny-cache';

const cacheSettings: CacheSetting = {
  key: 'user:123', // unique key
  localTtl: 10,    // seconds (in local cache/memory)
  remoteTtl: 300,  // seconds (remote/Redis)
};

Set and Get Data

// Set a value in cache
await cacheService.set(cacheSettings, { name: 'Alice', age: 30 });

// Retrieve the value from cache
const user = await cacheService.get(cacheSettings);
console.log(user); // { name: 'Alice', age: 30 }

Lazy Loading with getOrSetCache

const userData = await cacheService.getOrSetCache(cacheSettings, async () => {
  // Fallback: fetch from a database if not in cache
  return { id: 123, name: 'DB Alice' };
});

console.log(userData); // Value from cache or from the fallback function

Deleting Cache Entries

// Delete a specific cache key
await cacheService.delete(cacheSettings);

Distributed Locking

import { LockCacheSettings } from 'johny-cache';

const lockSettings: LockCacheSettings = {
  key: 'delete-inactive-users-cronjob-locker',
  remoteTtl: 5 * Constants.OneSecond()
  // optional locker settings
  lockOptions: {
    retryCount: 3,
    retryDelay: 50,
    retryJitter: 10,
  },
};

const lock = await cacheService.acquireLock(lockSettings);
if (lock) {
  try {
    // Execute critical section code here
  } finally {
    await cacheService.releaseLock(lock);
  }
}

Nestjs Module Sample

@Global()
@Module({
  imports: [CommonModule],
  providers: [
    {
      provide: JohnyCacheService,
      useFactory: (apiConfigService: ApiConfigService) =>
        new JohnyCacheService(apiConfigService.getRedisUrl()),
      inject: [ApiConfigService],
    },
    CacheInfoValidationService,
  ],
  exports: [JohnyCacheService],
})
export class CacheModule {}