async-guardian
v2.1.2
Published
Async deadlock, memory leak, and event loop monitoring for Node.js - with AI-powered suggestions
Maintainers
Readme
🛡️ Async Guardian
Catch memory leaks, deadlocks, blocking code and async bugs — instantly.
Like Chrome DevTools for your Node.js backend.
🎯 What is Guardian?
Guardian is a runtime analysis engine that detects:
- ⚡ Event Loop Blocking - Find synchronous code that's killing performance
- 🔄 Async Deadlocks - Detect circular waits and stuck promises
- 💾 Memory Leaks - Catch growing heaps before they crash production
- ⚠️ Unawaited Promises - Find missing await keywords
- 🔥 CPU-Bound Code - Identify blocking functions
All with file + line number and real-time dashboard.
🚀 Quick Start
Installation
npm install async-guardian
# or
yarn add async-guardianBasic Usage
CLI (Zero-Config)
# Start monitoring your app
npx guardian start -- node your-app.js
# Open real-time dashboard
npx guardian dashboard
# Check for deadlocks
npx guardian deadlocks
# Run health check
npx guardian doctorProgrammatic
import { Guardian } from 'async-guardian';
const guardian = Guardian.getInstance();
guardian.start();
// Your app code hereNestJS Integration (🎯 Recommended)
// app.module.ts
import { GuardianModule } from 'async-guardian/nestjs';
@Module({
imports: [
GuardianModule.forRoot({
dashboard: {
enabled: true,
port: 4600,
},
monitoring: {
eventLoop: true,
promises: true,
memory: true,
unawaitedPromises: true,
},
}),
],
})
export class AppModule {}Then visit: http://localhost:4600 for real-time monitoring.
💡 Key Features
1. Async Deadlock Detection
Automatically detects promises that are stuck waiting:
// ❌ This will be detected as a deadlock
async function orderService() {
await paymentService(); // Waiting...
}
async function paymentService() {
await orderService(); // Circular wait!
}Guardian Output:
🔴 CIRCULAR DEADLOCK DETECTED
Promise pending for 32s at:
src/order.service.ts:34
This is a circular dependency in your async calls.2. Unawaited Promise Detection
Finds promises that are created but never awaited:
// ❌ Missing await
async function badCode() {
someAsyncFunction(); // No await!
return 'done';
}Guardian Output:
⚠️ UNAWAITED PROMISE
src/user.service.ts:45
Fix: Add 'await' keyword or .catch()3. Memory Leak Detection
Monitors heap growth and identifies leaks:
🔴 MEMORY LEAK DETECTED
Heap growth: +127MB over 60s
Trend: growing
Common causes:
1. Event listeners not removed
2. Timers not cleared
3. Caches without size limits4. Event Loop Monitoring
Detects blocking code:
⚠️ EVENT LOOP STALL
Duration: 523ms (Critical!)
Look for:
- Synchronous I/O (fs.readFileSync)
- Heavy CPU computations
- Blocking database queries5. Real-Time Dashboard
Beautiful web UI with live metrics:
- 📊 Event loop lag graph
- 💾 Memory usage chart
- 🔄 Pending promises list
- ⚡ Live event stream
- 🎯 Issue suggestions
📖 CLI Commands
# Start monitoring
guardian start
# Open dashboard
guardian dashboard
# Show current status
guardian status
# Show recent events
guardian events
# Check for deadlocks (runs for 5s)
guardian deadlocks
# Run full health check (runs for 10s)
guardian doctor🎯 NestJS Integration
Guardian has first-class support for NestJS:
Method Monitoring
import { MonitorAsync } from 'async-guardian/nestjs';
@Injectable()
export class UserService {
@MonitorAsync({ timeout: 5000 })
async findUser(id: string) {
// Will alert if this takes > 5 seconds
return await this.db.user.findOne({ id });
}
}Class Monitoring
import { GuardianMonitored } from 'async-guardian/nestjs';
@GuardianMonitored()
@Injectable()
export class PaymentService {
// All async methods in this class are monitored
}🔧 Configuration
Advanced Config
import { Guardian } from 'async-guardian';
const guardian = Guardian.create({
eventLoop: {
enabled: true,
stallThreshold: 100, // ms
sampleInterval: 1000,
},
promises: {
enabled: true,
deadlockThreshold: 30000, // 30s
checkInterval: 5000,
},
memory: {
enabled: true,
checkInterval: 5000,
leakThreshold: 10, // MB
consecutiveGrowth: 3,
},
unawaitedPromises: {
enabled: true,
checkInterval: 3000,
warningThreshold: 5000,
},
});
guardian.start();🎨 Dashboard
Access the dashboard:
guardian dashboard --port 4600 --host localhostThen open: http://localhost:4600
Features:
- Real-time metrics
- Event stream
- Prometheus-style graphs
- Issue details with suggestions
- Export capabilities
📊 API Usage
import { Guardian, EventType } from 'async-guardian';
const guardian = Guardian.getInstance();
// Listen to specific events
guardian.getEventStore().on(EventType.MEMORY_LEAK, (event) => {
console.log('Memory leak detected!', event);
// Send to Slack, PagerDuty, etc.
});
// Get current status
const status = guardian.getStatus();
console.log(status);
// Get pending promises
const promises = guardian.getPendingPromises();
// Force garbage collection (if --expose-gc enabled)
guardian.forceGC();🚀 Production Usage
Recommended Setup
// main.ts
import { Guardian } from 'async-guardian';
import { DashboardServer } from 'async-guardian/dashboard';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
if (process.env.NODE_ENV === 'production') {
const guardian = Guardian.getInstance();
guardian.start();
// Only start dashboard on internal port
const dashboard = new DashboardServer(guardian, {
port: 4600,
host: '127.0.0.1', // Only localhost
});
await dashboard.start();
}
await app.listen(3000);
}Performance Impact
Guardian has minimal overhead:
- Dev Mode: ~5-10% CPU overhead
- Production Mode: ~2-3% CPU overhead (recommended config)
- Memory: ~50MB base + ~5MB per 10k tracked promises
🤝 Enterprise Features
Need more? We offer:
- 📊 Team Dashboard - Centralized monitoring for all services
- 📈 Historical Analysis - 90 days retention
- 🔔 Advanced Alerting - Slack, PagerDuty, Email
- 🎯 Custom Rules - Define your own detection logic
- 🏢 On-Premise - Deploy in your infrastructure
- 🎓 Training - Node.js performance workshops
- 🛠️ Consulting - Performance audits & optimization
Contact: [[email protected]]
📚 Examples
Check out the /examples folder for:
- Express integration
- NestJS full example
- Microservices setup
- Custom monitoring rules
🐛 Troubleshooting
"Can't call forceGC()"
Run with: node --expose-gc your-app.js
"Too many warnings about unawaited promises"
Adjust threshold in config or filter by file pattern.
"Dashboard not accessible"
Check firewall rules and host configuration.
🤝 Contributing
We love contributions! See CONTRIBUTING.md
📄 License
MIT © 2025
🌟 Why Guardian?
Other tools:
- ❌ Too complex (require deep V8 knowledge)
- ❌ Too expensive (APM services)
- ❌ Too limited (single-purpose)
- ❌ Too slow (high overhead)
Guardian:
- ✅ Zero-config
- ✅ Framework-aware (NestJS first-class)
- ✅ AI-powered suggestions
- ✅ Beautiful UI
- ✅ Minimal overhead
- ✅ Open source
Made with ❤️ for the Node.js community
Star us on GitHub! ⭐
