From 3e8b876052391dfcfb09914cbe5d545f94dbaf80 Mon Sep 17 00:00:00 2001 From: Mickael Bourgois Date: Tue, 22 Jul 2025 20:45:06 +0200 Subject: [PATCH 1/6] CLDSRV-717: Rename cluster master to primary master is deprecated --- lib/server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/server.js b/lib/server.js index 4e302f9904..83e53cfaaa 100644 --- a/lib/server.js +++ b/lib/server.js @@ -303,7 +303,7 @@ class S3Server { workerId: this.worker ? this.worker.id : undefined, workerPid: this.worker ? this.worker.process.pid : undefined, }); - // Will close all servers, cause disconnect event on master and kill + // Will close all servers, cause disconnect event on primary and kill // worker process with 'SIGTERM'. if (this.worker) { this.worker.kill(); @@ -389,7 +389,7 @@ function main() { const server = new S3Server(_config); server.initiateStartup(logger.newRequestLogger()); } - if (this.cluster && cluster.isMaster) { + if (this.cluster && cluster.isPrimary) { for (let n = 0; n < workers; n++) { const worker = cluster.fork(); logger.info('new worker forked', { From 313157ae2c967283d62412b2f1c822ad0297c8f7 Mon Sep 17 00:00:00 2001 From: Mickael Bourgois Date: Tue, 22 Jul 2025 20:46:46 +0200 Subject: [PATCH 2/6] CLDSRV-717: Fix cluster boolean in S3Server --- lib/Config.js | 4 ++++ lib/server.js | 15 +++++---------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/Config.js b/lib/Config.js index ee06af81ae..84d31bff92 100644 --- a/lib/Config.js +++ b/lib/Config.js @@ -1032,6 +1032,10 @@ class Config extends EventEmitter { 'bad config: clusters must be a positive integer'); this.clusters = config.clusters; } + if (process.env.S3BACKEND === 'mem') { + this.clusters = 1; + } + this.isCluster = this.clusters > 1; if (config.usEastBehavior !== undefined) { throw new Error('bad config: usEastBehavior key is deprecated. ' + diff --git a/lib/server.js b/lib/server.js index 83e53cfaaa..d240f5abe9 100644 --- a/lib/server.js +++ b/lib/server.js @@ -67,7 +67,7 @@ class S3Server { constructor(config, worker) { this.config = config; this.worker = worker; - this.cluster = true; + this.cluster = config.isCluster; this.servers = []; http.globalAgent = new HttpAgent({ keepAlive: true, @@ -378,18 +378,13 @@ class S3Server { } function main() { - // TODO: change config to use workers prop. name for clarity - let workers = _config.clusters || 1; - if (process.env.S3BACKEND === 'mem') { - workers = 1; - } - this.cluster = workers > 1; - if (!this.cluster) { + const workers = _config.clusters; + if (!_config.isCluster) { process.env.REPORT_TOKEN = _config.reportToken; const server = new S3Server(_config); server.initiateStartup(logger.newRequestLogger()); } - if (this.cluster && cluster.isPrimary) { + if (_config.isCluster && cluster.isPrimary) { for (let n = 0; n < workers; n++) { const worker = cluster.fork(); logger.info('new worker forked', { @@ -431,7 +426,7 @@ function main() { }); }); } - if (this.cluster && cluster.isWorker) { + if (_config.isCluster && cluster.isWorker) { const server = new S3Server(_config, cluster.worker); server.initiateStartup(logger.newRequestLogger()); } From 95fa93c649707cf0d8bf11bf925212e2417cb217 Mon Sep 17 00:00:00 2001 From: Mickael Bourgois Date: Tue, 22 Jul 2025 20:47:31 +0200 Subject: [PATCH 3/6] CLDSRV-717: Cluster start metricsServer on primary --- lib/server.js | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/lib/server.js b/lib/server.js index d240f5abe9..54e2ab9449 100644 --- a/lib/server.js +++ b/lib/server.js @@ -310,6 +310,16 @@ class S3Server { } } + startServer(listenOn, port, routeRequest) { + if (listenOn.length > 0) { + listenOn.forEach(item => { + this._startServer(routeRequest.bind(this), item.port, item.ip); + }); + } else if (port) { + this._startServer(routeRequest.bind(this), port); + } + } + initiateStartup(log) { series([ next => metadata.setup(next), @@ -329,30 +339,14 @@ class S3Server { } // Start API server(s) - if (this.config.listenOn.length > 0) { - this.config.listenOn.forEach(item => { - this._startServer(this.routeRequest.bind(this), item.port, item.ip); - }); - } else if (this.config.port) { - this._startServer(this.routeRequest.bind(this), this.config.port); - } + this.startServer(this.config.listenOn, this.config.port, this.routeRequest); // Start internal API server(s) - if (this.config.internalListenOn.length > 0) { - this.config.internalListenOn.forEach(item => { - this._startServer(this.internalRouteRequest.bind(this), item.port, item.ip); - }); - } else if (this.config.internalPort) { - this._startServer(this.internalRouteRequest.bind(this), this.config.internalPort); - } + this.startServer(this.config.internalListenOn, this.config.internalPort, this.internalRouteRequest); - // Start metrics server(s) - if (this.config.metricsListenOn.length > 0) { - this.config.metricsListenOn.forEach(item => { - this._startServer(this.routeAdminRequest.bind(this), item.port, item.ip); - }); - } else { - this._startServer(this.routeAdminRequest.bind(this), this.config.metricsPort); + // Start metrics server(s) only if not cluster mode worker + if (!this.cluster && !this.worker) { + this.startServer(this.config.metricsListenOn, this.config.metricsPort, this.routeAdminRequest); } // Start quota service health checks @@ -425,6 +419,10 @@ function main() { workerPid: worker.process.pid, }); }); + + const metricServer = new S3Server(_config); + metricServer.startServer(_config.metricsListenOn, + _config.metricsPort, metricServer.routeAdminRequest); } if (_config.isCluster && cluster.isWorker) { const server = new S3Server(_config, cluster.worker); From 00f5cf872ca295217b52fd349634ff15c0733c33 Mon Sep 17 00:00:00 2001 From: Mickael Bourgois Date: Tue, 22 Jul 2025 20:48:26 +0200 Subject: [PATCH 4/6] CLDSRV-717: Cluster primary doesn't collectMetrics It only aggregates metrics from workers --- lib/server.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/server.js b/lib/server.js index 54e2ab9449..985d0f29d5 100644 --- a/lib/server.js +++ b/lib/server.js @@ -428,7 +428,11 @@ function main() { const server = new S3Server(_config, cluster.worker); server.initiateStartup(logger.newRequestLogger()); } - monitoringClient.collectDefaultMetrics({ timeout: 5000 }); + + // Avoid default metrics on cluster primary as it only aggregate workers + if (!_config.isCluster || cluster.isWorker) { + monitoringClient.collectDefaultMetrics({ timeout: 5000 }); + } } module.exports = main; From 5c9c473dff2e4ed46250ab46fabdd01807cc09f8 Mon Sep 17 00:00:00 2001 From: Mickael Bourgois Date: Tue, 22 Jul 2025 20:49:43 +0200 Subject: [PATCH 5/6] CLDSRV-717: Prometheus use aggregate registry for cluster mode --- lib/utilities/monitoringHandler.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/utilities/monitoringHandler.js b/lib/utilities/monitoringHandler.js index 87a455193a..712a083067 100644 --- a/lib/utilities/monitoringHandler.js +++ b/lib/utilities/monitoringHandler.js @@ -215,16 +215,27 @@ function writeResponse(res, error, results, cb) { }); } +const registry = config.isCluster ? new client.AggregatorRegistry() : client.register; +const getMetrics = config.isCluster ? + registry.clusterMetrics.bind(registry) : registry.metrics.bind(registry); async function routeHandler(req, res, cb) { if (req.method !== 'GET') { return cb(errors.BadRequest, []); } - const promMetrics = await client.register.metrics(); + let promMetrics; + try { + // Catch timeout on IPC between worker and primary + // prom-client has a 5s hardcoded timeout + promMetrics = await getMetrics(); + } catch (err) { + return cb(err, { message: err.toString() }); + } + const contentLen = Buffer.byteLength(promMetrics, 'utf8'); res.writeHead(200, { 'Content-Length': contentLen, - 'Content-Type': client.register.contentType, + 'Content-Type': registry.contentType, }); res.end(promMetrics); return undefined; From 73488a3a149af8e14c4813ce5a716b302d2638cc Mon Sep 17 00:00:00 2001 From: Mickael Bourgois Date: Wed, 23 Jul 2025 19:23:26 +0200 Subject: [PATCH 6/6] CLDSRV-717: Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 68c96d87eb..85b272a418 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@zenko/cloudserver", - "version": "9.0.21", + "version": "9.0.22", "description": "Zenko CloudServer, an open-source Node.js implementation of a server handling the Amazon S3 protocol", "main": "index.js", "engines": {