dupontbertrand:cluster

v2.0.0Published 8 hours ago

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
  • MicroservicesCluster.discoverConnection() to connect services by name
  • Auto-registration — add/remove instances without reconfiguring anything

When to use this vs PM2 + Nginx

NeedUse this packageUse PM2 + Nginx
Multi-core onlyx
Auto-registration / discoveryx
DDP-aware inter-instance proxyingx
Cluster.discoverConnection()x
Microservices via DDPx
Simple production deploymentx

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

VariableDescription
CLUSTER_DISCOVERY_URLMongoDB URL for service discovery
CLUSTER_ENDPOINT_URLDirect URL to this instance
CLUSTER_SERVICEService name to register as
CLUSTER_WORKERS_COUNTNumber of workers (auto = all cores)
CLUSTER_BALANCER_URLURL if this instance is a balancer
CLUSTER_PUBLIC_SERVICESComma-separated list of public services
CLUSTER_UI_SERVICEService to proxy UI from
CLUSTER_SELF_WEIGHT0-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 in Meteor.startup)
  • underscore dependency 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.versionsFrom updated 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 OverShadowServerEvent pattern for HTTP/WS interception
  • The worker pool architecture (child_process.fork + port scanning)
  • SockJS URL patterns (still valid in Meteor 3)

Known limitations

  • OverShadowServerEvent monkey-patches WebApp.httpServer listeners — 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@14 to Npm.depends for tests — this is a known wart, it should ideally be test-only

Migration from meteorhacks:cluster

  1. Remove meteorhacks:cluster
  2. Add dupontbertrand:cluster
  3. No code changes needed — the API is identical
  4. If you used Cluster.connect() or Cluster.register() in synchronous code outside of Meteor.startup, wrap them in await or move them inside Meteor.startup(async function() { ... })

Credits

Original package by Arunoda Susiripala and MeteorHacks.

Meteor 3 port by Bertrand Dupont.

License

MIT