Performance Optimization
Learn how to use SkySignal to identify and fix performance bottlenecks.
Finding Slow Methods
Using the Methods Tab
- Navigate to your site's Methods tab
- Sort by Avg Response Time (descending)
- Look for methods with high P95/P99 values
Key Metrics to Watch
| Metric | Warning Threshold | Critical Threshold |
|---|---|---|
| Avg Response Time | > 200ms | > 500ms |
| P95 Response Time | > 500ms | > 1000ms |
| Error Rate | > 1% | > 5% |
Common Performance Issues
1. N+1 Query Problems
Symptoms:
- High method response times
- Many database queries per request
Solution:
// ❌ Bad: N+1 queries
const posts = Posts.find().fetch();
posts.forEach(post => {
post.author = Users.findOne(post.authorId);
});
// ✅ Good: Batch query
const posts = Posts.find().fetch();
const authorIds = [...new Set(posts.map(p => p.authorId))];
const authors = Users.find({ _id: { $in: authorIds } }).fetch();
const authorsMap = Object.fromEntries(authors.map(a => [a._id, a]));
posts.forEach(post => {
post.author = authorsMap[post.authorId];
});
2. Missing Database Indexes
Symptoms:
- Slow queries on large collections
- High CPU usage on database
Solution:
// Add indexes for frequently queried fields
Posts.createIndex({ authorId: 1 });
Posts.createIndex({ createdAt: -1 });
Posts.createIndex({ status: 1, createdAt: -1 });
3. Blocking Operations
Symptoms:
- Event loop lag spikes
- Slow response times across all methods
Solution:
// ❌ Bad: Blocking the event loop
const result = heavyComputation(data);
// ✅ Good: Use this.unblock() in methods
Meteor.methods({
'posts.process'() {
this.unblock(); // Allow other methods to run
return heavyComputation(data);
}
});
4. Memory Leaks
Symptoms:
- Memory usage continuously increasing
- Periodic slowdowns or crashes
Common Causes:
- Unreleased subscriptions
- Growing global caches
- Event listeners not cleaned up
Optimization Strategies
Method Optimization
Meteor.methods({
'posts.list'(options = {}) {
this.unblock();
const { limit = 20, skip = 0 } = options;
// Use projection to limit returned fields
return Posts.find(
{ status: 'published' },
{
fields: { title: 1, summary: 1, createdAt: 1 },
sort: { createdAt: -1 },
limit,
skip
}
).fetch();
}
});
Publication Optimization
Meteor.publish('posts.recent', function(limit = 10) {
// Limit fields sent to client
return Posts.find(
{ status: 'published' },
{
fields: { title: 1, summary: 1, authorId: 1 },
sort: { createdAt: -1 },
limit
}
);
});
Caching Strategies
import { Meteor } from 'meteor/meteor';
// Simple in-memory cache
const cache = new Map();
const CACHE_TTL = 60000; // 1 minute
function getCachedOrFetch(key, fetchFn) {
const cached = cache.get(key);
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
return cached.data;
}
const data = fetchFn();
cache.set(key, { data, timestamp: Date.now() });
return data;
}
Meteor.methods({
'stats.dashboard'() {
return getCachedOrFetch('dashboard-stats', () => {
return computeExpensiveStats();
});
}
});
Setting Up Alerts
Create alerts for performance degradation:
- Go to Settings → Alerts
- Add alert for Method Response Time
- Set threshold (e.g., P95 > 500ms)
- Configure notification channel
Performance Budgets
Define performance budgets to track over time:
| Metric | Budget |
|---|---|
| Method P95 | < 300ms |
| Subscription Ready Time | < 500ms |
| Error Rate | < 1% |
| Memory Usage | < 512MB |
Next Steps
- Error Tracking Guide - Track and fix errors
- Custom Metrics - Track business metrics
- Alerting Guide - Set up notifications