dupontbertrand:cluster
Meteor 3 compatible fork of meteorhacks:cluster — clustering, load balancing, and service discovery for Meteor.
This is a compatibility fork, not a rewrite. The goal is to provide a migration path for apps that depended on meteorhacks:cluster and can't simply switch to PM2 + Nginx because they relied on package-specific features.
What this package does
- Multi-core support — utilize all CPU cores via
CLUSTER_WORKERS_COUNT - Service discovery — instances auto-register and find each other via MongoDB
- DDP-aware load balancing — built-in balancer that understands SockJS/WebSocket routing
- Microservices —
Cluster.discoverConnection()to connect services by name - Auto-registration — add/remove instances without reconfiguring anything
When to use this vs PM2 + Nginx
| Need | Use this package | Use PM2 + Nginx |
|---|---|---|
| Multi-core only | x | |
| Auto-registration / discovery | x | |
| DDP-aware inter-instance proxying | x | |
Cluster.discoverConnection() | x | |
| Microservices via DDP | x | |
| Simple production deployment | x |
If you only need multi-core, PM2 is simpler and better maintained:
pm2 start main.js -i max --name "meteor-app"
Installation
meteor add dupontbertrand:cluster
Quick start
Multi-core only (simplest)
export CLUSTER_WORKERS_COUNT=auto # or a specific number: export CLUSTER_WORKERS_COUNT=4
Full clustering with service discovery
# MongoDB URL for cluster coordination (can be your app's MONGO_URL) export CLUSTER_DISCOVERY_URL=mongodb://host:port/db # Direct URL to this instance export CLUSTER_ENDPOINT_URL=http://this-server-ip # Service name export CLUSTER_SERVICE=web
Start as many instances as you like — they will find each other and balance DDP traffic automatically.
Microservices
1// search service 2Cluster.connect("mongodb://mongo-url"); 3Cluster.register("search"); 4 5Meteor.methods({ 6 searchPackages(text) { return Packages.find({ name: { $regex: text } }).fetch(); } 7}); 8 9// web service 10Cluster.connect("mongodb://mongo-url"); 11Cluster.register("web"); 12Cluster.allowPublicAccess("search"); 13 14const searchConn = Cluster.discoverConnection("search");
API
JavaScript API
1// Connect to discovery backend 2await Cluster.connect("mongodb://mongo-url", { 3 selfWeight: 1 // 0-1, portion of requests to process locally vs proxy 4}); 5 6// Register this instance as a service 7await Cluster.register("serviceName", { 8 endpoint: "http://direct-url-to-instance", 9 balancer: "http://balancer-url", // optional 10 uiService: "web" // optional 11}); 12 13// Allow public access to services 14Cluster.allowPublicAccess(["service1", "service2"]); 15 16// Discover a DDP connection (client and server) 17Cluster.discoverConnection("serviceName");
Environment variables
| Variable | Description |
|---|---|
CLUSTER_DISCOVERY_URL | MongoDB URL for service discovery |
CLUSTER_ENDPOINT_URL | Direct URL to this instance |
CLUSTER_SERVICE | Service name to register as |
CLUSTER_WORKERS_COUNT | Number of workers (auto = all cores) |
CLUSTER_BALANCER_URL | URL if this instance is a balancer |
CLUSTER_PUBLIC_SERVICES | Comma-separated list of public services |
CLUSTER_UI_SERVICE | Service to proxy UI from |
CLUSTER_SELF_WEIGHT | 0-1, local processing weight |
What changed from meteorhacks:cluster
This fork makes the package work on Meteor 3.4+ (Node 22, no Fibers). See METEOR3-PORT.md for the full changelog.
Summary of changes:
- MongoDB discovery backend rewritten in async/await (was
Meteor.wrapAsync/ Fibers) - MongoDB driver updated from 1.4.x (2014 tarball) to 6.12.0
Cluster.connect(),Cluster.register()are now async (wrapped inMeteor.startup)underscoredependency removed — all usages replaced with native ES2015+- npm dependencies updated:
cookies@0.9.1,http-proxy@1.18.1,portscanner@2.2.0 new Buffer()→Buffer.from()- Fixed pre-existing IPC listener bug in worker pool
- Transport-aware balancer — compatible with SockJS (default) and alternative transports from meteor/meteor#14231
api.versionsFromupdated for Meteor 3.0 compatibility- Tests adapted for Meteor 3 (async, sinon@14, no
practicalmeteor:sinon)
What was NOT changed:
- The public API (
Cluster.connect,register,discoverConnection,allowPublicAccess) - The
OverShadowServerEventpattern for HTTP/WS interception - The worker pool architecture (
child_process.fork+ port scanning) - SockJS URL patterns (still valid in Meteor 3)
Known limitations
OverShadowServerEventmonkey-patchesWebApp.httpServerlisteners — works but is fragile across Meteor upgrades- With non-SockJS transports (
DDP_TRANSPORT=ws|faye|uws), the balancer skips SockJS-specific routing but WebSocket proxying still works - Not tested on Windows (node-gyp / worker port scanning may have edge cases)
- The package adds
sinon@14toNpm.dependsfor tests — this is a known wart, it should ideally be test-only
Migration from meteorhacks:cluster
- Remove
meteorhacks:cluster - Add
dupontbertrand:cluster - No code changes needed — the API is identical
- If you used
Cluster.connect()orCluster.register()in synchronous code outside ofMeteor.startup, wrap them inawaitor move them insideMeteor.startup(async function() { ... })
Credits
Original package by Arunoda Susiripala and MeteorHacks.
Meteor 3 port by Bertrand Dupont.
License
MIT