Live Query Monitoring
SkySignal monitors Meteor's reactive query system -- the observers that keep your client-side data in sync with MongoDB. This is one of the most important things to keep an eye on in a Meteor app, because observer leaks and inefficient driver usage are common sources of memory and performance problems.
What Gets Tracked
For each observer in your application, SkySignal captures:
| Field | Description |
|---|---|
observerType | Driver type: changeStream, oplog, or polling |
observerCount | Total number of active observers |
documentsUpdated | Document update rates per observer |
reactiveEfficiency | Percentage of observers using efficient drivers |
timestamp | When the snapshot was taken |
The key metric here is reactive efficiency: the percentage of your observers that use an efficient real-time driver (change streams or oplog tailing) rather than polling.
How It Works
Observer Driver Detection
The agent inspects each observer's internal driver to determine how it receives updates from MongoDB. It does this by looking at:
handle._multiplexer._observeDriver.constructor.name
This gives the agent the driver class name, which maps to one of three observer types:
| Observer Type | Driver | Meteor Version | Efficiency |
|---|---|---|---|
changeStream | MongoDB Change Streams | 3.5+ | Best |
oplog | Oplog tailing | 3.0+ | Good |
polling | Periodic polling | 3.0+ | Least efficient |
Meteor 3.5+ Change Streams
Starting with Meteor 3.5, Meteor can use MongoDB Change Streams as the reactive driver instead of oplog tailing. Change Streams are the most efficient method -- they use MongoDB's built-in change notification system rather than tailing the oplog directly.
The agent automatically detects change stream usage. If you see changeStream observers in your dashboard, your app is taking advantage of this.
Requirements for Change Streams:
- Meteor 3.5 or later
- MongoDB replica set (standalone MongoDB instances don't support Change Streams)
Oplog vs Polling Fallback
For apps running Meteor 3.0 through 3.4 (or 3.5+ without a replica set), the agent checks for the MONGO_OPLOG_URL environment variable to distinguish between oplog tailing and polling:
- If
MONGO_OPLOG_URLis set and the driver matches an oplog driver, the observer is classified asoplog - Otherwise, it falls back to
polling
Configuration
Live query monitoring is controlled by a single setting:
{
"skysignal": {
"collectLiveQueries": true
}
}
| Option | Type | Default | Description |
|---|---|---|---|
collectLiveQueries | Boolean | true | Enable or disable live query monitoring |
There is no sampling option for live queries. The agent takes periodic snapshots of observer state, and the overhead is minimal since it is reading in-memory data structures rather than generating new events.
Dashboard
Navigate to your site's Live Queries tab to see the monitoring data.
Observer Overview
At the top you will see summary cards:
- Total Observers - Current count of active observers across your app
- Reactive Efficiency - The percentage of observers using efficient drivers
- Observer Breakdown - Count by type (change stream, oplog, polling)
Driver Statistics
The Driver Statistics card shows per-driver metrics:
- Observer count for each driver type
- Document update rates per driver
- Relative efficiency comparison
Trend Charts
The trend charts show observer counts over time. This is where you spot problems:
- A steadily growing observer count without corresponding subscriber growth usually means you have an observer leak
- A sudden spike in polling observers might mean your oplog connection dropped
- A shift from oplog to change stream after a Meteor upgrade is expected and good
Reactive Efficiency
Reactive efficiency is calculated as:
reactiveEfficiency = (changeStreamObservers + oplogObservers) / totalObservers
This tells you what percentage of your observers are using real-time drivers. The rest are polling, which means they are periodically re-running the query to check for changes.
What to aim for:
| Efficiency | Assessment |
|---|---|
| 90%+ | Good. Most of your observers are real-time. |
| 70-90% | Acceptable, but worth investigating the polling observers. |
| Below 70% | You likely have a configuration issue. Check your MongoDB setup. |
A few things can cause low reactive efficiency:
- No replica set - Oplog tailing and Change Streams both require a MongoDB replica set. If you are running a standalone MongoDB instance, all observers will fall back to polling.
- Missing
MONGO_OPLOG_URL- On Meteor versions before 3.5, you need this environment variable set for oplog tailing to work. - Unsupported query operators - Some MongoDB query operators are not compatible with oplog tailing. Queries using
$where,$near, or certain aggregation features will fall back to polling.
Change Streams (Meteor 3.5+)
If your app runs Meteor 3.5 or later with a MongoDB replica set, you get Change Streams support automatically. This is the most efficient reactive driver available.
Change Streams advantages over oplog tailing:
- Lower overhead - MongoDB pushes changes directly rather than the app tailing the oplog
- Better filtering - Change Streams can filter at the database level, reducing the data your app processes
- More reliable - Less sensitive to oplog size and retention settings
The agent detects change stream observers automatically. After upgrading to Meteor 3.5+, you should see your observer types shift from oplog to changeStream in the dashboard.
If you have upgraded to 3.5+ but still see mostly oplog observers, make sure:
- Your MongoDB is running as a replica set
- You are using a MongoDB version that supports Change Streams (4.0+)
- Your app has restarted after the Meteor upgrade
Best Practices
Aim for high reactive efficiency
Minimize the number of polling observers. If your reactive efficiency is below 90%, check your MongoDB setup first -- a missing replica set is the most common cause.
Watch for observer leaks
An observer leak happens when subscriptions are created but never cleaned up. Common causes:
- Components that subscribe in
useEffectbut don't return a cleanup function - Subscriptions created in
Tracker.autorunthat are never stopped - Server-side observers started with
observeChangesthat are never stopped
The trend chart in the Live Queries tab is your best tool here. If observer count keeps climbing and never comes back down, you have a leak.
// Good: cleanup on unmount
useEffect(() => {
const handle = Meteor.subscribe('posts');
return () => handle.stop();
}, []);
// Bad: no cleanup
useEffect(() => {
Meteor.subscribe('posts'); // This observer leaks on unmount
}, []);
Upgrade to Meteor 3.5+ for Change Streams
If you are still on Meteor 3.0-3.4 and using oplog tailing, consider upgrading to 3.5+ to take advantage of Change Streams. The agent will automatically detect and report the improved driver usage.
Ensure your MongoDB is a replica set
Both oplog tailing and Change Streams require a replica set. If you are developing locally with a standalone MongoDB instance, all your observers will show as polling. This is expected in local dev, but make sure your staging and production environments use replica sets.
For local development, you can convert to a single-node replica set:
mongosh --eval "rs.initiate()"
Troubleshooting
All Observers Show as Polling
- Check if your MongoDB is running as a replica set (
rs.status()in mongosh) - Verify
MONGO_OPLOG_URLis set (for Meteor versions before 3.5) - Make sure the agent can access the oplog database
Observer Count Keeps Growing
This is an observer leak. Check your client-side code for subscriptions that are not being cleaned up. The most common culprit is useEffect hooks that call Meteor.subscribe without returning a stop function.
Reactive Efficiency Dropped Suddenly
A sudden drop usually means your oplog or change stream connection was lost. Check:
- MongoDB replica set health
- Network connectivity between your app and MongoDB
- Oplog size -- if the oplog is too small and wraps around, Meteor loses its place and falls back to polling
Live Queries Not Appearing
- Verify
collectLiveQueriesistrue(or not set -- it defaults totrue) - Make sure your app actually has active subscriptions (no subscriptions means no observers)
- Check that the agent is initialized and connected
Next Steps
- Subscription Monitoring - Track DDP subscription performance
- Log Collection - Capture and search application logs
- Performance Optimization - Optimize reactive query performance