@titansys/persistent-cache
Version:
A robust, enterprise-grade persistent cache with file locking, corruption detection, health monitoring, and graceful degradation.
422 lines (331 loc) โข 10.9 kB
Markdown
# persistent-cache
A robust, enterprise-grade Node.js module for persistent caching with advanced features including file locking, corruption detection, health monitoring, and graceful degradation.
## ๐ Features
- **๐ Concurrent-Safe**: File locking prevents race conditions and data corruption
- **๐ก๏ธ Corruption Detection**: JSON validation with automatic error recovery
- **๐ Health Monitoring**: Real-time cache health tracking and reporting
- **๐ Graceful Degradation**: Continues operation even with partial corruption
- **โก High Performance**: Memory + disk hybrid caching for optimal speed
- **๐ง Zero Breaking Changes**: Fully backward compatible with v1.x
- **๐ Security Hardened**: All known vulnerabilities patched
## ๐ฆ Installation
```bash
npm install @titansys/persistent-cache
```
## ๐ฏ Quick Start
```js
const cache = require('@titansys/persistent-cache');
// Create a cache instance
const myCache = cache();
// Store data
myCache.put('user:123', { name: 'John', email: 'john@example.com' }, (err) => {
if (err) throw err;
console.log('User saved to cache');
});
// Retrieve data
myCache.get('user:123', (err, user) => {
if (err) throw err;
console.log('Retrieved user:', user);
});
```
## ๐ Core API
### Basic Operations
#### `cache.put(key, data, callback)`
Asynchronously stores data in the cache.
```js
cache.put('myKey', { foo: 'bar' }, (err) => {
if (err) console.error('Cache error:', err);
else console.log('Data cached successfully');
});
```
#### `cache.putSync(key, data)`
Synchronously stores data in the cache.
```js
try {
cache.putSync('myKey', { foo: 'bar' });
console.log('Data cached successfully');
} catch (err) {
console.error('Cache error:', err);
}
```
#### `cache.get(key, callback)`
Asynchronously retrieves data from the cache.
```js
cache.get('myKey', (err, data) => {
if (err) console.error('Cache error:', err);
else if (data === undefined) console.log('Key not found');
else console.log('Retrieved:', data);
});
```
#### `cache.getSync(key)`
Synchronously retrieves data from the cache.
```js
try {
const data = cache.getSync('myKey');
if (data === undefined) {
console.log('Key not found');
} else {
console.log('Retrieved:', data);
}
} catch (err) {
console.error('Cache error:', err);
}
```
#### `cache.delete(key, callback)` / `cache.deleteSync(key)`
Removes an entry from the cache.
```js
// Async
cache.delete('myKey', (err) => {
if (err) console.error('Delete error:', err);
else console.log('Key deleted');
});
// Sync
try {
cache.deleteSync('myKey');
console.log('Key deleted');
} catch (err) {
console.error('Delete error:', err);
}
```
#### `cache.keys(callback)` / `cache.keysSync()`
Lists all keys in the cache.
```js
// Async
cache.keys((err, keys) => {
if (err) console.error('Keys error:', err);
else console.log('Cache keys:', keys);
});
// Sync
try {
const keys = cache.keysSync();
console.log('Cache keys:', keys);
} catch (err) {
console.error('Keys error:', err);
}
```
#### `cache.unlink(callback)`
Completely removes the cache directory and all its contents.
```js
cache.unlink((err) => {
if (err) console.error('Unlink error:', err);
else console.log('Cache completely removed');
});
```
## ๐ฅ Health Monitoring API
### `cache.healthCheck(callback)`
Performs a comprehensive health check of all cache files.
```js
cache.healthCheck((err, report) => {
if (err) {
console.error('Health check failed:', err);
return;
}
console.log('Health Report:');
console.log(`โ
Healthy files: ${report.healthy}`);
console.log(`โ Corrupted files: ${report.corrupted}`);
console.log(`๐ง Repaired files: ${report.repaired}`);
// Detailed file status
report.files.forEach(file => {
console.log(`${file.name}: ${file.status}`);
if (file.error) console.log(` Error: ${file.error}`);
});
});
```
### `cache.healthCheckSync()`
Synchronous version of health check.
```js
try {
const report = cache.healthCheckSync();
console.log('Health report:', report);
} catch (err) {
console.error('Health check failed:', err);
}
```
### `cache.startHealthMonitoring(callback)`
Starts periodic health monitoring.
```js
cache.startHealthMonitoring((err, report) => {
if (err) {
console.error('Health monitoring error:', err);
return;
}
if (report.corrupted > 0) {
console.warn(`โ ๏ธ Found ${report.corrupted} corrupted files`);
// Take action: alert, repair, etc.
}
});
console.log('Health monitoring started');
```
### `cache.stopHealthMonitoring()`
Stops periodic health monitoring.
```js
cache.stopHealthMonitoring();
console.log('Health monitoring stopped');
```
### `cache.isHealthMonitoring()`
Check if health monitoring is currently active.
```js
if (cache.isHealthMonitoring()) {
console.log('Health monitoring is active');
} else {
console.log('Health monitoring is inactive');
}
```
## โ๏ธ Configuration Options
```js
const cache = require('@titansys/persistent-cache');
const myCache = cache({
base: './my-cache', // Base directory
name: 'user-cache', // Cache name
duration: 24 * 60 * 60 * 1000, // 24 hours in ms
memory: true, // Enable memory caching
persist: true, // Enable disk persistence
// ๐ Robustness Options
lockTimeout: 10000, // Lock timeout in ms (default: 5000)
healthCheckInterval: 300000, // Health check interval in ms (default: 5 min)
autoRepair: true // Auto-remove corrupted files (default: false)
});
```
### Core Options
#### `options.base`
- **Type**: `string`
- **Default**: Main module directory
- **Description**: Base directory where cache files are stored
#### `options.name`
- **Type**: `string`
- **Default**: `'cache'`
- **Description**: Cache name (creates subdirectory `base/name`)
#### `options.duration`
- **Type**: `number`
- **Default**: `undefined` (infinite)
- **Description**: Cache entry TTL in milliseconds
#### `options.memory`
- **Type**: `boolean`
- **Default**: `true`
- **Description**: Enable in-memory caching for performance
#### `options.persist`
- **Type**: `boolean`
- **Default**: `true`
- **Description**: Enable disk persistence
### ๐ Robustness Options
#### `options.lockTimeout`
- **Type**: `number`
- **Default**: `5000`
- **Description**: File lock timeout in milliseconds. Prevents indefinite blocking on concurrent access.
#### `options.healthCheckInterval`
- **Type**: `number`
- **Default**: `300000` (5 minutes)
- **Description**: Interval for periodic health checks when monitoring is enabled.
#### `options.autoRepair`
- **Type**: `boolean`
- **Default**: `false`
- **Description**: Automatically remove corrupted cache files during health checks.
## ๐ Concurrency & Locking
The cache uses file-based locking to prevent race conditions:
```js
// Multiple processes can safely write to the same cache
const cache1 = require('persistent-cache')({ name: 'shared' });
const cache2 = require('persistent-cache')({ name: 'shared' });
// These operations are safe to run concurrently
cache1.put('key1', 'value1', callback1);
cache2.put('key2', 'value2', callback2);
```
**Lock Features:**
- โฑ๏ธ Configurable timeout (default: 5 seconds)
- ๐งน Automatic cleanup on process exit
- ๐ Stale lock detection and recovery
- ๐ซ Deadlock prevention
## ๐ก๏ธ Error Handling & Graceful Degradation
The cache handles errors gracefully without breaking your application:
```js
const cache = require('persistent-cache')();
// Even if cache files are corrupted, operations continue
cache.get('potentially-corrupted-key', (err, data) => {
// err will be null, data will be undefined for corrupted entries
// Warning logged to console for debugging
if (data === undefined) {
console.log('Key not found or corrupted - using fallback');
// Your fallback logic here
}
});
```
**Graceful Degradation Features:**
- ๐ Corrupted files return `undefined` instead of throwing errors
- โ ๏ธ Warning logs for debugging (can be disabled)
- ๐ Memory fallback when disk operations fail
- ๐ฏ Isolated corruption (bad entries don't affect good ones)
## ๐ Security
- โ
**Zero Vulnerabilities**: All dependencies updated to secure versions
- ๐ **File Locking**: Prevents concurrent write corruption
- ๐ก๏ธ **Input Validation**: JSON structure validation before parsing
- ๐งน **Safe Cleanup**: Proper lock cleanup on process termination
## ๐ Performance
- **Memory + Disk Hybrid**: Best of both worlds
- **Efficient Locking**: Minimal performance overhead
- **Lazy Validation**: Only validates on read operations
- **Background Monitoring**: Health checks don't block operations
### Benchmarks
```
Memory Cache: ~0.1ms per operation
Disk Cache: ~1-5ms per operation (depending on file size)
Lock Acquisition: ~0.5ms average
Health Check: ~10ms per 100 files
```
## ๐ Migration from v1.x
No code changes required! All v1.x APIs work exactly the same:
```js
// v1.x code works unchanged
const cache = require('persistent-cache')();
cache.put('key', 'value', callback);
cache.get('key', callback);
```
**New features are opt-in:**
- Health monitoring is disabled by default
- Auto-repair is disabled by default
- All new APIs are additive
## ๐ Troubleshooting
### Health Check Issues
```js
cache.healthCheck((err, report) => {
if (report.corrupted > 0) {
console.log('Corrupted files found:', report.files.filter(f => f.status === 'corrupted'));
// Option 1: Enable auto-repair
const repairedCache = require('persistent-cache')({
name: 'same-cache',
autoRepair: true
});
// Option 2: Manual cleanup
report.files
.filter(f => f.status === 'corrupted')
.forEach(f => cache.delete(f.name, () => {}));
}
});
```
### Lock Timeout Issues
```js
// Increase timeout for slow systems
const cache = require('persistent-cache')({
lockTimeout: 15000 // 15 seconds
});
```
### Performance Tuning
```js
// Memory-only for maximum speed
const fastCache = require('persistent-cache')({
persist: false,
memory: true
});
// Disk-only for memory constrained environments
const diskCache = require('persistent-cache')({
persist: true,
memory: false
});
```
## ๐ License
MIT
## ๐ฅ Author
**Titan Systems** - [https://github.com/titansys](https://github.com/titansys)
## ๐ Links
- [GitHub Repository](https://github.com/titansys/persistent-cache)
- [Issue Tracker](https://github.com/titansys/persistent-cache/issues)
- [npm Package](https://www.npmjs.com/package/@titansys/persistent-cache)