Last active
March 18, 2025 10:39
-
-
Save rajeshpillai/b3cc78ffabca9be31b5ce0a9bc01e7df to your computer and use it in GitHub Desktop.
Revisions
-
rajeshpillai revised this gist
Mar 18, 2025 . 2 changed files with 109 additions and 18 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,18 +0,0 @@ This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,109 @@ // cache/baseCache.js // This is our abstract base class defining the contract for our cache implementations. class BaseCache { async get(key) { throw new Error('Method "get" must be implemented'); } async set(key, value, ttl) { throw new Error('Method "set" must be implemented'); } async del(key) { throw new Error('Method "del" must be implemented'); } } module.exports = BaseCache; // cache/in_memory_cache.js require('dotenv').config(); const BaseCache = require('./baseCache'); const DEFAULT_TTL = process.env.CACHE_DEFAULT_TTL ? parseInt(process.env.CACHE_DEFAULT_TTL, 10) : 60; class InMemoryCache extends BaseCache { constructor(defaultTTL = DEFAULT_TTL) { super(); this.store = new Map(); this.defaultTTL = defaultTTL; } async get(key) { const record = this.store.get(key); if (!record) return null; // Check if expired if (record.expireAt && record.expireAt < Date.now()) { this.store.delete(key); return null; } return record.value; } async set(key, value, ttl) { ttl = ttl || this.defaultTTL; const expireAt = ttl ? Date.now() + ttl * 1000 : null; this.store.set(key, { value, expireAt }); } async del(key) { return this.store.delete(key); } } module.exports = InMemoryCache; // cache/redis_cache.js require('dotenv').config(); const Redis = require('ioredis'); const BaseCache = require('./baseCache'); const DEFAULT_TTL = process.env.CACHE_DEFAULT_TTL ? parseInt(process.env.CACHE_DEFAULT_TTL, 10) : 60; class RedisCache extends BaseCache { constructor(defaultTTL = DEFAULT_TTL) { super(); this.defaultTTL = defaultTTL; this.client = new Redis(process.env.REDIS_URL); this.client.on('error', (err) => { console.error('Redis error:', err); }); } async get(key) { return await this.client.get(key); } async set(key, value, ttl) { ttl = ttl || this.defaultTTL; if (ttl) { await this.client.set(key, value, 'EX', ttl); } else { await this.client.set(key, value); } } async del(key) { await this.client.del(key); } } module.exports = RedisCache; // cache/index.js require('dotenv').config(); const InMemoryCache = require('./inMemoryCache'); const RedisCache = require('./redisCache'); // Choose Redis in production; otherwise use in-memory cache. const cache = process.env.NODE_ENV === 'production' ? new RedisCache() : new InMemoryCache(); module.exports = cache; -
rajeshpillai revised this gist
Mar 18, 2025 . 2 changed files with 18 additions and 71 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,18 @@ // cache/baseCache.js // This is our abstract base class defining the contract for our cache implementations. class BaseCache { async get(key) { throw new Error('Method "get" must be implemented'); } async set(key, value, ttl) { throw new Error('Method "set" must be implemented'); } async del(key) { throw new Error('Method "del" must be implemented'); } } module.exports = BaseCache; This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,71 +0,0 @@ -
rajeshpillai created this gist
Mar 18, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,71 @@ require('dotenv').config(); // Ensure env variables are loaded const Redis = require('ioredis'); // Use an environment variable or default to 60 seconds const DEFAULT_TTL = process.env.CACHE_DEFAULT_TTL ? parseInt(process.env.CACHE_DEFAULT_TTL, 10) : 60; class InMemoryCache { constructor(defaultTTL = DEFAULT_TTL) { this.store = new Map(); this.defaultTTL = defaultTTL; } async get(key) { const record = this.store.get(key); if (!record) return null; // Check if the key has expired if (record.expireAt && record.expireAt < Date.now()) { this.store.delete(key); return null; } return record.value; } async set(key, value, ttlInSeconds) { // Use provided TTL or fallback to the default TTL ttlInSeconds = ttlInSeconds || this.defaultTTL; const expireAt = ttlInSeconds ? Date.now() + ttlInSeconds * 1000 : null; this.store.set(key, { value, expireAt }); } async del(key) { return this.store.delete(key); } } class RedisCache { constructor(defaultTTL = DEFAULT_TTL) { this.defaultTTL = defaultTTL; // Create a new ioredis client using the connection string from environment variables this.client = new Redis(process.env.REDIS_URL); this.client.on('error', (err) => { console.error('Redis error:', err); }); } async get(key) { return await this.client.get(key); } async set(key, value, ttlInSeconds) { // Use provided TTL or fallback to the default TTL ttlInSeconds = ttlInSeconds || this.defaultTTL; if (ttlInSeconds) { // Use the EX option to set an expiration (in seconds) await this.client.set(key, value, 'EX', ttlInSeconds); } else { await this.client.set(key, value); } } async del(key) { await this.client.del(key); } } // Export the appropriate cache based on the environment. // In production mode use Redis; in all other cases (dev, testing) use in-memory cache. const cache = process.env.NODE_ENV === 'production' ? new RedisCache() : new InMemoryCache(); module.exports = cache;