Generic resource pooling for Node.js applications with Promise-based API for efficient management of expensive resources.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Properties and methods for monitoring pool state, capacity, and resource utilization, providing comprehensive visibility into pool performance and health metrics.
Monitor the pool's capacity and resource allocation limits.
/**
* Pool capacity properties (read-only)
*/
class Pool extends EventEmitter {
/** How many more resources can be created before hitting max limit */
readonly spareResourceCapacity: number;
/** Maximum number of resources allowed in the pool */
readonly max: number;
/** Minimum number of resources to maintain in the pool */
readonly min: number;
}Usage Examples:
// Monitor pool capacity
function logPoolCapacity() {
console.log(`Pool Capacity:`);
console.log(` Max resources: ${pool.max}`);
console.log(` Min resources: ${pool.min}`);
console.log(` Spare capacity: ${pool.spareResourceCapacity}`);
if (pool.spareResourceCapacity === 0) {
console.warn('Pool at maximum capacity!');
}
}
// Auto-scaling decision making
function shouldScale() {
const utilizationRate = (pool.max - pool.spareResourceCapacity) / pool.max;
return utilizationRate > 0.8; // Scale when 80% utilized
}
// Capacity alerts
setInterval(() => {
if (pool.spareResourceCapacity <= 2) {
console.warn(`Low pool capacity: only ${pool.spareResourceCapacity} resources can be created`);
}
}, 30000); // Check every 30 secondsMonitor the current state and distribution of resources in the pool.
/**
* Resource count properties (read-only)
*/
class Pool extends EventEmitter {
/** Total number of resources in the pool regardless of state */
readonly size: number;
/** Number of resources currently available for borrowing */
readonly available: number;
/** Number of resources currently borrowed by consumers */
readonly borrowed: number;
/** Number of pending resource requests waiting in the queue */
readonly pending: number;
}Usage Examples:
// Comprehensive pool status
function getPoolStatus() {
return {
totalResources: pool.size,
available: pool.available,
inUse: pool.borrowed,
waitingRequests: pool.pending,
utilizationPercent: Math.round((pool.borrowed / pool.size) * 100),
queueDepth: pool.pending
};
}
// Resource distribution analysis
function analyzeResourceDistribution() {
const total = pool.size;
const available = pool.available;
const borrowed = pool.borrowed;
const pending = pool.pending;
console.log(`Resource Distribution:`);
console.log(` Total: ${total}`);
console.log(` Available: ${available} (${Math.round(available/total*100)}%)`);
console.log(` Borrowed: ${borrowed} (${Math.round(borrowed/total*100)}%)`);
console.log(` Pending requests: ${pending}`);
// Health indicators
if (pending > borrowed) {
console.warn('Queue backup: more requests pending than resources in use');
}
if (available === 0 && borrowed < pool.max) {
console.info('All available resources in use, but pool can still grow');
}
}
// Performance monitoring
class PoolPerformanceMonitor {
constructor(pool) {
this.pool = pool;
this.samples = [];
this.startTime = Date.now();
}
takeSample() {
const sample = {
timestamp: Date.now(),
size: this.pool.size,
available: this.pool.available,
borrowed: this.pool.borrowed,
pending: this.pool.pending,
utilizationRate: this.pool.borrowed / this.pool.size
};
this.samples.push(sample);
// Keep only last 100 samples
if (this.samples.length > 100) {
this.samples.shift();
}
return sample;
}
getAverageUtilization(minutes = 5) {
const cutoff = Date.now() - (minutes * 60 * 1000);
const recentSamples = this.samples.filter(s => s.timestamp > cutoff);
if (recentSamples.length === 0) return 0;
const totalUtilization = recentSamples.reduce((sum, s) => sum + s.utilizationRate, 0);
return totalUtilization / recentSamples.length;
}
getPeakUsage() {
return this.samples.reduce((max, sample) =>
Math.max(max, sample.borrowed), 0
);
}
}Monitor pending resource requests and queue behavior.
Usage Examples:
// Queue depth monitoring
function monitorQueue() {
const queueDepth = pool.pending;
if (queueDepth > 0) {
console.log(`${queueDepth} requests waiting for resources`);
if (queueDepth > pool.max) {
console.warn('Queue depth exceeds pool capacity - consider increasing max pool size');
}
}
}
// Queue performance metrics
class QueueMetrics {
constructor(pool) {
this.pool = pool;
this.maxQueueDepth = 0;
this.queueEvents = [];
// Monitor queue changes
setInterval(() => {
const currentPending = pool.pending;
if (currentPending > this.maxQueueDepth) {
this.maxQueueDepth = currentPending;
}
this.queueEvents.push({
timestamp: Date.now(),
pending: currentPending,
available: pool.available
});
// Keep only last hour of events
const oneHourAgo = Date.now() - (60 * 60 * 1000);
this.queueEvents = this.queueEvents.filter(e => e.timestamp > oneHourAgo);
}, 1000);
}
getQueueStats() {
return {
currentPending: this.pool.pending,
maxQueueDepth: this.maxQueueDepth,
averageQueueDepth: this.getAverageQueueDepth(),
queueBlockageTime: this.getAverageBlockageTime()
};
}
getAverageQueueDepth() {
if (this.queueEvents.length === 0) return 0;
const total = this.queueEvents.reduce((sum, e) => sum + e.pending, 0);
return total / this.queueEvents.length;
}
getAverageBlockageTime() {
// Calculate average time when queue is blocked (pending > 0 but available = 0)
const blockedEvents = this.queueEvents.filter(e => e.pending > 0 && e.available === 0);
return (blockedEvents.length / this.queueEvents.length) * 100; // Percentage
}
}Integrate pool monitoring with health check systems and alerting.
Usage Examples:
// Health check endpoint
function poolHealthCheck() {
const status = getPoolStatus();
// Determine health status
let health = 'healthy';
const issues = [];
if (status.utilizationPercent > 90) {
health = 'warning';
issues.push('High utilization');
}
if (status.queueDepth > status.totalResources) {
health = 'critical';
issues.push('Queue backup');
}
if (status.available === 0 && status.inUse < pool.max) {
issues.push('Resource starvation');
}
return {
status: health,
issues,
metrics: status,
timestamp: new Date().toISOString()
};
}
// Monitoring dashboard data
function getDashboardMetrics() {
return {
pool: {
configuration: {
maxSize: pool.max,
minSize: pool.min,
currentSize: pool.size
},
utilization: {
total: pool.size,
available: pool.available,
borrowed: pool.borrowed,
utilizationPercent: Math.round((pool.borrowed / pool.size) * 100)
},
queue: {
pending: pool.pending,
capacity: pool.spareResourceCapacity
},
health: poolHealthCheck().status
}
};
}
// Alerting integration
class PoolAlerting {
constructor(pool, thresholds = {}) {
this.pool = pool;
this.thresholds = {
highUtilization: 85,
criticalUtilization: 95,
maxQueueDepth: 50,
...thresholds
};
this.alerts = [];
this.startMonitoring();
}
startMonitoring() {
setInterval(() => {
this.checkThresholds();
}, 10000); // Check every 10 seconds
}
checkThresholds() {
const utilization = (this.pool.borrowed / this.pool.size) * 100;
const queueDepth = this.pool.pending;
if (utilization > this.thresholds.criticalUtilization) {
this.raiseAlert('critical', `Pool utilization critical: ${utilization.toFixed(1)}%`);
} else if (utilization > this.thresholds.highUtilization) {
this.raiseAlert('warning', `Pool utilization high: ${utilization.toFixed(1)}%`);
}
if (queueDepth > this.thresholds.maxQueueDepth) {
this.raiseAlert('warning', `Queue depth excessive: ${queueDepth} pending requests`);
}
}
raiseAlert(level, message) {
const alert = {
level,
message,
timestamp: Date.now(),
poolStats: getPoolStatus()
};
this.alerts.push(alert);
console.log(`[${level.toUpperCase()}] ${message}`);
// Integrate with external alerting systems
this.sendToAlertingSystem(alert);
}
sendToAlertingSystem(alert) {
// Implementation depends on your alerting system
// e.g., send to Slack, PagerDuty, email, etc.
}
}Set up real-time monitoring and logging for continuous pool observation.
Usage Examples:
// Real-time pool monitor
class RealTimePoolMonitor {
constructor(pool, intervalMs = 5000) {
this.pool = pool;
this.interval = intervalMs;
this.monitoring = false;
}
start() {
if (this.monitoring) return;
this.monitoring = true;
this.monitoringInterval = setInterval(() => {
this.logPoolState();
}, this.interval);
console.log('Pool monitoring started');
}
stop() {
if (!this.monitoring) return;
clearInterval(this.monitoringInterval);
this.monitoring = false;
console.log('Pool monitoring stopped');
}
logPoolState() {
const timestamp = new Date().toISOString();
const stats = getPoolStatus();
console.log(`[${timestamp}] Pool Status:`, {
size: stats.totalResources,
available: stats.available,
borrowed: stats.inUse,
pending: stats.waitingRequests,
utilization: `${stats.utilizationPercent}%`
});
}
}
// Usage
const monitor = new RealTimePoolMonitor(pool, 10000); // Log every 10 seconds
monitor.start();
// Stop monitoring on shutdown
process.on('SIGTERM', () => {
monitor.stop();
});