Skip to main content

Performance Optimization

Learn how to use SkySignal to identify and fix performance bottlenecks.

Finding Slow Methods​

Using the Methods Tab​

  1. Navigate to your site's Methods tab
  2. Sort by Avg Response Time (descending)
  3. Look for methods with high P95/P99 values

Key Metrics to Watch​

MetricWarning ThresholdCritical 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:

  1. Go to Settings → Alerts
  2. Add alert for Method Response Time
  3. Set threshold (e.g., P95 > 500ms)
  4. Configure notification channel

Performance Budgets​

Define performance budgets to track over time:

MetricBudget
Method P95< 300ms
Subscription Ready Time< 500ms
Error Rate< 1%
Memory Usage< 512MB

Next Steps​