-
-
Notifications
You must be signed in to change notification settings - Fork 0
6.2 cache return value
Decorates methods and getter properties to cache their return values with optional TTL-based expiration and Joi schema validation.
import { CacheReturnValue } from '@triplef/config-factory/cache-return-value';By default, cached values expire after 5 minutes and use a stale-while-revalidate strategy.
import { Injectable } from '@nestjs/common';
import { CacheReturnValue } from '@triplef/config-factory/cache-return-value';
@Injectable()
export class AppConfigService {
@CacheReturnValue()
get config() {
console.log('Computing config...');
return { port: 3000, env: 'development' };
}
}
const service = new AppConfigService();
service.config; // Logs "Computing config..."
service.config; // Returns cached value (no log)Use false to disable TTL expiration entirely.
@CacheReturnValue(false)
get permanentConfig() {
return { version: '1.0.0' };
}Provide a custom TTL in milliseconds. Use a number for shorthand or a CacheConfig object for additional options.
// Number shorthand (60 seconds)
@CacheReturnValue(60000)
get userData() {
return fetchUserData();
}
// Config object (60 seconds)
@CacheReturnValue({ ttl: 60000 })
get otherData() {
return fetchOtherData();
}import Joi from 'joi';
const UserSchema = Joi.object({
id: Joi.number().required(),
name: Joi.string().required(),
});
@CacheReturnValue(UserSchema)
getUserById(id: number) {
return { id, name: 'John' };
}
getUserById(1); // Validates against UserSchema
getUserById(1); // Returns cached, validated value@CacheReturnValue({ schema: UserSchema, ttl: 300000 }) // 5 minutes with validation
getUserById(id: number) {
return { id, name: 'John' };
}@CacheReturnValue()
getUserById(id: number) {
console.log(`Fetching user ${id}...`);
return { id, name: 'John' };
}
getUserById(1); // Logs "Fetching user 1..."
getUserById(1); // Returns cached value
getUserById(2); // Logs "Fetching user 2..." (different args)When TTL expires, the cached value is returned immediately (non-blocking) while a background refresh is triggered. This ensures:
- No blocking: The caller always receives a value immediately
- Background refresh: The cache is updated asynchronously
- Shared promise: Multiple concurrent reads share the same refresh promise, preventing duplicate fetches
@CacheReturnValue({ ttl: 1000 })
get data() {
return fetchData(); // Called once when stale, not per concurrent read
}
// Request 1: Returns stale value, triggers refresh
// Request 2-10: Returns stale value, reuses in-flight refresh
// After refresh completes: All subsequent requests get fresh valueEach class instance has its own cache. Different instances do not share cached values.
Method caches are keyed by a hash of the method name and serialized arguments, enabling separate caches for different argument combinations.
When a Joi schema is provided, return values are validated before caching. Invalid values throw ValidateReturnValueError.
| Input | TTL Behavior |
|---|---|
@CacheReturnValue() |
5 minutes (default) |
@CacheReturnValue(schema) |
5 minutes with validation |
@CacheReturnValue(60000) |
60 seconds, no validation |
@CacheReturnValue(false) |
Permanent (no expiration) |
@CacheReturnValue({ ttl: false }) |
Permanent with optional validation |
@CacheReturnValue({ ttl: 60000 }) |
60 seconds, no validation |
@CacheReturnValue({ schema, ttl: 60000 }) |
60 seconds with validation |
import { Injectable } from '@nestjs/common';
import { CacheReturnValue } from '@triplef/config-factory/cache-return-value';
import Joi from 'joi';
const DatabaseConfigSchema = Joi.object({
host: Joi.string().required(),
port: Joi.number().port().required(),
database: Joi.string().required(),
});
@Injectable()
export class DatabaseConfigService {
// Default 5 minute TTL with validation
@CacheReturnValue(DatabaseConfigSchema)
get config() {
return {
host: process.env.DB_HOST || 'localhost',
port: parseInt(process.env.DB_PORT || '5432'),
database: process.env.DB_NAME || 'myapp',
};
}
// Custom 1 minute TTL with validation
@CacheReturnValue({ schema: Joi.object({ id: Joi.number().required() }), ttl: 60000 })
async fetchUser(id: number) {
return { id, name: 'User ' + id };
}
// Permanent cache (no TTL)
@CacheReturnValue({ schema: Joi.string(), ttl: false })
getVersion() {
return '1.0.0';
}
}- 6.3. Validate Return Value - Standalone validation decorator
- 6.1. Config-Factory Module - Module for registering config services