@contember/engine-server 2.1.0-alpha.8 → 2.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CLAUDE.md ADDED
@@ -0,0 +1,24 @@
1
+ # engine-server
2
+
3
+ Entry point for the Contember backend. Bootstraps the DI container, loads plugins, resolves configuration, and manages process lifecycle (single-node or clustered).
4
+
5
+ ## Boot Sequence
6
+
7
+ 1. `start.ts`: Load plugins (S3, Vimeo, Actions), resolve config from env/YAML/JSON, create `MasterContainer` from `engine-http`
8
+ 2. Master process: run tenant migrations, initialize projects, start monitoring server (Prometheus)
9
+ 3. If `workerCount` configured: fork worker processes via `WorkerManager` with auto-restart on crash
10
+ 4. Workers: start HTTP server via `container.application.listen()`
11
+
12
+ ## Clustering
13
+
14
+ - `WorkerManager` forks Node.js child processes, coordinates via IPC (`msg_worker_started`)
15
+ - 15-second startup timeout per worker, 2-second delay on restart
16
+ - Graceful termination: disconnect → kill sequence
17
+
18
+ ## Plugins
19
+
20
+ `loadPlugins()` returns `[S3Plugin(), VimeoPlugin(), ActionsPlugin()]`. Plugins hook into config, schema, execution container, and master container lifecycle.
21
+
22
+ ## Config
23
+
24
+ Loaded from `CONTEMBER_CONFIG_FILE` (YAML), `CONTEMBER_CONFIG_YAML`, or `CONTEMBER_CONFIG_JSON` env vars. Key env vars: `NODE_ENV` (debug mode), `CONTEMBER_LOGGER_FORMAT` (pretty/json).
@@ -65,19 +65,21 @@ class WorkerManager {
65
65
  throw new Error(`Worker manager is terminating`);
66
66
  }
67
67
  this.isTerminating = true;
68
- await Promise.allSettled(Array.from(this.workers).map(async (it) => {
69
- if (!it) {
70
- return;
71
- }
72
- console.log(`Terminating worker ${it.process.pid}`);
73
- const disconnectPromise = new Promise((resolve) => it.once("disconnect", resolve));
74
- it.disconnect();
75
- await disconnectPromise;
76
- const killPromise = new Promise((resolve) => it.once("exit", resolve));
77
- it.kill(signal);
78
- await killPromise;
79
- console.log(`Worker ${it.process.pid} terminated`);
80
- }));
68
+ await Promise.allSettled(
69
+ Array.from(this.workers).map(async (it) => {
70
+ if (!it) {
71
+ return;
72
+ }
73
+ console.log(`Terminating worker ${it.process.pid}`);
74
+ const disconnectPromise = new Promise((resolve) => it.once("disconnect", resolve));
75
+ it.disconnect();
76
+ await disconnectPromise;
77
+ const killPromise = new Promise((resolve) => it.once("exit", resolve));
78
+ it.kill(signal);
79
+ await killPromise;
80
+ console.log(`Worker ${it.process.pid} terminated`);
81
+ })
82
+ );
81
83
  }
82
84
  }
83
85
  exports.WorkerManager = WorkerManager;
@@ -1 +1 @@
1
- {"version":3,"file":"cluster.cjs","sources":["../../../../packages/engine-server/src/cluster.ts"],"sourcesContent":["import cluster, { Worker } from 'node:cluster'\nimport { timeout } from './utils'\n\nexport const getClusterProcessType = (isClusterMode: boolean): ProcessType =>\n\t!isClusterMode ? 'singleNode' : cluster.isMaster ? 'clusterMaster' : 'clusterWorker'\n\nexport type ProcessType =\n\t| 'singleNode'\n\t| 'clusterMaster'\n\t| 'clusterWorker'\n\nconst MSG_WORKER_STARTED = 'msg_worker_started'\n\nexport const waitForWorker = (worker: Worker, timeoutMs: number) => {\n\tlet ok = false\n\treturn Promise.race([\n\t\tnew Promise(async resolve => {\n\t\t\tconst listener = (message: any) => {\n\t\t\t\tif ('type' in message && message.type === MSG_WORKER_STARTED) {\n\t\t\t\t\tok = true\n\t\t\t\t\tresolve(null)\n\t\t\t\t\tworker.removeListener('message', listener)\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait worker.on('message', listener)\n\t\t}),\n\t\ttimeout(timeoutMs).then(() => {\n\t\t\tif (!ok) {\n\t\t\t\tthrow new Error('Worker start timed out')\n\t\t\t}\n\t\t\treturn true\n\t\t}),\n\t])\n}\n\nexport const notifyWorkerStarted = () =>\n\tprocess.send?.({\n\t\ttype: MSG_WORKER_STARTED,\n\t})\n\nexport class WorkerManager {\n\n\tprivate isTerminating = false\n\n\tprivate workers: Set<Worker> = new Set()\n\n\tpublic async start({ workerCount, env }: { workerCount: number; env?: any }): Promise<void> {\n\t\tif (this.isTerminating) {\n\t\t\tthrow new Error(`Worker manager is terminating`)\n\t\t}\n\t\tfor (let i = 0; i < workerCount; i++) {\n\t\t\tawait this.startWorker(env)\n\t\t\tif (this.isTerminating) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async startWorker(env?: any) {\n\t\tconst worker = cluster.fork(env)\n\t\tworker.on('exit', async (code, signal) => {\n\t\t\tthis.workers.delete(worker)\n\t\t\tif (!this.isTerminating) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.log(`Worker ${worker.process.pid} died with signal ${signal}, restarting`)\n\t\t\t\tawait timeout(2000)\n\t\t\t\tawait this.startWorker(env)\n\t\t\t}\n\t\t})\n\t\tthis.workers.add(worker)\n\t\tawait waitForWorker(worker, 15000)\n\t}\n\n\tpublic async terminate(signal: NodeJS.Signals): Promise<void> {\n\t\tif (this.isTerminating) {\n\t\t\tthrow new Error(`Worker manager is terminating`)\n\t\t}\n\t\tthis.isTerminating = true\n\t\tawait Promise.allSettled(Array.from(this.workers).map(async it => {\n\t\t\tif (!it) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.log(`Terminating worker ${it.process.pid}`)\n\t\t\tconst disconnectPromise = new Promise(resolve => it.once('disconnect', resolve))\n\t\t\tit.disconnect()\n\t\t\tawait disconnectPromise\n\t\t\tconst killPromise = new Promise(resolve => it.once('exit', resolve))\n\t\t\tit.kill(signal)\n\t\t\tawait killPromise\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.log(`Worker ${it.process.pid} terminated`)\n\t\t}))\n\t}\n}\n"],"names":["timeout"],"mappings":";;;;;;;AAGa,MAAA,wBAAwB,CAAC,kBACrC,CAAC,gBAAgB,eAAe,QAAQ,WAAW,kBAAkB;AAOtE,MAAM,qBAAqB;AAEd,MAAA,gBAAgB,CAAC,QAAgB,cAAsB;AACnE,MAAI,KAAK;AACT,SAAO,QAAQ,KAAK;AAAA,IACnB,IAAI,QAAQ,OAAM,YAAW;AACtB,YAAA,WAAW,CAAC,YAAiB;AAClC,YAAI,UAAU,WAAW,QAAQ,SAAS,oBAAoB;AACxD,eAAA;AACL,kBAAQ,IAAI;AACL,iBAAA,eAAe,WAAW,QAAQ;AAAA,QAAA;AAAA,MAE3C;AACM,YAAA,OAAO,GAAG,WAAW,QAAQ;AAAA,IAAA,CACnC;AAAA,IACDA,cAAQ,SAAS,EAAE,KAAK,MAAM;AAC7B,UAAI,CAAC,IAAI;AACF,cAAA,IAAI,MAAM,wBAAwB;AAAA,MAAA;AAElC,aAAA;AAAA,IACP,CAAA;AAAA,EAAA,CACD;AACF;AAEa,MAAA,sBAAsB,MAClC,QAAQ,OAAO;AAAA,EACd,MAAM;AACP,CAAC;AAEK,MAAM,cAAc;AAAA,EAApB,cAAA;AAEN,kBAAA,MAAQ,iBAAgB,KAAA;AAEhB,kBAAA,MAAA,+BAA2B,IAAI,CAAA;AAAA,EAAA;AAAA,EAEvC,MAAa,MAAM,EAAE,aAAa,OAA0D;AAC3F,QAAI,KAAK,eAAe;AACjB,YAAA,IAAI,MAAM,+BAA+B;AAAA,IAAA;AAEhD,aAAS,IAAI,GAAG,IAAI,aAAa,KAAK;AAC/B,YAAA,KAAK,YAAY,GAAG;AAC1B,UAAI,KAAK,eAAe;AACvB;AAAA,MAAA;AAAA,IACD;AAAA,EACD;AAAA,EAGD,MAAc,YAAY,KAAW;AAC9B,UAAA,SAAS,QAAQ,KAAK,GAAG;AAC/B,WAAO,GAAG,QAAQ,OAAO,MAAM,WAAW;AACpC,WAAA,QAAQ,OAAO,MAAM;AACtB,UAAA,CAAC,KAAK,eAAe;AAExB,gBAAQ,IAAI,UAAU,OAAO,QAAQ,GAAG,qBAAqB,MAAM,cAAc;AACjF,cAAMA,MAAAA,QAAQ,GAAI;AACZ,cAAA,KAAK,YAAY,GAAG;AAAA,MAAA;AAAA,IAC3B,CACA;AACI,SAAA,QAAQ,IAAI,MAAM;AACjB,UAAA,cAAc,QAAQ,IAAK;AAAA,EAAA;AAAA,EAGlC,MAAa,UAAU,QAAuC;AAC7D,QAAI,KAAK,eAAe;AACjB,YAAA,IAAI,MAAM,+BAA+B;AAAA,IAAA;AAEhD,SAAK,gBAAgB;AACf,UAAA,QAAQ,WAAW,MAAM,KAAK,KAAK,OAAO,EAAE,IAAI,OAAM,OAAM;AACjE,UAAI,CAAC,IAAI;AACR;AAAA,MAAA;AAGD,cAAQ,IAAI,sBAAsB,GAAG,QAAQ,GAAG,EAAE;AAC5C,YAAA,oBAAoB,IAAI,QAAQ,CAAA,YAAW,GAAG,KAAK,cAAc,OAAO,CAAC;AAC/E,SAAG,WAAW;AACR,YAAA;AACA,YAAA,cAAc,IAAI,QAAQ,CAAA,YAAW,GAAG,KAAK,QAAQ,OAAO,CAAC;AACnE,SAAG,KAAK,MAAM;AACR,YAAA;AAEN,cAAQ,IAAI,UAAU,GAAG,QAAQ,GAAG,aAAa;AAAA,IAAA,CACjD,CAAC;AAAA,EAAA;AAEJ;;;;;"}
1
+ {"version":3,"file":"cluster.cjs","sources":["../../../../packages/engine-server/src/cluster.ts"],"sourcesContent":["import cluster, { Worker } from 'node:cluster'\nimport { timeout } from './utils'\n\nexport const getClusterProcessType = (isClusterMode: boolean): ProcessType =>\n\t!isClusterMode ? 'singleNode' : cluster.isMaster ? 'clusterMaster' : 'clusterWorker'\n\nexport type ProcessType =\n\t| 'singleNode'\n\t| 'clusterMaster'\n\t| 'clusterWorker'\n\nconst MSG_WORKER_STARTED = 'msg_worker_started'\n\nexport const waitForWorker = (worker: Worker, timeoutMs: number) => {\n\tlet ok = false\n\treturn Promise.race([\n\t\tnew Promise(async resolve => {\n\t\t\tconst listener = (message: any) => {\n\t\t\t\tif ('type' in message && message.type === MSG_WORKER_STARTED) {\n\t\t\t\t\tok = true\n\t\t\t\t\tresolve(null)\n\t\t\t\t\tworker.removeListener('message', listener)\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait worker.on('message', listener)\n\t\t}),\n\t\ttimeout(timeoutMs).then(() => {\n\t\t\tif (!ok) {\n\t\t\t\tthrow new Error('Worker start timed out')\n\t\t\t}\n\t\t\treturn true\n\t\t}),\n\t])\n}\n\nexport const notifyWorkerStarted = () =>\n\tprocess.send?.({\n\t\ttype: MSG_WORKER_STARTED,\n\t})\n\nexport class WorkerManager {\n\tprivate isTerminating = false\n\n\tprivate workers: Set<Worker> = new Set()\n\n\tpublic async start({ workerCount, env }: { workerCount: number; env?: any }): Promise<void> {\n\t\tif (this.isTerminating) {\n\t\t\tthrow new Error(`Worker manager is terminating`)\n\t\t}\n\t\tfor (let i = 0; i < workerCount; i++) {\n\t\t\tawait this.startWorker(env)\n\t\t\tif (this.isTerminating) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async startWorker(env?: any) {\n\t\tconst worker = cluster.fork(env)\n\t\tworker.on('exit', async (code, signal) => {\n\t\t\tthis.workers.delete(worker)\n\t\t\tif (!this.isTerminating) {\n\t\t\t\tconsole.log(`Worker ${worker.process.pid} died with signal ${signal}, restarting`)\n\t\t\t\tawait timeout(2000)\n\t\t\t\tawait this.startWorker(env)\n\t\t\t}\n\t\t})\n\t\tthis.workers.add(worker)\n\t\tawait waitForWorker(worker, 15000)\n\t}\n\n\tpublic async terminate(signal: NodeJS.Signals): Promise<void> {\n\t\tif (this.isTerminating) {\n\t\t\tthrow new Error(`Worker manager is terminating`)\n\t\t}\n\t\tthis.isTerminating = true\n\t\tawait Promise.allSettled(\n\t\t\tArray.from(this.workers).map(async it => {\n\t\t\t\tif (!it) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconsole.log(`Terminating worker ${it.process.pid}`)\n\t\t\t\tconst disconnectPromise = new Promise(resolve => it.once('disconnect', resolve))\n\t\t\t\tit.disconnect()\n\t\t\t\tawait disconnectPromise\n\t\t\t\tconst killPromise = new Promise(resolve => it.once('exit', resolve))\n\t\t\t\tit.kill(signal)\n\t\t\t\tawait killPromise\n\t\t\t\tconsole.log(`Worker ${it.process.pid} terminated`)\n\t\t\t}),\n\t\t)\n\t}\n}\n"],"names":["timeout"],"mappings":";;;;;;;AAGO,MAAM,wBAAwB,CAAC,kBACrC,CAAC,gBAAgB,eAAe,QAAQ,WAAW,kBAAkB;AAOtE,MAAM,qBAAqB;AAEpB,MAAM,gBAAgB,CAAC,QAAgB,cAAsB;AACnE,MAAI,KAAK;AACT,SAAO,QAAQ,KAAK;AAAA,IACnB,IAAI,QAAQ,OAAM,YAAW;AAC5B,YAAM,WAAW,CAAC,YAAiB;AAClC,YAAI,UAAU,WAAW,QAAQ,SAAS,oBAAoB;AAC7D,eAAK;AACL,kBAAQ,IAAI;AACZ,iBAAO,eAAe,WAAW,QAAQ;AAAA,QAC1C;AAAA,MACD;AACA,YAAM,OAAO,GAAG,WAAW,QAAQ;AAAA,IACpC,CAAC;AAAA,IACDA,cAAQ,SAAS,EAAE,KAAK,MAAM;AAC7B,UAAI,CAAC,IAAI;AACR,cAAM,IAAI,MAAM,wBAAwB;AAAA,MACzC;AACA,aAAO;AAAA,IACR,CAAC;AAAA,EAAA,CACD;AACF;AAEO,MAAM,sBAAsB,MAClC,QAAQ,OAAO;AAAA,EACd,MAAM;AACP,CAAC;AAEK,MAAM,cAAc;AAAA,EAApB,cAAA;AACN,kBAAA,MAAQ,iBAAgB,KAAA;AAExB,kBAAA,MAAQ,+BAA2B,IAAA,CAAI;AAAA,EAAA;AAAA,EAEvC,MAAa,MAAM,EAAE,aAAa,OAA0D;AAC3F,QAAI,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,+BAA+B;AAAA,IAChD;AACA,aAAS,IAAI,GAAG,IAAI,aAAa,KAAK;AACrC,YAAM,KAAK,YAAY,GAAG;AAC1B,UAAI,KAAK,eAAe;AACvB;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAc,YAAY,KAAW;AACpC,UAAM,SAAS,QAAQ,KAAK,GAAG;AAC/B,WAAO,GAAG,QAAQ,OAAO,MAAM,WAAW;AACzC,WAAK,QAAQ,OAAO,MAAM;AAC1B,UAAI,CAAC,KAAK,eAAe;AACxB,gBAAQ,IAAI,UAAU,OAAO,QAAQ,GAAG,qBAAqB,MAAM,cAAc;AACjF,cAAMA,MAAAA,QAAQ,GAAI;AAClB,cAAM,KAAK,YAAY,GAAG;AAAA,MAC3B;AAAA,IACD,CAAC;AACD,SAAK,QAAQ,IAAI,MAAM;AACvB,UAAM,cAAc,QAAQ,IAAK;AAAA,EAClC;AAAA,EAEA,MAAa,UAAU,QAAuC;AAC7D,QAAI,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,+BAA+B;AAAA,IAChD;AACA,SAAK,gBAAgB;AACrB,UAAM,QAAQ;AAAA,MACb,MAAM,KAAK,KAAK,OAAO,EAAE,IAAI,OAAM,OAAM;AACxC,YAAI,CAAC,IAAI;AACR;AAAA,QACD;AACA,gBAAQ,IAAI,sBAAsB,GAAG,QAAQ,GAAG,EAAE;AAClD,cAAM,oBAAoB,IAAI,QAAQ,CAAA,YAAW,GAAG,KAAK,cAAc,OAAO,CAAC;AAC/E,WAAG,WAAA;AACH,cAAM;AACN,cAAM,cAAc,IAAI,QAAQ,CAAA,YAAW,GAAG,KAAK,QAAQ,OAAO,CAAC;AACnE,WAAG,KAAK,MAAM;AACd,cAAM;AACN,gBAAQ,IAAI,UAAU,GAAG,QAAQ,GAAG,aAAa;AAAA,MAClD,CAAC;AAAA,IAAA;AAAA,EAEH;AACD;;;;;"}
@@ -63,19 +63,21 @@ class WorkerManager {
63
63
  throw new Error(`Worker manager is terminating`);
64
64
  }
65
65
  this.isTerminating = true;
66
- await Promise.allSettled(Array.from(this.workers).map(async (it) => {
67
- if (!it) {
68
- return;
69
- }
70
- console.log(`Terminating worker ${it.process.pid}`);
71
- const disconnectPromise = new Promise((resolve) => it.once("disconnect", resolve));
72
- it.disconnect();
73
- await disconnectPromise;
74
- const killPromise = new Promise((resolve) => it.once("exit", resolve));
75
- it.kill(signal);
76
- await killPromise;
77
- console.log(`Worker ${it.process.pid} terminated`);
78
- }));
66
+ await Promise.allSettled(
67
+ Array.from(this.workers).map(async (it) => {
68
+ if (!it) {
69
+ return;
70
+ }
71
+ console.log(`Terminating worker ${it.process.pid}`);
72
+ const disconnectPromise = new Promise((resolve) => it.once("disconnect", resolve));
73
+ it.disconnect();
74
+ await disconnectPromise;
75
+ const killPromise = new Promise((resolve) => it.once("exit", resolve));
76
+ it.kill(signal);
77
+ await killPromise;
78
+ console.log(`Worker ${it.process.pid} terminated`);
79
+ })
80
+ );
79
81
  }
80
82
  }
81
83
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"cluster.js","sources":["../../../../packages/engine-server/src/cluster.ts"],"sourcesContent":["import cluster, { Worker } from 'node:cluster'\nimport { timeout } from './utils'\n\nexport const getClusterProcessType = (isClusterMode: boolean): ProcessType =>\n\t!isClusterMode ? 'singleNode' : cluster.isMaster ? 'clusterMaster' : 'clusterWorker'\n\nexport type ProcessType =\n\t| 'singleNode'\n\t| 'clusterMaster'\n\t| 'clusterWorker'\n\nconst MSG_WORKER_STARTED = 'msg_worker_started'\n\nexport const waitForWorker = (worker: Worker, timeoutMs: number) => {\n\tlet ok = false\n\treturn Promise.race([\n\t\tnew Promise(async resolve => {\n\t\t\tconst listener = (message: any) => {\n\t\t\t\tif ('type' in message && message.type === MSG_WORKER_STARTED) {\n\t\t\t\t\tok = true\n\t\t\t\t\tresolve(null)\n\t\t\t\t\tworker.removeListener('message', listener)\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait worker.on('message', listener)\n\t\t}),\n\t\ttimeout(timeoutMs).then(() => {\n\t\t\tif (!ok) {\n\t\t\t\tthrow new Error('Worker start timed out')\n\t\t\t}\n\t\t\treturn true\n\t\t}),\n\t])\n}\n\nexport const notifyWorkerStarted = () =>\n\tprocess.send?.({\n\t\ttype: MSG_WORKER_STARTED,\n\t})\n\nexport class WorkerManager {\n\n\tprivate isTerminating = false\n\n\tprivate workers: Set<Worker> = new Set()\n\n\tpublic async start({ workerCount, env }: { workerCount: number; env?: any }): Promise<void> {\n\t\tif (this.isTerminating) {\n\t\t\tthrow new Error(`Worker manager is terminating`)\n\t\t}\n\t\tfor (let i = 0; i < workerCount; i++) {\n\t\t\tawait this.startWorker(env)\n\t\t\tif (this.isTerminating) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async startWorker(env?: any) {\n\t\tconst worker = cluster.fork(env)\n\t\tworker.on('exit', async (code, signal) => {\n\t\t\tthis.workers.delete(worker)\n\t\t\tif (!this.isTerminating) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.log(`Worker ${worker.process.pid} died with signal ${signal}, restarting`)\n\t\t\t\tawait timeout(2000)\n\t\t\t\tawait this.startWorker(env)\n\t\t\t}\n\t\t})\n\t\tthis.workers.add(worker)\n\t\tawait waitForWorker(worker, 15000)\n\t}\n\n\tpublic async terminate(signal: NodeJS.Signals): Promise<void> {\n\t\tif (this.isTerminating) {\n\t\t\tthrow new Error(`Worker manager is terminating`)\n\t\t}\n\t\tthis.isTerminating = true\n\t\tawait Promise.allSettled(Array.from(this.workers).map(async it => {\n\t\t\tif (!it) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.log(`Terminating worker ${it.process.pid}`)\n\t\t\tconst disconnectPromise = new Promise(resolve => it.once('disconnect', resolve))\n\t\t\tit.disconnect()\n\t\t\tawait disconnectPromise\n\t\t\tconst killPromise = new Promise(resolve => it.once('exit', resolve))\n\t\t\tit.kill(signal)\n\t\t\tawait killPromise\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.log(`Worker ${it.process.pid} terminated`)\n\t\t}))\n\t}\n}\n"],"names":[],"mappings":";;;;;AAGa,MAAA,wBAAwB,CAAC,kBACrC,CAAC,gBAAgB,eAAe,QAAQ,WAAW,kBAAkB;AAOtE,MAAM,qBAAqB;AAEd,MAAA,gBAAgB,CAAC,QAAgB,cAAsB;AACnE,MAAI,KAAK;AACT,SAAO,QAAQ,KAAK;AAAA,IACnB,IAAI,QAAQ,OAAM,YAAW;AACtB,YAAA,WAAW,CAAC,YAAiB;AAClC,YAAI,UAAU,WAAW,QAAQ,SAAS,oBAAoB;AACxD,eAAA;AACL,kBAAQ,IAAI;AACL,iBAAA,eAAe,WAAW,QAAQ;AAAA,QAAA;AAAA,MAE3C;AACM,YAAA,OAAO,GAAG,WAAW,QAAQ;AAAA,IAAA,CACnC;AAAA,IACD,QAAQ,SAAS,EAAE,KAAK,MAAM;AAC7B,UAAI,CAAC,IAAI;AACF,cAAA,IAAI,MAAM,wBAAwB;AAAA,MAAA;AAElC,aAAA;AAAA,IACP,CAAA;AAAA,EAAA,CACD;AACF;AAEa,MAAA,sBAAsB,MAClC,QAAQ,OAAO;AAAA,EACd,MAAM;AACP,CAAC;AAEK,MAAM,cAAc;AAAA,EAApB,cAAA;AAEN,kBAAA,MAAQ,iBAAgB,KAAA;AAEhB,kBAAA,MAAA,+BAA2B,IAAI,CAAA;AAAA,EAAA;AAAA,EAEvC,MAAa,MAAM,EAAE,aAAa,OAA0D;AAC3F,QAAI,KAAK,eAAe;AACjB,YAAA,IAAI,MAAM,+BAA+B;AAAA,IAAA;AAEhD,aAAS,IAAI,GAAG,IAAI,aAAa,KAAK;AAC/B,YAAA,KAAK,YAAY,GAAG;AAC1B,UAAI,KAAK,eAAe;AACvB;AAAA,MAAA;AAAA,IACD;AAAA,EACD;AAAA,EAGD,MAAc,YAAY,KAAW;AAC9B,UAAA,SAAS,QAAQ,KAAK,GAAG;AAC/B,WAAO,GAAG,QAAQ,OAAO,MAAM,WAAW;AACpC,WAAA,QAAQ,OAAO,MAAM;AACtB,UAAA,CAAC,KAAK,eAAe;AAExB,gBAAQ,IAAI,UAAU,OAAO,QAAQ,GAAG,qBAAqB,MAAM,cAAc;AACjF,cAAM,QAAQ,GAAI;AACZ,cAAA,KAAK,YAAY,GAAG;AAAA,MAAA;AAAA,IAC3B,CACA;AACI,SAAA,QAAQ,IAAI,MAAM;AACjB,UAAA,cAAc,QAAQ,IAAK;AAAA,EAAA;AAAA,EAGlC,MAAa,UAAU,QAAuC;AAC7D,QAAI,KAAK,eAAe;AACjB,YAAA,IAAI,MAAM,+BAA+B;AAAA,IAAA;AAEhD,SAAK,gBAAgB;AACf,UAAA,QAAQ,WAAW,MAAM,KAAK,KAAK,OAAO,EAAE,IAAI,OAAM,OAAM;AACjE,UAAI,CAAC,IAAI;AACR;AAAA,MAAA;AAGD,cAAQ,IAAI,sBAAsB,GAAG,QAAQ,GAAG,EAAE;AAC5C,YAAA,oBAAoB,IAAI,QAAQ,CAAA,YAAW,GAAG,KAAK,cAAc,OAAO,CAAC;AAC/E,SAAG,WAAW;AACR,YAAA;AACA,YAAA,cAAc,IAAI,QAAQ,CAAA,YAAW,GAAG,KAAK,QAAQ,OAAO,CAAC;AACnE,SAAG,KAAK,MAAM;AACR,YAAA;AAEN,cAAQ,IAAI,UAAU,GAAG,QAAQ,GAAG,aAAa;AAAA,IAAA,CACjD,CAAC;AAAA,EAAA;AAEJ;"}
1
+ {"version":3,"file":"cluster.js","sources":["../../../../packages/engine-server/src/cluster.ts"],"sourcesContent":["import cluster, { Worker } from 'node:cluster'\nimport { timeout } from './utils'\n\nexport const getClusterProcessType = (isClusterMode: boolean): ProcessType =>\n\t!isClusterMode ? 'singleNode' : cluster.isMaster ? 'clusterMaster' : 'clusterWorker'\n\nexport type ProcessType =\n\t| 'singleNode'\n\t| 'clusterMaster'\n\t| 'clusterWorker'\n\nconst MSG_WORKER_STARTED = 'msg_worker_started'\n\nexport const waitForWorker = (worker: Worker, timeoutMs: number) => {\n\tlet ok = false\n\treturn Promise.race([\n\t\tnew Promise(async resolve => {\n\t\t\tconst listener = (message: any) => {\n\t\t\t\tif ('type' in message && message.type === MSG_WORKER_STARTED) {\n\t\t\t\t\tok = true\n\t\t\t\t\tresolve(null)\n\t\t\t\t\tworker.removeListener('message', listener)\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait worker.on('message', listener)\n\t\t}),\n\t\ttimeout(timeoutMs).then(() => {\n\t\t\tif (!ok) {\n\t\t\t\tthrow new Error('Worker start timed out')\n\t\t\t}\n\t\t\treturn true\n\t\t}),\n\t])\n}\n\nexport const notifyWorkerStarted = () =>\n\tprocess.send?.({\n\t\ttype: MSG_WORKER_STARTED,\n\t})\n\nexport class WorkerManager {\n\tprivate isTerminating = false\n\n\tprivate workers: Set<Worker> = new Set()\n\n\tpublic async start({ workerCount, env }: { workerCount: number; env?: any }): Promise<void> {\n\t\tif (this.isTerminating) {\n\t\t\tthrow new Error(`Worker manager is terminating`)\n\t\t}\n\t\tfor (let i = 0; i < workerCount; i++) {\n\t\t\tawait this.startWorker(env)\n\t\t\tif (this.isTerminating) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async startWorker(env?: any) {\n\t\tconst worker = cluster.fork(env)\n\t\tworker.on('exit', async (code, signal) => {\n\t\t\tthis.workers.delete(worker)\n\t\t\tif (!this.isTerminating) {\n\t\t\t\tconsole.log(`Worker ${worker.process.pid} died with signal ${signal}, restarting`)\n\t\t\t\tawait timeout(2000)\n\t\t\t\tawait this.startWorker(env)\n\t\t\t}\n\t\t})\n\t\tthis.workers.add(worker)\n\t\tawait waitForWorker(worker, 15000)\n\t}\n\n\tpublic async terminate(signal: NodeJS.Signals): Promise<void> {\n\t\tif (this.isTerminating) {\n\t\t\tthrow new Error(`Worker manager is terminating`)\n\t\t}\n\t\tthis.isTerminating = true\n\t\tawait Promise.allSettled(\n\t\t\tArray.from(this.workers).map(async it => {\n\t\t\t\tif (!it) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconsole.log(`Terminating worker ${it.process.pid}`)\n\t\t\t\tconst disconnectPromise = new Promise(resolve => it.once('disconnect', resolve))\n\t\t\t\tit.disconnect()\n\t\t\t\tawait disconnectPromise\n\t\t\t\tconst killPromise = new Promise(resolve => it.once('exit', resolve))\n\t\t\t\tit.kill(signal)\n\t\t\t\tawait killPromise\n\t\t\t\tconsole.log(`Worker ${it.process.pid} terminated`)\n\t\t\t}),\n\t\t)\n\t}\n}\n"],"names":[],"mappings":";;;;;AAGO,MAAM,wBAAwB,CAAC,kBACrC,CAAC,gBAAgB,eAAe,QAAQ,WAAW,kBAAkB;AAOtE,MAAM,qBAAqB;AAEpB,MAAM,gBAAgB,CAAC,QAAgB,cAAsB;AACnE,MAAI,KAAK;AACT,SAAO,QAAQ,KAAK;AAAA,IACnB,IAAI,QAAQ,OAAM,YAAW;AAC5B,YAAM,WAAW,CAAC,YAAiB;AAClC,YAAI,UAAU,WAAW,QAAQ,SAAS,oBAAoB;AAC7D,eAAK;AACL,kBAAQ,IAAI;AACZ,iBAAO,eAAe,WAAW,QAAQ;AAAA,QAC1C;AAAA,MACD;AACA,YAAM,OAAO,GAAG,WAAW,QAAQ;AAAA,IACpC,CAAC;AAAA,IACD,QAAQ,SAAS,EAAE,KAAK,MAAM;AAC7B,UAAI,CAAC,IAAI;AACR,cAAM,IAAI,MAAM,wBAAwB;AAAA,MACzC;AACA,aAAO;AAAA,IACR,CAAC;AAAA,EAAA,CACD;AACF;AAEO,MAAM,sBAAsB,MAClC,QAAQ,OAAO;AAAA,EACd,MAAM;AACP,CAAC;AAEK,MAAM,cAAc;AAAA,EAApB,cAAA;AACN,kBAAA,MAAQ,iBAAgB,KAAA;AAExB,kBAAA,MAAQ,+BAA2B,IAAA,CAAI;AAAA,EAAA;AAAA,EAEvC,MAAa,MAAM,EAAE,aAAa,OAA0D;AAC3F,QAAI,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,+BAA+B;AAAA,IAChD;AACA,aAAS,IAAI,GAAG,IAAI,aAAa,KAAK;AACrC,YAAM,KAAK,YAAY,GAAG;AAC1B,UAAI,KAAK,eAAe;AACvB;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAc,YAAY,KAAW;AACpC,UAAM,SAAS,QAAQ,KAAK,GAAG;AAC/B,WAAO,GAAG,QAAQ,OAAO,MAAM,WAAW;AACzC,WAAK,QAAQ,OAAO,MAAM;AAC1B,UAAI,CAAC,KAAK,eAAe;AACxB,gBAAQ,IAAI,UAAU,OAAO,QAAQ,GAAG,qBAAqB,MAAM,cAAc;AACjF,cAAM,QAAQ,GAAI;AAClB,cAAM,KAAK,YAAY,GAAG;AAAA,MAC3B;AAAA,IACD,CAAC;AACD,SAAK,QAAQ,IAAI,MAAM;AACvB,UAAM,cAAc,QAAQ,IAAK;AAAA,EAClC;AAAA,EAEA,MAAa,UAAU,QAAuC;AAC7D,QAAI,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,+BAA+B;AAAA,IAChD;AACA,SAAK,gBAAgB;AACrB,UAAM,QAAQ;AAAA,MACb,MAAM,KAAK,KAAK,OAAO,EAAE,IAAI,OAAM,OAAM;AACxC,YAAI,CAAC,IAAI;AACR;AAAA,QACD;AACA,gBAAQ,IAAI,sBAAsB,GAAG,QAAQ,GAAG,EAAE;AAClD,cAAM,oBAAoB,IAAI,QAAQ,CAAA,YAAW,GAAG,KAAK,cAAc,OAAO,CAAC;AAC/E,WAAG,WAAA;AACH,cAAM;AACN,cAAM,cAAc,IAAI,QAAQ,CAAA,YAAW,GAAG,KAAK,QAAQ,OAAO,CAAC;AACnE,WAAG,KAAK,MAAM;AACd,cAAM;AACN,gBAAQ,IAAI,UAAU,GAAG,QAAQ,GAAG,aAAa;AAAA,MAClD,CAAC;AAAA,IAAA;AAAA,EAEH;AACD;"}
@@ -1 +1 @@
1
- {"version":3,"file":"loadPlugins.cjs","sources":["../../../../packages/engine-server/src/loadPlugins.ts"],"sourcesContent":["import ActionsPlugin from '@contember/engine-actions'\nimport { Plugin } from '@contember/engine-plugins'\nimport S3Plugin from '@contember/engine-s3-plugin'\nimport VimeoPlugin from '@contember/engine-vimeo-plugin'\n\nexport default function loadPlugins(): Promise<Plugin[]> {\n\treturn Promise.resolve([new S3Plugin(), new VimeoPlugin(), new ActionsPlugin()])\n}\n"],"names":[],"mappings":";;;;AAKA,SAAwB,cAAiC;AACxD,SAAO,QAAQ,QAAQ,CAAC,IAAI,SAAS,GAAG,IAAI,YAAe,GAAA,IAAI,cAAc,CAAC,CAAC;AAChF;;"}
1
+ {"version":3,"file":"loadPlugins.cjs","sources":["../../../../packages/engine-server/src/loadPlugins.ts"],"sourcesContent":["import ActionsPlugin from '@contember/engine-actions'\nimport { Plugin } from '@contember/engine-plugins'\nimport S3Plugin from '@contember/engine-s3-plugin'\nimport VimeoPlugin from '@contember/engine-vimeo-plugin'\n\nexport default function loadPlugins(): Promise<Plugin[]> {\n\treturn Promise.resolve([new S3Plugin(), new VimeoPlugin(), new ActionsPlugin()])\n}\n"],"names":[],"mappings":";;;;AAKA,SAAwB,cAAiC;AACxD,SAAO,QAAQ,QAAQ,CAAC,IAAI,SAAA,GAAY,IAAI,YAAA,GAAe,IAAI,cAAA,CAAe,CAAC;AAChF;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"loadPlugins.js","sources":["../../../../packages/engine-server/src/loadPlugins.ts"],"sourcesContent":["import ActionsPlugin from '@contember/engine-actions'\nimport { Plugin } from '@contember/engine-plugins'\nimport S3Plugin from '@contember/engine-s3-plugin'\nimport VimeoPlugin from '@contember/engine-vimeo-plugin'\n\nexport default function loadPlugins(): Promise<Plugin[]> {\n\treturn Promise.resolve([new S3Plugin(), new VimeoPlugin(), new ActionsPlugin()])\n}\n"],"names":[],"mappings":";;;AAKA,SAAwB,cAAiC;AACxD,SAAO,QAAQ,QAAQ,CAAC,IAAI,SAAS,GAAG,IAAI,YAAe,GAAA,IAAI,cAAc,CAAC,CAAC;AAChF;"}
1
+ {"version":3,"file":"loadPlugins.js","sources":["../../../../packages/engine-server/src/loadPlugins.ts"],"sourcesContent":["import ActionsPlugin from '@contember/engine-actions'\nimport { Plugin } from '@contember/engine-plugins'\nimport S3Plugin from '@contember/engine-s3-plugin'\nimport VimeoPlugin from '@contember/engine-vimeo-plugin'\n\nexport default function loadPlugins(): Promise<Plugin[]> {\n\treturn Promise.resolve([new S3Plugin(), new VimeoPlugin(), new ActionsPlugin()])\n}\n"],"names":[],"mappings":";;;AAKA,SAAwB,cAAiC;AACxD,SAAO,QAAQ,QAAQ,CAAC,IAAI,SAAA,GAAY,IAAI,YAAA,GAAe,IAAI,cAAA,CAAe,CAAC;AAChF;"}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.cjs","sources":["../../../../packages/engine-server/src/utils.ts"],"sourcesContent":["export const timeout = (ms: number) =>\n\tnew Promise(resolve => {\n\t\tsetTimeout(resolve, ms)\n\t})\n"],"names":[],"mappings":";;AAAO,MAAM,UAAU,CAAC,OACvB,IAAI,QAAQ,CAAW,YAAA;AACtB,aAAW,SAAS,EAAE;AACvB,CAAC;;"}
1
+ {"version":3,"file":"utils.cjs","sources":["../../../../packages/engine-server/src/utils.ts"],"sourcesContent":["export const timeout = (ms: number) =>\n\tnew Promise(resolve => {\n\t\tsetTimeout(resolve, ms)\n\t})\n"],"names":[],"mappings":";;AAAO,MAAM,UAAU,CAAC,OACvB,IAAI,QAAQ,CAAA,YAAW;AACtB,aAAW,SAAS,EAAE;AACvB,CAAC;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../../../../packages/engine-server/src/utils.ts"],"sourcesContent":["export const timeout = (ms: number) =>\n\tnew Promise(resolve => {\n\t\tsetTimeout(resolve, ms)\n\t})\n"],"names":[],"mappings":"AAAO,MAAM,UAAU,CAAC,OACvB,IAAI,QAAQ,CAAW,YAAA;AACtB,aAAW,SAAS,EAAE;AACvB,CAAC;"}
1
+ {"version":3,"file":"utils.js","sources":["../../../../packages/engine-server/src/utils.ts"],"sourcesContent":["export const timeout = (ms: number) =>\n\tnew Promise(resolve => {\n\t\tsetTimeout(resolve, ms)\n\t})\n"],"names":[],"mappings":"AAAO,MAAM,UAAU,CAAC,OACvB,IAAI,QAAQ,CAAA,YAAW;AACtB,aAAW,SAAS,EAAE;AACvB,CAAC;"}
@@ -1 +1 @@
1
- {"version":3,"file":"start.cjs","sources":["../../../packages/engine-server/src/start.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport {\n\tcreateContainer,\n\tcreateDefaultLogger,\n\tcreateSentryLoggerHandler,\n\tgetServerVersion,\n\tisDebugMode,\n\tlistenOnProcessTermination,\n\tprintStartInfo,\n\tresolveServerConfig,\n\tserverConfigSchema,\n\tTerminationJob,\n} from '@contember/engine-http'\nimport loadPlugins from './loadPlugins'\nimport cluster from 'node:cluster'\nimport * as os from 'node:os'\nimport { timeout } from './utils'\nimport { getClusterProcessType, notifyWorkerStarted, WorkerManager } from './cluster'\n\nconst logger = createDefaultLogger()\nprocess.on('warning', message => {\n\tlogger.warn(message)\n})\n;(async () => {\n\tconst isDebug = isDebugMode()\n\n\tconst version = await getServerVersion()\n\tprintStartInfo({ version, isDebug }, logger)\n\tconst plugins = await loadPlugins()\n\tconst { serverConfig, projectConfigResolver, tenantConfigResolver } = await resolveServerConfig({ plugins, serverConfigSchema })\n\n\tif (process.argv[2] === 'validate') {\n\t\tprocess.exit(0)\n\t}\n\n\tconst sentryhandler = createSentryLoggerHandler(serverConfig.logging?.sentry?.dsn)\n\tif (sentryhandler !== null) {\n\t\tlogger.addHandler(sentryhandler)\n\t}\n\n\tconst workerConfig = serverConfig.workerCount || 1\n\n\tconst workerCount = workerConfig === 'auto' ? os.cpus().length : Number(workerConfig)\n\tconst isClusterMode = serverConfig.workerCount !== undefined\n\n\tconst processType = getClusterProcessType(isClusterMode)\n\n\tconst container = createContainer({\n\t\tdebugMode: isDebug,\n\t\tserverConfig,\n\t\tprojectConfigResolver,\n\t\ttenantConfigResolver,\n\t\tplugins,\n\t\tprocessType,\n\t\tversion,\n\t\tlogger,\n\t})\n\n\tlet initializedProjects: string[] = []\n\tconst terminationJobs: TerminationJob[] = []\n\tlistenOnProcessTermination(terminationJobs, logger)\n\n\tif (cluster.isMaster) {\n\t\tconst monitoringPort = serverConfig.monitoringPort\n\t\tconst monitoringServer = container.monitoringKoa.listen(monitoringPort, () => {\n\t\t\tlogger.info(`Monitoring running on http://localhost:${monitoringPort}`)\n\t\t})\n\t\tterminationJobs.push(async () => {\n\t\t\tawait new Promise<any>(resolve => monitoringServer.close(resolve))\n\t\t\tlogger.info('Monitoring server terminated')\n\t\t})\n\t\tif (!serverConfig.projectGroup) {\n\t\t\tinitializedProjects = await container.initializer.initialize()\n\t\t}\n\t}\n\n\tconst port = serverConfig.port\n\tconst printStarted = () => {\n\t\tif (serverConfig.projectGroup) {\n\t\t\tlogger.info('Contember Cloud running')\n\t\t} else {\n\t\t\tlogger.info(`Contember API running on http://localhost:${port}`)\n\t\t}\n\t\tif (initializedProjects.length) {\n\t\t\tlogger.info(`Initialized projects: ${initializedProjects.join(', ')}`)\n\t\t}\n\t}\n\n\tconst startApplication = async () => {\n\t\tconst httpServerPromise = container.application.listen()\n\t\tterminationJobs.push(async () => {\n\t\t\tawait (await httpServerPromise).close()\n\t\t\tlogger.info('API server terminated')\n\t\t})\n\t\tawait httpServerPromise\n\t}\n\n\tconst startWorker = async (workerName: string) => {\n\t\tconst worker = container.applicationWorkers.getWorker(workerName)\n\t\tconst runningWorker = worker.run({\n\t\t\tlogger,\n\t\t\tonError: e => {\n\t\t\t\tlogger.crit(e)\n\t\t\t\tprocess.exit(1)\n\t\t\t},\n\t\t})\n\t\tterminationJobs.push(async () => {\n\t\t\t(await runningWorker).end()\n\t\t})\n\t\tawait runningWorker\n\t\tlogger.info(`Contember Worker ${workerName} started.`)\n\n\t}\n\n\tconst applicationWorker = serverConfig.applicationWorker\n\tif (applicationWorker && applicationWorker !== 'all') {\n\t\tawait startWorker(applicationWorker)\n\t\tif (isClusterMode) {\n\t\t\tnotifyWorkerStarted()\n\t\t}\n\t} else if (isClusterMode) {\n\t\tif (cluster.isMaster) {\n\t\t\tlogger.info(`Master ${process.pid} is running`)\n\t\t\tconst workerManager = new WorkerManager()\n\t\t\tterminationJobs.push(async ({ signal }) => {\n\t\t\t\tawait workerManager.terminate(signal)\n\t\t\t\tlogger.info('Workers terminated')\n\t\t\t})\n\n\t\t\tawait workerManager.start({ workerCount })\n\n\t\t\tif (applicationWorker === 'all') {\n\t\t\t\tfor (const workerName of container.applicationWorkers.getWorkerNames()) {\n\t\t\t\t\tawait workerManager.start({\n\t\t\t\t\t\tworkerCount, env: {\n\t\t\t\t\t\t\tCONTEMBER_APPLICATION_WORKER: workerName,\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t\tprintStarted()\n\t\t} else {\n\t\t\tlogger.info(`Starting worker ${process.pid}`)\n\n\t\t\t// this line somehow ensures, that worker waits for termination of all jobs\n\t\t\tprocess.on('disconnect', () => timeout(0))\n\n\t\t\tawait startApplication()\n\t\t\tnotifyWorkerStarted()\n\t\t}\n\t} else {\n\t\tawait startApplication()\n\t\tif (applicationWorker === 'all') {\n\t\t\tfor (const workerName of container.applicationWorkers.getWorkerNames()) {\n\t\t\t\tawait startWorker(workerName)\n\t\t\t}\n\t\t}\n\t\tprintStarted()\n\t}\n\n})().catch(e => {\n\tlogger.crit(e)\n\tprocess.exit(1)\n})\n"],"names":["createDefaultLogger","isDebugMode","getServerVersion","printStartInfo","resolveServerConfig","serverConfigSchema","createSentryLoggerHandler","os","getClusterProcessType","createContainer","listenOnProcessTermination","cluster","notifyWorkerStarted","WorkerManager","timeout"],"mappings":"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"}
1
+ {"version":3,"file":"start.cjs","sources":["../../../packages/engine-server/src/start.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport {\n\tcreateContainer,\n\tcreateDefaultLogger,\n\tcreateSentryLoggerHandler,\n\tgetServerVersion,\n\tisDebugMode,\n\tlistenOnProcessTermination,\n\tprintStartInfo,\n\tresolveServerConfig,\n\tserverConfigSchema,\n\tTerminationJob,\n} from '@contember/engine-http'\nimport loadPlugins from './loadPlugins'\nimport cluster from 'node:cluster'\nimport * as os from 'node:os'\nimport { timeout } from './utils'\nimport { getClusterProcessType, notifyWorkerStarted, WorkerManager } from './cluster'\n\nconst logger = createDefaultLogger()\nprocess.on('warning', message => {\n\tlogger.warn(message)\n})\n;(async () => {\n\tconst isDebug = isDebugMode()\n\n\tconst version = await getServerVersion()\n\tprintStartInfo({ version, isDebug }, logger)\n\tconst plugins = await loadPlugins()\n\tconst { serverConfig, projectConfigResolver, tenantConfigResolver } = await resolveServerConfig({ plugins, serverConfigSchema })\n\n\tif (process.argv[2] === 'validate') {\n\t\tprocess.exit(0)\n\t}\n\n\tconst sentryhandler = createSentryLoggerHandler(serverConfig.logging?.sentry?.dsn)\n\tif (sentryhandler !== null) {\n\t\tlogger.addHandler(sentryhandler)\n\t}\n\n\tconst workerConfig = serverConfig.workerCount || 1\n\n\tconst workerCount = workerConfig === 'auto' ? os.cpus().length : Number(workerConfig)\n\tconst isClusterMode = serverConfig.workerCount !== undefined\n\n\tconst processType = getClusterProcessType(isClusterMode)\n\n\tconst container = createContainer({\n\t\tdebugMode: isDebug,\n\t\tserverConfig,\n\t\tprojectConfigResolver,\n\t\ttenantConfigResolver,\n\t\tplugins,\n\t\tprocessType,\n\t\tversion,\n\t\tlogger,\n\t})\n\n\tlet initializedProjects: string[] = []\n\tconst terminationJobs: TerminationJob[] = []\n\tlistenOnProcessTermination(terminationJobs, logger)\n\n\tif (cluster.isMaster) {\n\t\tconst monitoringPort = serverConfig.monitoringPort\n\t\tconst monitoringServer = container.monitoringKoa.listen(monitoringPort, () => {\n\t\t\tlogger.info(`Monitoring running on http://localhost:${monitoringPort}`)\n\t\t})\n\t\tterminationJobs.push(async () => {\n\t\t\tawait new Promise<any>(resolve => monitoringServer.close(resolve))\n\t\t\tlogger.info('Monitoring server terminated')\n\t\t})\n\t\tif (!serverConfig.projectGroup) {\n\t\t\tinitializedProjects = await container.initializer.initialize()\n\t\t}\n\t}\n\n\tconst port = serverConfig.port\n\tconst printStarted = () => {\n\t\tif (serverConfig.projectGroup) {\n\t\t\tlogger.info('Contember Cloud running')\n\t\t} else {\n\t\t\tlogger.info(`Contember API running on http://localhost:${port}`)\n\t\t}\n\t\tif (initializedProjects.length) {\n\t\t\tlogger.info(`Initialized projects: ${initializedProjects.join(', ')}`)\n\t\t}\n\t}\n\n\tconst startApplication = async () => {\n\t\tconst httpServerPromise = container.application.listen()\n\t\tterminationJobs.push(async () => {\n\t\t\tawait (await httpServerPromise).close()\n\t\t\tlogger.info('API server terminated')\n\t\t})\n\t\tawait httpServerPromise\n\t}\n\n\tconst startWorker = async (workerName: string) => {\n\t\tconst worker = container.applicationWorkers.getWorker(workerName)\n\t\tconst runningWorker = worker.run({\n\t\t\tlogger,\n\t\t\tonError: e => {\n\t\t\t\tlogger.crit(e)\n\t\t\t\tprocess.exit(1)\n\t\t\t},\n\t\t})\n\t\tterminationJobs.push(async () => {\n\t\t\t;(await runningWorker).end()\n\t\t})\n\t\tawait runningWorker\n\t\tlogger.info(`Contember Worker ${workerName} started.`)\n\t}\n\n\tconst applicationWorker = serverConfig.applicationWorker\n\tif (applicationWorker && applicationWorker !== 'all') {\n\t\tawait startWorker(applicationWorker)\n\t\tif (isClusterMode) {\n\t\t\tnotifyWorkerStarted()\n\t\t}\n\t} else if (isClusterMode) {\n\t\tif (cluster.isMaster) {\n\t\t\tlogger.info(`Master ${process.pid} is running`)\n\t\t\tconst workerManager = new WorkerManager()\n\t\t\tterminationJobs.push(async ({ signal }) => {\n\t\t\t\tawait workerManager.terminate(signal)\n\t\t\t\tlogger.info('Workers terminated')\n\t\t\t})\n\n\t\t\tawait workerManager.start({ workerCount })\n\n\t\t\tif (applicationWorker === 'all') {\n\t\t\t\tfor (const workerName of container.applicationWorkers.getWorkerNames()) {\n\t\t\t\t\tawait workerManager.start({\n\t\t\t\t\t\tworkerCount,\n\t\t\t\t\t\tenv: {\n\t\t\t\t\t\t\tCONTEMBER_APPLICATION_WORKER: workerName,\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t\tprintStarted()\n\t\t} else {\n\t\t\tlogger.info(`Starting worker ${process.pid}`)\n\n\t\t\t// this line somehow ensures, that worker waits for termination of all jobs\n\t\t\tprocess.on('disconnect', () => timeout(0))\n\n\t\t\tawait startApplication()\n\t\t\tnotifyWorkerStarted()\n\t\t}\n\t} else {\n\t\tawait startApplication()\n\t\tif (applicationWorker === 'all') {\n\t\t\tfor (const workerName of container.applicationWorkers.getWorkerNames()) {\n\t\t\t\tawait startWorker(workerName)\n\t\t\t}\n\t\t}\n\t\tprintStarted()\n\t}\n})().catch(e => {\n\tlogger.crit(e)\n\tprocess.exit(1)\n})\n"],"names":["createDefaultLogger","isDebugMode","getServerVersion","printStartInfo","resolveServerConfig","serverConfigSchema","createSentryLoggerHandler","os","getClusterProcessType","createContainer","listenOnProcessTermination","cluster","notifyWorkerStarted","WorkerManager","timeout"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"start.js","sources":["../../../packages/engine-server/src/start.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport {\n\tcreateContainer,\n\tcreateDefaultLogger,\n\tcreateSentryLoggerHandler,\n\tgetServerVersion,\n\tisDebugMode,\n\tlistenOnProcessTermination,\n\tprintStartInfo,\n\tresolveServerConfig,\n\tserverConfigSchema,\n\tTerminationJob,\n} from '@contember/engine-http'\nimport loadPlugins from './loadPlugins'\nimport cluster from 'node:cluster'\nimport * as os from 'node:os'\nimport { timeout } from './utils'\nimport { getClusterProcessType, notifyWorkerStarted, WorkerManager } from './cluster'\n\nconst logger = createDefaultLogger()\nprocess.on('warning', message => {\n\tlogger.warn(message)\n})\n;(async () => {\n\tconst isDebug = isDebugMode()\n\n\tconst version = await getServerVersion()\n\tprintStartInfo({ version, isDebug }, logger)\n\tconst plugins = await loadPlugins()\n\tconst { serverConfig, projectConfigResolver, tenantConfigResolver } = await resolveServerConfig({ plugins, serverConfigSchema })\n\n\tif (process.argv[2] === 'validate') {\n\t\tprocess.exit(0)\n\t}\n\n\tconst sentryhandler = createSentryLoggerHandler(serverConfig.logging?.sentry?.dsn)\n\tif (sentryhandler !== null) {\n\t\tlogger.addHandler(sentryhandler)\n\t}\n\n\tconst workerConfig = serverConfig.workerCount || 1\n\n\tconst workerCount = workerConfig === 'auto' ? os.cpus().length : Number(workerConfig)\n\tconst isClusterMode = serverConfig.workerCount !== undefined\n\n\tconst processType = getClusterProcessType(isClusterMode)\n\n\tconst container = createContainer({\n\t\tdebugMode: isDebug,\n\t\tserverConfig,\n\t\tprojectConfigResolver,\n\t\ttenantConfigResolver,\n\t\tplugins,\n\t\tprocessType,\n\t\tversion,\n\t\tlogger,\n\t})\n\n\tlet initializedProjects: string[] = []\n\tconst terminationJobs: TerminationJob[] = []\n\tlistenOnProcessTermination(terminationJobs, logger)\n\n\tif (cluster.isMaster) {\n\t\tconst monitoringPort = serverConfig.monitoringPort\n\t\tconst monitoringServer = container.monitoringKoa.listen(monitoringPort, () => {\n\t\t\tlogger.info(`Monitoring running on http://localhost:${monitoringPort}`)\n\t\t})\n\t\tterminationJobs.push(async () => {\n\t\t\tawait new Promise<any>(resolve => monitoringServer.close(resolve))\n\t\t\tlogger.info('Monitoring server terminated')\n\t\t})\n\t\tif (!serverConfig.projectGroup) {\n\t\t\tinitializedProjects = await container.initializer.initialize()\n\t\t}\n\t}\n\n\tconst port = serverConfig.port\n\tconst printStarted = () => {\n\t\tif (serverConfig.projectGroup) {\n\t\t\tlogger.info('Contember Cloud running')\n\t\t} else {\n\t\t\tlogger.info(`Contember API running on http://localhost:${port}`)\n\t\t}\n\t\tif (initializedProjects.length) {\n\t\t\tlogger.info(`Initialized projects: ${initializedProjects.join(', ')}`)\n\t\t}\n\t}\n\n\tconst startApplication = async () => {\n\t\tconst httpServerPromise = container.application.listen()\n\t\tterminationJobs.push(async () => {\n\t\t\tawait (await httpServerPromise).close()\n\t\t\tlogger.info('API server terminated')\n\t\t})\n\t\tawait httpServerPromise\n\t}\n\n\tconst startWorker = async (workerName: string) => {\n\t\tconst worker = container.applicationWorkers.getWorker(workerName)\n\t\tconst runningWorker = worker.run({\n\t\t\tlogger,\n\t\t\tonError: e => {\n\t\t\t\tlogger.crit(e)\n\t\t\t\tprocess.exit(1)\n\t\t\t},\n\t\t})\n\t\tterminationJobs.push(async () => {\n\t\t\t(await runningWorker).end()\n\t\t})\n\t\tawait runningWorker\n\t\tlogger.info(`Contember Worker ${workerName} started.`)\n\n\t}\n\n\tconst applicationWorker = serverConfig.applicationWorker\n\tif (applicationWorker && applicationWorker !== 'all') {\n\t\tawait startWorker(applicationWorker)\n\t\tif (isClusterMode) {\n\t\t\tnotifyWorkerStarted()\n\t\t}\n\t} else if (isClusterMode) {\n\t\tif (cluster.isMaster) {\n\t\t\tlogger.info(`Master ${process.pid} is running`)\n\t\t\tconst workerManager = new WorkerManager()\n\t\t\tterminationJobs.push(async ({ signal }) => {\n\t\t\t\tawait workerManager.terminate(signal)\n\t\t\t\tlogger.info('Workers terminated')\n\t\t\t})\n\n\t\t\tawait workerManager.start({ workerCount })\n\n\t\t\tif (applicationWorker === 'all') {\n\t\t\t\tfor (const workerName of container.applicationWorkers.getWorkerNames()) {\n\t\t\t\t\tawait workerManager.start({\n\t\t\t\t\t\tworkerCount, env: {\n\t\t\t\t\t\t\tCONTEMBER_APPLICATION_WORKER: workerName,\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t\tprintStarted()\n\t\t} else {\n\t\t\tlogger.info(`Starting worker ${process.pid}`)\n\n\t\t\t// this line somehow ensures, that worker waits for termination of all jobs\n\t\t\tprocess.on('disconnect', () => timeout(0))\n\n\t\t\tawait startApplication()\n\t\t\tnotifyWorkerStarted()\n\t\t}\n\t} else {\n\t\tawait startApplication()\n\t\tif (applicationWorker === 'all') {\n\t\t\tfor (const workerName of container.applicationWorkers.getWorkerNames()) {\n\t\t\t\tawait startWorker(workerName)\n\t\t\t}\n\t\t}\n\t\tprintStarted()\n\t}\n\n})().catch(e => {\n\tlogger.crit(e)\n\tprocess.exit(1)\n})\n"],"names":[],"mappings":";;;;;;;AAoBA,MAAM,SAAS,oBAAoB;AACnC,QAAQ,GAAG,WAAW,CAAW,YAAA;AAChC,SAAO,KAAK,OAAO;AACpB,CAAC;AAAA,CACC,YAAY;AACb,QAAM,UAAU,YAAY;AAEtB,QAAA,UAAU,MAAM,iBAAiB;AACvC,iBAAe,EAAE,SAAS,QAAQ,GAAG,MAAM;AACrC,QAAA,UAAU,MAAM,YAAY;AAC5B,QAAA,EAAE,cAAc,uBAAuB,qBAAqB,IAAI,MAAM,oBAAoB,EAAE,SAAS,oBAAoB;AAE/H,MAAI,QAAQ,KAAK,CAAC,MAAM,YAAY;AACnC,YAAQ,KAAK,CAAC;AAAA,EAAA;AAGf,QAAM,gBAAgB,0BAA0B,aAAa,SAAS,QAAQ,GAAG;AACjF,MAAI,kBAAkB,MAAM;AAC3B,WAAO,WAAW,aAAa;AAAA,EAAA;AAG1B,QAAA,eAAe,aAAa,eAAe;AAE3C,QAAA,cAAc,iBAAiB,SAAS,GAAG,OAAO,SAAS,OAAO,YAAY;AAC9E,QAAA,gBAAgB,aAAa,gBAAgB;AAE7C,QAAA,cAAc,sBAAsB,aAAa;AAEvD,QAAM,YAAY,gBAAgB;AAAA,IACjC,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,CACA;AAED,MAAI,sBAAgC,CAAC;AACrC,QAAM,kBAAoC,CAAC;AAC3C,6BAA2B,iBAAiB,MAAM;AAElD,MAAI,QAAQ,UAAU;AACrB,UAAM,iBAAiB,aAAa;AACpC,UAAM,mBAAmB,UAAU,cAAc,OAAO,gBAAgB,MAAM;AACtE,aAAA,KAAK,0CAA0C,cAAc,EAAE;AAAA,IAAA,CACtE;AACD,oBAAgB,KAAK,YAAY;AAChC,YAAM,IAAI,QAAa,CAAA,YAAW,iBAAiB,MAAM,OAAO,CAAC;AACjE,aAAO,KAAK,8BAA8B;AAAA,IAAA,CAC1C;AACG,QAAA,CAAC,aAAa,cAAc;AACT,4BAAA,MAAM,UAAU,YAAY,WAAW;AAAA,IAAA;AAAA,EAC9D;AAGD,QAAM,OAAO,aAAa;AAC1B,QAAM,eAAe,MAAM;AAC1B,QAAI,aAAa,cAAc;AAC9B,aAAO,KAAK,yBAAyB;AAAA,IAAA,OAC/B;AACC,aAAA,KAAK,6CAA6C,IAAI,EAAE;AAAA,IAAA;AAEhE,QAAI,oBAAoB,QAAQ;AAC/B,aAAO,KAAK,yBAAyB,oBAAoB,KAAK,IAAI,CAAC,EAAE;AAAA,IAAA;AAAA,EAEvE;AAEA,QAAM,mBAAmB,YAAY;AAC9B,UAAA,oBAAoB,UAAU,YAAY,OAAO;AACvD,oBAAgB,KAAK,YAAY;AACzB,aAAA,MAAM,mBAAmB,MAAM;AACtC,aAAO,KAAK,uBAAuB;AAAA,IAAA,CACnC;AACK,UAAA;AAAA,EACP;AAEM,QAAA,cAAc,OAAO,eAAuB;AACjD,UAAM,SAAS,UAAU,mBAAmB,UAAU,UAAU;AAC1D,UAAA,gBAAgB,OAAO,IAAI;AAAA,MAChC;AAAA,MACA,SAAS,CAAK,MAAA;AACb,eAAO,KAAK,CAAC;AACb,gBAAQ,KAAK,CAAC;AAAA,MAAA;AAAA,IACf,CACA;AACD,oBAAgB,KAAK,YAAY;AAC/B,OAAA,MAAM,eAAe,IAAI;AAAA,IAAA,CAC1B;AACK,UAAA;AACC,WAAA,KAAK,oBAAoB,UAAU,WAAW;AAAA,EAEtD;AAEA,QAAM,oBAAoB,aAAa;AACnC,MAAA,qBAAqB,sBAAsB,OAAO;AACrD,UAAM,YAAY,iBAAiB;AACnC,QAAI,eAAe;AACE,0BAAA;AAAA,IAAA;AAAA,aAEX,eAAe;AACzB,QAAI,QAAQ,UAAU;AACrB,aAAO,KAAK,UAAU,QAAQ,GAAG,aAAa;AACxC,YAAA,gBAAgB,IAAI,cAAc;AACxC,sBAAgB,KAAK,OAAO,EAAE,aAAa;AACpC,cAAA,cAAc,UAAU,MAAM;AACpC,eAAO,KAAK,oBAAoB;AAAA,MAAA,CAChC;AAED,YAAM,cAAc,MAAM,EAAE,aAAa;AAEzC,UAAI,sBAAsB,OAAO;AAChC,mBAAW,cAAc,UAAU,mBAAmB,eAAA,GAAkB;AACvE,gBAAM,cAAc,MAAM;AAAA,YACzB;AAAA,YAAa,KAAK;AAAA,cACjB,8BAA8B;AAAA,YAAA;AAAA,UAC/B,CACA;AAAA,QAAA;AAAA,MACF;AAEY,mBAAA;AAAA,IAAA,OACP;AACN,aAAO,KAAK,mBAAmB,QAAQ,GAAG,EAAE;AAG5C,cAAQ,GAAG,cAAc,MAAM,QAAQ,CAAC,CAAC;AAEzC,YAAM,iBAAiB;AACH,0BAAA;AAAA,IAAA;AAAA,EACrB,OACM;AACN,UAAM,iBAAiB;AACvB,QAAI,sBAAsB,OAAO;AAChC,iBAAW,cAAc,UAAU,mBAAmB,eAAA,GAAkB;AACvE,cAAM,YAAY,UAAU;AAAA,MAAA;AAAA,IAC7B;AAEY,iBAAA;AAAA,EAAA;AAGf,KAAK,MAAM,CAAK,MAAA;AACf,SAAO,KAAK,CAAC;AACb,UAAQ,KAAK,CAAC;AACf,CAAC;"}
1
+ {"version":3,"file":"start.js","sources":["../../../packages/engine-server/src/start.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport {\n\tcreateContainer,\n\tcreateDefaultLogger,\n\tcreateSentryLoggerHandler,\n\tgetServerVersion,\n\tisDebugMode,\n\tlistenOnProcessTermination,\n\tprintStartInfo,\n\tresolveServerConfig,\n\tserverConfigSchema,\n\tTerminationJob,\n} from '@contember/engine-http'\nimport loadPlugins from './loadPlugins'\nimport cluster from 'node:cluster'\nimport * as os from 'node:os'\nimport { timeout } from './utils'\nimport { getClusterProcessType, notifyWorkerStarted, WorkerManager } from './cluster'\n\nconst logger = createDefaultLogger()\nprocess.on('warning', message => {\n\tlogger.warn(message)\n})\n;(async () => {\n\tconst isDebug = isDebugMode()\n\n\tconst version = await getServerVersion()\n\tprintStartInfo({ version, isDebug }, logger)\n\tconst plugins = await loadPlugins()\n\tconst { serverConfig, projectConfigResolver, tenantConfigResolver } = await resolveServerConfig({ plugins, serverConfigSchema })\n\n\tif (process.argv[2] === 'validate') {\n\t\tprocess.exit(0)\n\t}\n\n\tconst sentryhandler = createSentryLoggerHandler(serverConfig.logging?.sentry?.dsn)\n\tif (sentryhandler !== null) {\n\t\tlogger.addHandler(sentryhandler)\n\t}\n\n\tconst workerConfig = serverConfig.workerCount || 1\n\n\tconst workerCount = workerConfig === 'auto' ? os.cpus().length : Number(workerConfig)\n\tconst isClusterMode = serverConfig.workerCount !== undefined\n\n\tconst processType = getClusterProcessType(isClusterMode)\n\n\tconst container = createContainer({\n\t\tdebugMode: isDebug,\n\t\tserverConfig,\n\t\tprojectConfigResolver,\n\t\ttenantConfigResolver,\n\t\tplugins,\n\t\tprocessType,\n\t\tversion,\n\t\tlogger,\n\t})\n\n\tlet initializedProjects: string[] = []\n\tconst terminationJobs: TerminationJob[] = []\n\tlistenOnProcessTermination(terminationJobs, logger)\n\n\tif (cluster.isMaster) {\n\t\tconst monitoringPort = serverConfig.monitoringPort\n\t\tconst monitoringServer = container.monitoringKoa.listen(monitoringPort, () => {\n\t\t\tlogger.info(`Monitoring running on http://localhost:${monitoringPort}`)\n\t\t})\n\t\tterminationJobs.push(async () => {\n\t\t\tawait new Promise<any>(resolve => monitoringServer.close(resolve))\n\t\t\tlogger.info('Monitoring server terminated')\n\t\t})\n\t\tif (!serverConfig.projectGroup) {\n\t\t\tinitializedProjects = await container.initializer.initialize()\n\t\t}\n\t}\n\n\tconst port = serverConfig.port\n\tconst printStarted = () => {\n\t\tif (serverConfig.projectGroup) {\n\t\t\tlogger.info('Contember Cloud running')\n\t\t} else {\n\t\t\tlogger.info(`Contember API running on http://localhost:${port}`)\n\t\t}\n\t\tif (initializedProjects.length) {\n\t\t\tlogger.info(`Initialized projects: ${initializedProjects.join(', ')}`)\n\t\t}\n\t}\n\n\tconst startApplication = async () => {\n\t\tconst httpServerPromise = container.application.listen()\n\t\tterminationJobs.push(async () => {\n\t\t\tawait (await httpServerPromise).close()\n\t\t\tlogger.info('API server terminated')\n\t\t})\n\t\tawait httpServerPromise\n\t}\n\n\tconst startWorker = async (workerName: string) => {\n\t\tconst worker = container.applicationWorkers.getWorker(workerName)\n\t\tconst runningWorker = worker.run({\n\t\t\tlogger,\n\t\t\tonError: e => {\n\t\t\t\tlogger.crit(e)\n\t\t\t\tprocess.exit(1)\n\t\t\t},\n\t\t})\n\t\tterminationJobs.push(async () => {\n\t\t\t;(await runningWorker).end()\n\t\t})\n\t\tawait runningWorker\n\t\tlogger.info(`Contember Worker ${workerName} started.`)\n\t}\n\n\tconst applicationWorker = serverConfig.applicationWorker\n\tif (applicationWorker && applicationWorker !== 'all') {\n\t\tawait startWorker(applicationWorker)\n\t\tif (isClusterMode) {\n\t\t\tnotifyWorkerStarted()\n\t\t}\n\t} else if (isClusterMode) {\n\t\tif (cluster.isMaster) {\n\t\t\tlogger.info(`Master ${process.pid} is running`)\n\t\t\tconst workerManager = new WorkerManager()\n\t\t\tterminationJobs.push(async ({ signal }) => {\n\t\t\t\tawait workerManager.terminate(signal)\n\t\t\t\tlogger.info('Workers terminated')\n\t\t\t})\n\n\t\t\tawait workerManager.start({ workerCount })\n\n\t\t\tif (applicationWorker === 'all') {\n\t\t\t\tfor (const workerName of container.applicationWorkers.getWorkerNames()) {\n\t\t\t\t\tawait workerManager.start({\n\t\t\t\t\t\tworkerCount,\n\t\t\t\t\t\tenv: {\n\t\t\t\t\t\t\tCONTEMBER_APPLICATION_WORKER: workerName,\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t\tprintStarted()\n\t\t} else {\n\t\t\tlogger.info(`Starting worker ${process.pid}`)\n\n\t\t\t// this line somehow ensures, that worker waits for termination of all jobs\n\t\t\tprocess.on('disconnect', () => timeout(0))\n\n\t\t\tawait startApplication()\n\t\t\tnotifyWorkerStarted()\n\t\t}\n\t} else {\n\t\tawait startApplication()\n\t\tif (applicationWorker === 'all') {\n\t\t\tfor (const workerName of container.applicationWorkers.getWorkerNames()) {\n\t\t\t\tawait startWorker(workerName)\n\t\t\t}\n\t\t}\n\t\tprintStarted()\n\t}\n})().catch(e => {\n\tlogger.crit(e)\n\tprocess.exit(1)\n})\n"],"names":[],"mappings":"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"}
@@ -65,19 +65,21 @@ class WorkerManager {
65
65
  throw new Error(`Worker manager is terminating`);
66
66
  }
67
67
  this.isTerminating = true;
68
- await Promise.allSettled(Array.from(this.workers).map(async (it) => {
69
- if (!it) {
70
- return;
71
- }
72
- console.log(`Terminating worker ${it.process.pid}`);
73
- const disconnectPromise = new Promise((resolve) => it.once("disconnect", resolve));
74
- it.disconnect();
75
- await disconnectPromise;
76
- const killPromise = new Promise((resolve) => it.once("exit", resolve));
77
- it.kill(signal);
78
- await killPromise;
79
- console.log(`Worker ${it.process.pid} terminated`);
80
- }));
68
+ await Promise.allSettled(
69
+ Array.from(this.workers).map(async (it) => {
70
+ if (!it) {
71
+ return;
72
+ }
73
+ console.log(`Terminating worker ${it.process.pid}`);
74
+ const disconnectPromise = new Promise((resolve) => it.once("disconnect", resolve));
75
+ it.disconnect();
76
+ await disconnectPromise;
77
+ const killPromise = new Promise((resolve) => it.once("exit", resolve));
78
+ it.kill(signal);
79
+ await killPromise;
80
+ console.log(`Worker ${it.process.pid} terminated`);
81
+ })
82
+ );
81
83
  }
82
84
  }
83
85
  exports.WorkerManager = WorkerManager;
@@ -1 +1 @@
1
- {"version":3,"file":"cluster.cjs","sources":["../../../../packages/engine-server/src/cluster.ts"],"sourcesContent":["import cluster, { Worker } from 'node:cluster'\nimport { timeout } from './utils'\n\nexport const getClusterProcessType = (isClusterMode: boolean): ProcessType =>\n\t!isClusterMode ? 'singleNode' : cluster.isMaster ? 'clusterMaster' : 'clusterWorker'\n\nexport type ProcessType =\n\t| 'singleNode'\n\t| 'clusterMaster'\n\t| 'clusterWorker'\n\nconst MSG_WORKER_STARTED = 'msg_worker_started'\n\nexport const waitForWorker = (worker: Worker, timeoutMs: number) => {\n\tlet ok = false\n\treturn Promise.race([\n\t\tnew Promise(async resolve => {\n\t\t\tconst listener = (message: any) => {\n\t\t\t\tif ('type' in message && message.type === MSG_WORKER_STARTED) {\n\t\t\t\t\tok = true\n\t\t\t\t\tresolve(null)\n\t\t\t\t\tworker.removeListener('message', listener)\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait worker.on('message', listener)\n\t\t}),\n\t\ttimeout(timeoutMs).then(() => {\n\t\t\tif (!ok) {\n\t\t\t\tthrow new Error('Worker start timed out')\n\t\t\t}\n\t\t\treturn true\n\t\t}),\n\t])\n}\n\nexport const notifyWorkerStarted = () =>\n\tprocess.send?.({\n\t\ttype: MSG_WORKER_STARTED,\n\t})\n\nexport class WorkerManager {\n\n\tprivate isTerminating = false\n\n\tprivate workers: Set<Worker> = new Set()\n\n\tpublic async start({ workerCount, env }: { workerCount: number; env?: any }): Promise<void> {\n\t\tif (this.isTerminating) {\n\t\t\tthrow new Error(`Worker manager is terminating`)\n\t\t}\n\t\tfor (let i = 0; i < workerCount; i++) {\n\t\t\tawait this.startWorker(env)\n\t\t\tif (this.isTerminating) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async startWorker(env?: any) {\n\t\tconst worker = cluster.fork(env)\n\t\tworker.on('exit', async (code, signal) => {\n\t\t\tthis.workers.delete(worker)\n\t\t\tif (!this.isTerminating) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.log(`Worker ${worker.process.pid} died with signal ${signal}, restarting`)\n\t\t\t\tawait timeout(2000)\n\t\t\t\tawait this.startWorker(env)\n\t\t\t}\n\t\t})\n\t\tthis.workers.add(worker)\n\t\tawait waitForWorker(worker, 15000)\n\t}\n\n\tpublic async terminate(signal: NodeJS.Signals): Promise<void> {\n\t\tif (this.isTerminating) {\n\t\t\tthrow new Error(`Worker manager is terminating`)\n\t\t}\n\t\tthis.isTerminating = true\n\t\tawait Promise.allSettled(Array.from(this.workers).map(async it => {\n\t\t\tif (!it) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.log(`Terminating worker ${it.process.pid}`)\n\t\t\tconst disconnectPromise = new Promise(resolve => it.once('disconnect', resolve))\n\t\t\tit.disconnect()\n\t\t\tawait disconnectPromise\n\t\t\tconst killPromise = new Promise(resolve => it.once('exit', resolve))\n\t\t\tit.kill(signal)\n\t\t\tawait killPromise\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.log(`Worker ${it.process.pid} terminated`)\n\t\t}))\n\t}\n}\n"],"names":["timeout"],"mappings":";;;;;;;AAGa,MAAA,wBAAwB,CAAC,kBACrC,CAAC,gBAAgB,eAAe,QAAQ,WAAW,kBAAkB;AAOtE,MAAM,qBAAqB;AAEd,MAAA,gBAAgB,CAAC,QAAgB,cAAsB;AACnE,MAAI,KAAK;AACT,SAAO,QAAQ,KAAK;AAAA,IACnB,IAAI,QAAQ,OAAM,YAAW;AACtB,YAAA,WAAW,CAAC,YAAiB;AAClC,YAAI,UAAU,WAAW,QAAQ,SAAS,oBAAoB;AACxD,eAAA;AACL,kBAAQ,IAAI;AACL,iBAAA,eAAe,WAAW,QAAQ;AAAA,QAAA;AAAA,MAE3C;AACM,YAAA,OAAO,GAAG,WAAW,QAAQ;AAAA,IAAA,CACnC;AAAA,IACDA,cAAQ,SAAS,EAAE,KAAK,MAAM;AAC7B,UAAI,CAAC,IAAI;AACF,cAAA,IAAI,MAAM,wBAAwB;AAAA,MAAA;AAElC,aAAA;AAAA,IACP,CAAA;AAAA,EAAA,CACD;AACF;AAEa,MAAA,sBAAsB,MAClC,QAAQ,OAAO;AAAA,EACd,MAAM;AACP,CAAC;AAEK,MAAM,cAAc;AAAA,EAApB,cAAA;AAEN,kBAAA,MAAQ,iBAAgB,KAAA;AAEhB,kBAAA,MAAA,+BAA2B,IAAI,CAAA;AAAA,EAAA;AAAA,EAEvC,MAAa,MAAM,EAAE,aAAa,OAA0D;AAC3F,QAAI,KAAK,eAAe;AACjB,YAAA,IAAI,MAAM,+BAA+B;AAAA,IAAA;AAEhD,aAAS,IAAI,GAAG,IAAI,aAAa,KAAK;AAC/B,YAAA,KAAK,YAAY,GAAG;AAC1B,UAAI,KAAK,eAAe;AACvB;AAAA,MAAA;AAAA,IACD;AAAA,EACD;AAAA,EAGD,MAAc,YAAY,KAAW;AAC9B,UAAA,SAAS,QAAQ,KAAK,GAAG;AAC/B,WAAO,GAAG,QAAQ,OAAO,MAAM,WAAW;AACpC,WAAA,QAAQ,OAAO,MAAM;AACtB,UAAA,CAAC,KAAK,eAAe;AAExB,gBAAQ,IAAI,UAAU,OAAO,QAAQ,GAAG,qBAAqB,MAAM,cAAc;AACjF,cAAMA,MAAAA,QAAQ,GAAI;AACZ,cAAA,KAAK,YAAY,GAAG;AAAA,MAAA;AAAA,IAC3B,CACA;AACI,SAAA,QAAQ,IAAI,MAAM;AACjB,UAAA,cAAc,QAAQ,IAAK;AAAA,EAAA;AAAA,EAGlC,MAAa,UAAU,QAAuC;AAC7D,QAAI,KAAK,eAAe;AACjB,YAAA,IAAI,MAAM,+BAA+B;AAAA,IAAA;AAEhD,SAAK,gBAAgB;AACf,UAAA,QAAQ,WAAW,MAAM,KAAK,KAAK,OAAO,EAAE,IAAI,OAAM,OAAM;AACjE,UAAI,CAAC,IAAI;AACR;AAAA,MAAA;AAGD,cAAQ,IAAI,sBAAsB,GAAG,QAAQ,GAAG,EAAE;AAC5C,YAAA,oBAAoB,IAAI,QAAQ,CAAA,YAAW,GAAG,KAAK,cAAc,OAAO,CAAC;AAC/E,SAAG,WAAW;AACR,YAAA;AACA,YAAA,cAAc,IAAI,QAAQ,CAAA,YAAW,GAAG,KAAK,QAAQ,OAAO,CAAC;AACnE,SAAG,KAAK,MAAM;AACR,YAAA;AAEN,cAAQ,IAAI,UAAU,GAAG,QAAQ,GAAG,aAAa;AAAA,IAAA,CACjD,CAAC;AAAA,EAAA;AAEJ;;;;;"}
1
+ {"version":3,"file":"cluster.cjs","sources":["../../../../packages/engine-server/src/cluster.ts"],"sourcesContent":["import cluster, { Worker } from 'node:cluster'\nimport { timeout } from './utils'\n\nexport const getClusterProcessType = (isClusterMode: boolean): ProcessType =>\n\t!isClusterMode ? 'singleNode' : cluster.isMaster ? 'clusterMaster' : 'clusterWorker'\n\nexport type ProcessType =\n\t| 'singleNode'\n\t| 'clusterMaster'\n\t| 'clusterWorker'\n\nconst MSG_WORKER_STARTED = 'msg_worker_started'\n\nexport const waitForWorker = (worker: Worker, timeoutMs: number) => {\n\tlet ok = false\n\treturn Promise.race([\n\t\tnew Promise(async resolve => {\n\t\t\tconst listener = (message: any) => {\n\t\t\t\tif ('type' in message && message.type === MSG_WORKER_STARTED) {\n\t\t\t\t\tok = true\n\t\t\t\t\tresolve(null)\n\t\t\t\t\tworker.removeListener('message', listener)\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait worker.on('message', listener)\n\t\t}),\n\t\ttimeout(timeoutMs).then(() => {\n\t\t\tif (!ok) {\n\t\t\t\tthrow new Error('Worker start timed out')\n\t\t\t}\n\t\t\treturn true\n\t\t}),\n\t])\n}\n\nexport const notifyWorkerStarted = () =>\n\tprocess.send?.({\n\t\ttype: MSG_WORKER_STARTED,\n\t})\n\nexport class WorkerManager {\n\tprivate isTerminating = false\n\n\tprivate workers: Set<Worker> = new Set()\n\n\tpublic async start({ workerCount, env }: { workerCount: number; env?: any }): Promise<void> {\n\t\tif (this.isTerminating) {\n\t\t\tthrow new Error(`Worker manager is terminating`)\n\t\t}\n\t\tfor (let i = 0; i < workerCount; i++) {\n\t\t\tawait this.startWorker(env)\n\t\t\tif (this.isTerminating) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async startWorker(env?: any) {\n\t\tconst worker = cluster.fork(env)\n\t\tworker.on('exit', async (code, signal) => {\n\t\t\tthis.workers.delete(worker)\n\t\t\tif (!this.isTerminating) {\n\t\t\t\tconsole.log(`Worker ${worker.process.pid} died with signal ${signal}, restarting`)\n\t\t\t\tawait timeout(2000)\n\t\t\t\tawait this.startWorker(env)\n\t\t\t}\n\t\t})\n\t\tthis.workers.add(worker)\n\t\tawait waitForWorker(worker, 15000)\n\t}\n\n\tpublic async terminate(signal: NodeJS.Signals): Promise<void> {\n\t\tif (this.isTerminating) {\n\t\t\tthrow new Error(`Worker manager is terminating`)\n\t\t}\n\t\tthis.isTerminating = true\n\t\tawait Promise.allSettled(\n\t\t\tArray.from(this.workers).map(async it => {\n\t\t\t\tif (!it) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconsole.log(`Terminating worker ${it.process.pid}`)\n\t\t\t\tconst disconnectPromise = new Promise(resolve => it.once('disconnect', resolve))\n\t\t\t\tit.disconnect()\n\t\t\t\tawait disconnectPromise\n\t\t\t\tconst killPromise = new Promise(resolve => it.once('exit', resolve))\n\t\t\t\tit.kill(signal)\n\t\t\t\tawait killPromise\n\t\t\t\tconsole.log(`Worker ${it.process.pid} terminated`)\n\t\t\t}),\n\t\t)\n\t}\n}\n"],"names":["timeout"],"mappings":";;;;;;;AAGO,MAAM,wBAAwB,CAAC,kBACrC,CAAC,gBAAgB,eAAe,QAAQ,WAAW,kBAAkB;AAOtE,MAAM,qBAAqB;AAEpB,MAAM,gBAAgB,CAAC,QAAgB,cAAsB;AACnE,MAAI,KAAK;AACT,SAAO,QAAQ,KAAK;AAAA,IACnB,IAAI,QAAQ,OAAM,YAAW;AAC5B,YAAM,WAAW,CAAC,YAAiB;AAClC,YAAI,UAAU,WAAW,QAAQ,SAAS,oBAAoB;AAC7D,eAAK;AACL,kBAAQ,IAAI;AACZ,iBAAO,eAAe,WAAW,QAAQ;AAAA,QAC1C;AAAA,MACD;AACA,YAAM,OAAO,GAAG,WAAW,QAAQ;AAAA,IACpC,CAAC;AAAA,IACDA,cAAQ,SAAS,EAAE,KAAK,MAAM;AAC7B,UAAI,CAAC,IAAI;AACR,cAAM,IAAI,MAAM,wBAAwB;AAAA,MACzC;AACA,aAAO;AAAA,IACR,CAAC;AAAA,EAAA,CACD;AACF;AAEO,MAAM,sBAAsB,MAClC,QAAQ,OAAO;AAAA,EACd,MAAM;AACP,CAAC;AAEK,MAAM,cAAc;AAAA,EAApB,cAAA;AACN,kBAAA,MAAQ,iBAAgB,KAAA;AAExB,kBAAA,MAAQ,+BAA2B,IAAA,CAAI;AAAA,EAAA;AAAA,EAEvC,MAAa,MAAM,EAAE,aAAa,OAA0D;AAC3F,QAAI,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,+BAA+B;AAAA,IAChD;AACA,aAAS,IAAI,GAAG,IAAI,aAAa,KAAK;AACrC,YAAM,KAAK,YAAY,GAAG;AAC1B,UAAI,KAAK,eAAe;AACvB;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAc,YAAY,KAAW;AACpC,UAAM,SAAS,QAAQ,KAAK,GAAG;AAC/B,WAAO,GAAG,QAAQ,OAAO,MAAM,WAAW;AACzC,WAAK,QAAQ,OAAO,MAAM;AAC1B,UAAI,CAAC,KAAK,eAAe;AACxB,gBAAQ,IAAI,UAAU,OAAO,QAAQ,GAAG,qBAAqB,MAAM,cAAc;AACjF,cAAMA,MAAAA,QAAQ,GAAI;AAClB,cAAM,KAAK,YAAY,GAAG;AAAA,MAC3B;AAAA,IACD,CAAC;AACD,SAAK,QAAQ,IAAI,MAAM;AACvB,UAAM,cAAc,QAAQ,IAAK;AAAA,EAClC;AAAA,EAEA,MAAa,UAAU,QAAuC;AAC7D,QAAI,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,+BAA+B;AAAA,IAChD;AACA,SAAK,gBAAgB;AACrB,UAAM,QAAQ;AAAA,MACb,MAAM,KAAK,KAAK,OAAO,EAAE,IAAI,OAAM,OAAM;AACxC,YAAI,CAAC,IAAI;AACR;AAAA,QACD;AACA,gBAAQ,IAAI,sBAAsB,GAAG,QAAQ,GAAG,EAAE;AAClD,cAAM,oBAAoB,IAAI,QAAQ,CAAA,YAAW,GAAG,KAAK,cAAc,OAAO,CAAC;AAC/E,WAAG,WAAA;AACH,cAAM;AACN,cAAM,cAAc,IAAI,QAAQ,CAAA,YAAW,GAAG,KAAK,QAAQ,OAAO,CAAC;AACnE,WAAG,KAAK,MAAM;AACd,cAAM;AACN,gBAAQ,IAAI,UAAU,GAAG,QAAQ,GAAG,aAAa;AAAA,MAClD,CAAC;AAAA,IAAA;AAAA,EAEH;AACD;;;;;"}
@@ -63,19 +63,21 @@ class WorkerManager {
63
63
  throw new Error(`Worker manager is terminating`);
64
64
  }
65
65
  this.isTerminating = true;
66
- await Promise.allSettled(Array.from(this.workers).map(async (it) => {
67
- if (!it) {
68
- return;
69
- }
70
- console.log(`Terminating worker ${it.process.pid}`);
71
- const disconnectPromise = new Promise((resolve) => it.once("disconnect", resolve));
72
- it.disconnect();
73
- await disconnectPromise;
74
- const killPromise = new Promise((resolve) => it.once("exit", resolve));
75
- it.kill(signal);
76
- await killPromise;
77
- console.log(`Worker ${it.process.pid} terminated`);
78
- }));
66
+ await Promise.allSettled(
67
+ Array.from(this.workers).map(async (it) => {
68
+ if (!it) {
69
+ return;
70
+ }
71
+ console.log(`Terminating worker ${it.process.pid}`);
72
+ const disconnectPromise = new Promise((resolve) => it.once("disconnect", resolve));
73
+ it.disconnect();
74
+ await disconnectPromise;
75
+ const killPromise = new Promise((resolve) => it.once("exit", resolve));
76
+ it.kill(signal);
77
+ await killPromise;
78
+ console.log(`Worker ${it.process.pid} terminated`);
79
+ })
80
+ );
79
81
  }
80
82
  }
81
83
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"cluster.js","sources":["../../../../packages/engine-server/src/cluster.ts"],"sourcesContent":["import cluster, { Worker } from 'node:cluster'\nimport { timeout } from './utils'\n\nexport const getClusterProcessType = (isClusterMode: boolean): ProcessType =>\n\t!isClusterMode ? 'singleNode' : cluster.isMaster ? 'clusterMaster' : 'clusterWorker'\n\nexport type ProcessType =\n\t| 'singleNode'\n\t| 'clusterMaster'\n\t| 'clusterWorker'\n\nconst MSG_WORKER_STARTED = 'msg_worker_started'\n\nexport const waitForWorker = (worker: Worker, timeoutMs: number) => {\n\tlet ok = false\n\treturn Promise.race([\n\t\tnew Promise(async resolve => {\n\t\t\tconst listener = (message: any) => {\n\t\t\t\tif ('type' in message && message.type === MSG_WORKER_STARTED) {\n\t\t\t\t\tok = true\n\t\t\t\t\tresolve(null)\n\t\t\t\t\tworker.removeListener('message', listener)\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait worker.on('message', listener)\n\t\t}),\n\t\ttimeout(timeoutMs).then(() => {\n\t\t\tif (!ok) {\n\t\t\t\tthrow new Error('Worker start timed out')\n\t\t\t}\n\t\t\treturn true\n\t\t}),\n\t])\n}\n\nexport const notifyWorkerStarted = () =>\n\tprocess.send?.({\n\t\ttype: MSG_WORKER_STARTED,\n\t})\n\nexport class WorkerManager {\n\n\tprivate isTerminating = false\n\n\tprivate workers: Set<Worker> = new Set()\n\n\tpublic async start({ workerCount, env }: { workerCount: number; env?: any }): Promise<void> {\n\t\tif (this.isTerminating) {\n\t\t\tthrow new Error(`Worker manager is terminating`)\n\t\t}\n\t\tfor (let i = 0; i < workerCount; i++) {\n\t\t\tawait this.startWorker(env)\n\t\t\tif (this.isTerminating) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async startWorker(env?: any) {\n\t\tconst worker = cluster.fork(env)\n\t\tworker.on('exit', async (code, signal) => {\n\t\t\tthis.workers.delete(worker)\n\t\t\tif (!this.isTerminating) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.log(`Worker ${worker.process.pid} died with signal ${signal}, restarting`)\n\t\t\t\tawait timeout(2000)\n\t\t\t\tawait this.startWorker(env)\n\t\t\t}\n\t\t})\n\t\tthis.workers.add(worker)\n\t\tawait waitForWorker(worker, 15000)\n\t}\n\n\tpublic async terminate(signal: NodeJS.Signals): Promise<void> {\n\t\tif (this.isTerminating) {\n\t\t\tthrow new Error(`Worker manager is terminating`)\n\t\t}\n\t\tthis.isTerminating = true\n\t\tawait Promise.allSettled(Array.from(this.workers).map(async it => {\n\t\t\tif (!it) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.log(`Terminating worker ${it.process.pid}`)\n\t\t\tconst disconnectPromise = new Promise(resolve => it.once('disconnect', resolve))\n\t\t\tit.disconnect()\n\t\t\tawait disconnectPromise\n\t\t\tconst killPromise = new Promise(resolve => it.once('exit', resolve))\n\t\t\tit.kill(signal)\n\t\t\tawait killPromise\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.log(`Worker ${it.process.pid} terminated`)\n\t\t}))\n\t}\n}\n"],"names":[],"mappings":";;;;;AAGa,MAAA,wBAAwB,CAAC,kBACrC,CAAC,gBAAgB,eAAe,QAAQ,WAAW,kBAAkB;AAOtE,MAAM,qBAAqB;AAEd,MAAA,gBAAgB,CAAC,QAAgB,cAAsB;AACnE,MAAI,KAAK;AACT,SAAO,QAAQ,KAAK;AAAA,IACnB,IAAI,QAAQ,OAAM,YAAW;AACtB,YAAA,WAAW,CAAC,YAAiB;AAClC,YAAI,UAAU,WAAW,QAAQ,SAAS,oBAAoB;AACxD,eAAA;AACL,kBAAQ,IAAI;AACL,iBAAA,eAAe,WAAW,QAAQ;AAAA,QAAA;AAAA,MAE3C;AACM,YAAA,OAAO,GAAG,WAAW,QAAQ;AAAA,IAAA,CACnC;AAAA,IACD,QAAQ,SAAS,EAAE,KAAK,MAAM;AAC7B,UAAI,CAAC,IAAI;AACF,cAAA,IAAI,MAAM,wBAAwB;AAAA,MAAA;AAElC,aAAA;AAAA,IACP,CAAA;AAAA,EAAA,CACD;AACF;AAEa,MAAA,sBAAsB,MAClC,QAAQ,OAAO;AAAA,EACd,MAAM;AACP,CAAC;AAEK,MAAM,cAAc;AAAA,EAApB,cAAA;AAEN,kBAAA,MAAQ,iBAAgB,KAAA;AAEhB,kBAAA,MAAA,+BAA2B,IAAI,CAAA;AAAA,EAAA;AAAA,EAEvC,MAAa,MAAM,EAAE,aAAa,OAA0D;AAC3F,QAAI,KAAK,eAAe;AACjB,YAAA,IAAI,MAAM,+BAA+B;AAAA,IAAA;AAEhD,aAAS,IAAI,GAAG,IAAI,aAAa,KAAK;AAC/B,YAAA,KAAK,YAAY,GAAG;AAC1B,UAAI,KAAK,eAAe;AACvB;AAAA,MAAA;AAAA,IACD;AAAA,EACD;AAAA,EAGD,MAAc,YAAY,KAAW;AAC9B,UAAA,SAAS,QAAQ,KAAK,GAAG;AAC/B,WAAO,GAAG,QAAQ,OAAO,MAAM,WAAW;AACpC,WAAA,QAAQ,OAAO,MAAM;AACtB,UAAA,CAAC,KAAK,eAAe;AAExB,gBAAQ,IAAI,UAAU,OAAO,QAAQ,GAAG,qBAAqB,MAAM,cAAc;AACjF,cAAM,QAAQ,GAAI;AACZ,cAAA,KAAK,YAAY,GAAG;AAAA,MAAA;AAAA,IAC3B,CACA;AACI,SAAA,QAAQ,IAAI,MAAM;AACjB,UAAA,cAAc,QAAQ,IAAK;AAAA,EAAA;AAAA,EAGlC,MAAa,UAAU,QAAuC;AAC7D,QAAI,KAAK,eAAe;AACjB,YAAA,IAAI,MAAM,+BAA+B;AAAA,IAAA;AAEhD,SAAK,gBAAgB;AACf,UAAA,QAAQ,WAAW,MAAM,KAAK,KAAK,OAAO,EAAE,IAAI,OAAM,OAAM;AACjE,UAAI,CAAC,IAAI;AACR;AAAA,MAAA;AAGD,cAAQ,IAAI,sBAAsB,GAAG,QAAQ,GAAG,EAAE;AAC5C,YAAA,oBAAoB,IAAI,QAAQ,CAAA,YAAW,GAAG,KAAK,cAAc,OAAO,CAAC;AAC/E,SAAG,WAAW;AACR,YAAA;AACA,YAAA,cAAc,IAAI,QAAQ,CAAA,YAAW,GAAG,KAAK,QAAQ,OAAO,CAAC;AACnE,SAAG,KAAK,MAAM;AACR,YAAA;AAEN,cAAQ,IAAI,UAAU,GAAG,QAAQ,GAAG,aAAa;AAAA,IAAA,CACjD,CAAC;AAAA,EAAA;AAEJ;"}
1
+ {"version":3,"file":"cluster.js","sources":["../../../../packages/engine-server/src/cluster.ts"],"sourcesContent":["import cluster, { Worker } from 'node:cluster'\nimport { timeout } from './utils'\n\nexport const getClusterProcessType = (isClusterMode: boolean): ProcessType =>\n\t!isClusterMode ? 'singleNode' : cluster.isMaster ? 'clusterMaster' : 'clusterWorker'\n\nexport type ProcessType =\n\t| 'singleNode'\n\t| 'clusterMaster'\n\t| 'clusterWorker'\n\nconst MSG_WORKER_STARTED = 'msg_worker_started'\n\nexport const waitForWorker = (worker: Worker, timeoutMs: number) => {\n\tlet ok = false\n\treturn Promise.race([\n\t\tnew Promise(async resolve => {\n\t\t\tconst listener = (message: any) => {\n\t\t\t\tif ('type' in message && message.type === MSG_WORKER_STARTED) {\n\t\t\t\t\tok = true\n\t\t\t\t\tresolve(null)\n\t\t\t\t\tworker.removeListener('message', listener)\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait worker.on('message', listener)\n\t\t}),\n\t\ttimeout(timeoutMs).then(() => {\n\t\t\tif (!ok) {\n\t\t\t\tthrow new Error('Worker start timed out')\n\t\t\t}\n\t\t\treturn true\n\t\t}),\n\t])\n}\n\nexport const notifyWorkerStarted = () =>\n\tprocess.send?.({\n\t\ttype: MSG_WORKER_STARTED,\n\t})\n\nexport class WorkerManager {\n\tprivate isTerminating = false\n\n\tprivate workers: Set<Worker> = new Set()\n\n\tpublic async start({ workerCount, env }: { workerCount: number; env?: any }): Promise<void> {\n\t\tif (this.isTerminating) {\n\t\t\tthrow new Error(`Worker manager is terminating`)\n\t\t}\n\t\tfor (let i = 0; i < workerCount; i++) {\n\t\t\tawait this.startWorker(env)\n\t\t\tif (this.isTerminating) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async startWorker(env?: any) {\n\t\tconst worker = cluster.fork(env)\n\t\tworker.on('exit', async (code, signal) => {\n\t\t\tthis.workers.delete(worker)\n\t\t\tif (!this.isTerminating) {\n\t\t\t\tconsole.log(`Worker ${worker.process.pid} died with signal ${signal}, restarting`)\n\t\t\t\tawait timeout(2000)\n\t\t\t\tawait this.startWorker(env)\n\t\t\t}\n\t\t})\n\t\tthis.workers.add(worker)\n\t\tawait waitForWorker(worker, 15000)\n\t}\n\n\tpublic async terminate(signal: NodeJS.Signals): Promise<void> {\n\t\tif (this.isTerminating) {\n\t\t\tthrow new Error(`Worker manager is terminating`)\n\t\t}\n\t\tthis.isTerminating = true\n\t\tawait Promise.allSettled(\n\t\t\tArray.from(this.workers).map(async it => {\n\t\t\t\tif (!it) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconsole.log(`Terminating worker ${it.process.pid}`)\n\t\t\t\tconst disconnectPromise = new Promise(resolve => it.once('disconnect', resolve))\n\t\t\t\tit.disconnect()\n\t\t\t\tawait disconnectPromise\n\t\t\t\tconst killPromise = new Promise(resolve => it.once('exit', resolve))\n\t\t\t\tit.kill(signal)\n\t\t\t\tawait killPromise\n\t\t\t\tconsole.log(`Worker ${it.process.pid} terminated`)\n\t\t\t}),\n\t\t)\n\t}\n}\n"],"names":[],"mappings":";;;;;AAGO,MAAM,wBAAwB,CAAC,kBACrC,CAAC,gBAAgB,eAAe,QAAQ,WAAW,kBAAkB;AAOtE,MAAM,qBAAqB;AAEpB,MAAM,gBAAgB,CAAC,QAAgB,cAAsB;AACnE,MAAI,KAAK;AACT,SAAO,QAAQ,KAAK;AAAA,IACnB,IAAI,QAAQ,OAAM,YAAW;AAC5B,YAAM,WAAW,CAAC,YAAiB;AAClC,YAAI,UAAU,WAAW,QAAQ,SAAS,oBAAoB;AAC7D,eAAK;AACL,kBAAQ,IAAI;AACZ,iBAAO,eAAe,WAAW,QAAQ;AAAA,QAC1C;AAAA,MACD;AACA,YAAM,OAAO,GAAG,WAAW,QAAQ;AAAA,IACpC,CAAC;AAAA,IACD,QAAQ,SAAS,EAAE,KAAK,MAAM;AAC7B,UAAI,CAAC,IAAI;AACR,cAAM,IAAI,MAAM,wBAAwB;AAAA,MACzC;AACA,aAAO;AAAA,IACR,CAAC;AAAA,EAAA,CACD;AACF;AAEO,MAAM,sBAAsB,MAClC,QAAQ,OAAO;AAAA,EACd,MAAM;AACP,CAAC;AAEK,MAAM,cAAc;AAAA,EAApB,cAAA;AACN,kBAAA,MAAQ,iBAAgB,KAAA;AAExB,kBAAA,MAAQ,+BAA2B,IAAA,CAAI;AAAA,EAAA;AAAA,EAEvC,MAAa,MAAM,EAAE,aAAa,OAA0D;AAC3F,QAAI,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,+BAA+B;AAAA,IAChD;AACA,aAAS,IAAI,GAAG,IAAI,aAAa,KAAK;AACrC,YAAM,KAAK,YAAY,GAAG;AAC1B,UAAI,KAAK,eAAe;AACvB;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAc,YAAY,KAAW;AACpC,UAAM,SAAS,QAAQ,KAAK,GAAG;AAC/B,WAAO,GAAG,QAAQ,OAAO,MAAM,WAAW;AACzC,WAAK,QAAQ,OAAO,MAAM;AAC1B,UAAI,CAAC,KAAK,eAAe;AACxB,gBAAQ,IAAI,UAAU,OAAO,QAAQ,GAAG,qBAAqB,MAAM,cAAc;AACjF,cAAM,QAAQ,GAAI;AAClB,cAAM,KAAK,YAAY,GAAG;AAAA,MAC3B;AAAA,IACD,CAAC;AACD,SAAK,QAAQ,IAAI,MAAM;AACvB,UAAM,cAAc,QAAQ,IAAK;AAAA,EAClC;AAAA,EAEA,MAAa,UAAU,QAAuC;AAC7D,QAAI,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,+BAA+B;AAAA,IAChD;AACA,SAAK,gBAAgB;AACrB,UAAM,QAAQ;AAAA,MACb,MAAM,KAAK,KAAK,OAAO,EAAE,IAAI,OAAM,OAAM;AACxC,YAAI,CAAC,IAAI;AACR;AAAA,QACD;AACA,gBAAQ,IAAI,sBAAsB,GAAG,QAAQ,GAAG,EAAE;AAClD,cAAM,oBAAoB,IAAI,QAAQ,CAAA,YAAW,GAAG,KAAK,cAAc,OAAO,CAAC;AAC/E,WAAG,WAAA;AACH,cAAM;AACN,cAAM,cAAc,IAAI,QAAQ,CAAA,YAAW,GAAG,KAAK,QAAQ,OAAO,CAAC;AACnE,WAAG,KAAK,MAAM;AACd,cAAM;AACN,gBAAQ,IAAI,UAAU,GAAG,QAAQ,GAAG,aAAa;AAAA,MAClD,CAAC;AAAA,IAAA;AAAA,EAEH;AACD;"}
@@ -1 +1 @@
1
- {"version":3,"file":"loadPlugins.cjs","sources":["../../../../packages/engine-server/src/loadPlugins.ts"],"sourcesContent":["import ActionsPlugin from '@contember/engine-actions'\nimport { Plugin } from '@contember/engine-plugins'\nimport S3Plugin from '@contember/engine-s3-plugin'\nimport VimeoPlugin from '@contember/engine-vimeo-plugin'\n\nexport default function loadPlugins(): Promise<Plugin[]> {\n\treturn Promise.resolve([new S3Plugin(), new VimeoPlugin(), new ActionsPlugin()])\n}\n"],"names":[],"mappings":";;;;AAKA,SAAwB,cAAiC;AACxD,SAAO,QAAQ,QAAQ,CAAC,IAAI,SAAS,GAAG,IAAI,YAAe,GAAA,IAAI,cAAc,CAAC,CAAC;AAChF;;"}
1
+ {"version":3,"file":"loadPlugins.cjs","sources":["../../../../packages/engine-server/src/loadPlugins.ts"],"sourcesContent":["import ActionsPlugin from '@contember/engine-actions'\nimport { Plugin } from '@contember/engine-plugins'\nimport S3Plugin from '@contember/engine-s3-plugin'\nimport VimeoPlugin from '@contember/engine-vimeo-plugin'\n\nexport default function loadPlugins(): Promise<Plugin[]> {\n\treturn Promise.resolve([new S3Plugin(), new VimeoPlugin(), new ActionsPlugin()])\n}\n"],"names":[],"mappings":";;;;AAKA,SAAwB,cAAiC;AACxD,SAAO,QAAQ,QAAQ,CAAC,IAAI,SAAA,GAAY,IAAI,YAAA,GAAe,IAAI,cAAA,CAAe,CAAC;AAChF;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"loadPlugins.js","sources":["../../../../packages/engine-server/src/loadPlugins.ts"],"sourcesContent":["import ActionsPlugin from '@contember/engine-actions'\nimport { Plugin } from '@contember/engine-plugins'\nimport S3Plugin from '@contember/engine-s3-plugin'\nimport VimeoPlugin from '@contember/engine-vimeo-plugin'\n\nexport default function loadPlugins(): Promise<Plugin[]> {\n\treturn Promise.resolve([new S3Plugin(), new VimeoPlugin(), new ActionsPlugin()])\n}\n"],"names":[],"mappings":";;;AAKA,SAAwB,cAAiC;AACxD,SAAO,QAAQ,QAAQ,CAAC,IAAI,SAAS,GAAG,IAAI,YAAe,GAAA,IAAI,cAAc,CAAC,CAAC;AAChF;"}
1
+ {"version":3,"file":"loadPlugins.js","sources":["../../../../packages/engine-server/src/loadPlugins.ts"],"sourcesContent":["import ActionsPlugin from '@contember/engine-actions'\nimport { Plugin } from '@contember/engine-plugins'\nimport S3Plugin from '@contember/engine-s3-plugin'\nimport VimeoPlugin from '@contember/engine-vimeo-plugin'\n\nexport default function loadPlugins(): Promise<Plugin[]> {\n\treturn Promise.resolve([new S3Plugin(), new VimeoPlugin(), new ActionsPlugin()])\n}\n"],"names":[],"mappings":";;;AAKA,SAAwB,cAAiC;AACxD,SAAO,QAAQ,QAAQ,CAAC,IAAI,SAAA,GAAY,IAAI,YAAA,GAAe,IAAI,cAAA,CAAe,CAAC;AAChF;"}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.cjs","sources":["../../../../packages/engine-server/src/utils.ts"],"sourcesContent":["export const timeout = (ms: number) =>\n\tnew Promise(resolve => {\n\t\tsetTimeout(resolve, ms)\n\t})\n"],"names":[],"mappings":";;AAAO,MAAM,UAAU,CAAC,OACvB,IAAI,QAAQ,CAAW,YAAA;AACtB,aAAW,SAAS,EAAE;AACvB,CAAC;;"}
1
+ {"version":3,"file":"utils.cjs","sources":["../../../../packages/engine-server/src/utils.ts"],"sourcesContent":["export const timeout = (ms: number) =>\n\tnew Promise(resolve => {\n\t\tsetTimeout(resolve, ms)\n\t})\n"],"names":[],"mappings":";;AAAO,MAAM,UAAU,CAAC,OACvB,IAAI,QAAQ,CAAA,YAAW;AACtB,aAAW,SAAS,EAAE;AACvB,CAAC;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../../../../packages/engine-server/src/utils.ts"],"sourcesContent":["export const timeout = (ms: number) =>\n\tnew Promise(resolve => {\n\t\tsetTimeout(resolve, ms)\n\t})\n"],"names":[],"mappings":"AAAO,MAAM,UAAU,CAAC,OACvB,IAAI,QAAQ,CAAW,YAAA;AACtB,aAAW,SAAS,EAAE;AACvB,CAAC;"}
1
+ {"version":3,"file":"utils.js","sources":["../../../../packages/engine-server/src/utils.ts"],"sourcesContent":["export const timeout = (ms: number) =>\n\tnew Promise(resolve => {\n\t\tsetTimeout(resolve, ms)\n\t})\n"],"names":[],"mappings":"AAAO,MAAM,UAAU,CAAC,OACvB,IAAI,QAAQ,CAAA,YAAW;AACtB,aAAW,SAAS,EAAE;AACvB,CAAC;"}
@@ -1 +1 @@
1
- {"version":3,"file":"start.cjs","sources":["../../../packages/engine-server/src/start.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport {\n\tcreateContainer,\n\tcreateDefaultLogger,\n\tcreateSentryLoggerHandler,\n\tgetServerVersion,\n\tisDebugMode,\n\tlistenOnProcessTermination,\n\tprintStartInfo,\n\tresolveServerConfig,\n\tserverConfigSchema,\n\tTerminationJob,\n} from '@contember/engine-http'\nimport loadPlugins from './loadPlugins'\nimport cluster from 'node:cluster'\nimport * as os from 'node:os'\nimport { timeout } from './utils'\nimport { getClusterProcessType, notifyWorkerStarted, WorkerManager } from './cluster'\n\nconst logger = createDefaultLogger()\nprocess.on('warning', message => {\n\tlogger.warn(message)\n})\n;(async () => {\n\tconst isDebug = isDebugMode()\n\n\tconst version = await getServerVersion()\n\tprintStartInfo({ version, isDebug }, logger)\n\tconst plugins = await loadPlugins()\n\tconst { serverConfig, projectConfigResolver, tenantConfigResolver } = await resolveServerConfig({ plugins, serverConfigSchema })\n\n\tif (process.argv[2] === 'validate') {\n\t\tprocess.exit(0)\n\t}\n\n\tconst sentryhandler = createSentryLoggerHandler(serverConfig.logging?.sentry?.dsn)\n\tif (sentryhandler !== null) {\n\t\tlogger.addHandler(sentryhandler)\n\t}\n\n\tconst workerConfig = serverConfig.workerCount || 1\n\n\tconst workerCount = workerConfig === 'auto' ? os.cpus().length : Number(workerConfig)\n\tconst isClusterMode = serverConfig.workerCount !== undefined\n\n\tconst processType = getClusterProcessType(isClusterMode)\n\n\tconst container = createContainer({\n\t\tdebugMode: isDebug,\n\t\tserverConfig,\n\t\tprojectConfigResolver,\n\t\ttenantConfigResolver,\n\t\tplugins,\n\t\tprocessType,\n\t\tversion,\n\t\tlogger,\n\t})\n\n\tlet initializedProjects: string[] = []\n\tconst terminationJobs: TerminationJob[] = []\n\tlistenOnProcessTermination(terminationJobs, logger)\n\n\tif (cluster.isMaster) {\n\t\tconst monitoringPort = serverConfig.monitoringPort\n\t\tconst monitoringServer = container.monitoringKoa.listen(monitoringPort, () => {\n\t\t\tlogger.info(`Monitoring running on http://localhost:${monitoringPort}`)\n\t\t})\n\t\tterminationJobs.push(async () => {\n\t\t\tawait new Promise<any>(resolve => monitoringServer.close(resolve))\n\t\t\tlogger.info('Monitoring server terminated')\n\t\t})\n\t\tif (!serverConfig.projectGroup) {\n\t\t\tinitializedProjects = await container.initializer.initialize()\n\t\t}\n\t}\n\n\tconst port = serverConfig.port\n\tconst printStarted = () => {\n\t\tif (serverConfig.projectGroup) {\n\t\t\tlogger.info('Contember Cloud running')\n\t\t} else {\n\t\t\tlogger.info(`Contember API running on http://localhost:${port}`)\n\t\t}\n\t\tif (initializedProjects.length) {\n\t\t\tlogger.info(`Initialized projects: ${initializedProjects.join(', ')}`)\n\t\t}\n\t}\n\n\tconst startApplication = async () => {\n\t\tconst httpServerPromise = container.application.listen()\n\t\tterminationJobs.push(async () => {\n\t\t\tawait (await httpServerPromise).close()\n\t\t\tlogger.info('API server terminated')\n\t\t})\n\t\tawait httpServerPromise\n\t}\n\n\tconst startWorker = async (workerName: string) => {\n\t\tconst worker = container.applicationWorkers.getWorker(workerName)\n\t\tconst runningWorker = worker.run({\n\t\t\tlogger,\n\t\t\tonError: e => {\n\t\t\t\tlogger.crit(e)\n\t\t\t\tprocess.exit(1)\n\t\t\t},\n\t\t})\n\t\tterminationJobs.push(async () => {\n\t\t\t(await runningWorker).end()\n\t\t})\n\t\tawait runningWorker\n\t\tlogger.info(`Contember Worker ${workerName} started.`)\n\n\t}\n\n\tconst applicationWorker = serverConfig.applicationWorker\n\tif (applicationWorker && applicationWorker !== 'all') {\n\t\tawait startWorker(applicationWorker)\n\t\tif (isClusterMode) {\n\t\t\tnotifyWorkerStarted()\n\t\t}\n\t} else if (isClusterMode) {\n\t\tif (cluster.isMaster) {\n\t\t\tlogger.info(`Master ${process.pid} is running`)\n\t\t\tconst workerManager = new WorkerManager()\n\t\t\tterminationJobs.push(async ({ signal }) => {\n\t\t\t\tawait workerManager.terminate(signal)\n\t\t\t\tlogger.info('Workers terminated')\n\t\t\t})\n\n\t\t\tawait workerManager.start({ workerCount })\n\n\t\t\tif (applicationWorker === 'all') {\n\t\t\t\tfor (const workerName of container.applicationWorkers.getWorkerNames()) {\n\t\t\t\t\tawait workerManager.start({\n\t\t\t\t\t\tworkerCount, env: {\n\t\t\t\t\t\t\tCONTEMBER_APPLICATION_WORKER: workerName,\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t\tprintStarted()\n\t\t} else {\n\t\t\tlogger.info(`Starting worker ${process.pid}`)\n\n\t\t\t// this line somehow ensures, that worker waits for termination of all jobs\n\t\t\tprocess.on('disconnect', () => timeout(0))\n\n\t\t\tawait startApplication()\n\t\t\tnotifyWorkerStarted()\n\t\t}\n\t} else {\n\t\tawait startApplication()\n\t\tif (applicationWorker === 'all') {\n\t\t\tfor (const workerName of container.applicationWorkers.getWorkerNames()) {\n\t\t\t\tawait startWorker(workerName)\n\t\t\t}\n\t\t}\n\t\tprintStarted()\n\t}\n\n})().catch(e => {\n\tlogger.crit(e)\n\tprocess.exit(1)\n})\n"],"names":["createDefaultLogger","isDebugMode","getServerVersion","printStartInfo","resolveServerConfig","serverConfigSchema","createSentryLoggerHandler","os","getClusterProcessType","createContainer","listenOnProcessTermination","cluster","notifyWorkerStarted","WorkerManager","timeout"],"mappings":"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"}
1
+ {"version":3,"file":"start.cjs","sources":["../../../packages/engine-server/src/start.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport {\n\tcreateContainer,\n\tcreateDefaultLogger,\n\tcreateSentryLoggerHandler,\n\tgetServerVersion,\n\tisDebugMode,\n\tlistenOnProcessTermination,\n\tprintStartInfo,\n\tresolveServerConfig,\n\tserverConfigSchema,\n\tTerminationJob,\n} from '@contember/engine-http'\nimport loadPlugins from './loadPlugins'\nimport cluster from 'node:cluster'\nimport * as os from 'node:os'\nimport { timeout } from './utils'\nimport { getClusterProcessType, notifyWorkerStarted, WorkerManager } from './cluster'\n\nconst logger = createDefaultLogger()\nprocess.on('warning', message => {\n\tlogger.warn(message)\n})\n;(async () => {\n\tconst isDebug = isDebugMode()\n\n\tconst version = await getServerVersion()\n\tprintStartInfo({ version, isDebug }, logger)\n\tconst plugins = await loadPlugins()\n\tconst { serverConfig, projectConfigResolver, tenantConfigResolver } = await resolveServerConfig({ plugins, serverConfigSchema })\n\n\tif (process.argv[2] === 'validate') {\n\t\tprocess.exit(0)\n\t}\n\n\tconst sentryhandler = createSentryLoggerHandler(serverConfig.logging?.sentry?.dsn)\n\tif (sentryhandler !== null) {\n\t\tlogger.addHandler(sentryhandler)\n\t}\n\n\tconst workerConfig = serverConfig.workerCount || 1\n\n\tconst workerCount = workerConfig === 'auto' ? os.cpus().length : Number(workerConfig)\n\tconst isClusterMode = serverConfig.workerCount !== undefined\n\n\tconst processType = getClusterProcessType(isClusterMode)\n\n\tconst container = createContainer({\n\t\tdebugMode: isDebug,\n\t\tserverConfig,\n\t\tprojectConfigResolver,\n\t\ttenantConfigResolver,\n\t\tplugins,\n\t\tprocessType,\n\t\tversion,\n\t\tlogger,\n\t})\n\n\tlet initializedProjects: string[] = []\n\tconst terminationJobs: TerminationJob[] = []\n\tlistenOnProcessTermination(terminationJobs, logger)\n\n\tif (cluster.isMaster) {\n\t\tconst monitoringPort = serverConfig.monitoringPort\n\t\tconst monitoringServer = container.monitoringKoa.listen(monitoringPort, () => {\n\t\t\tlogger.info(`Monitoring running on http://localhost:${monitoringPort}`)\n\t\t})\n\t\tterminationJobs.push(async () => {\n\t\t\tawait new Promise<any>(resolve => monitoringServer.close(resolve))\n\t\t\tlogger.info('Monitoring server terminated')\n\t\t})\n\t\tif (!serverConfig.projectGroup) {\n\t\t\tinitializedProjects = await container.initializer.initialize()\n\t\t}\n\t}\n\n\tconst port = serverConfig.port\n\tconst printStarted = () => {\n\t\tif (serverConfig.projectGroup) {\n\t\t\tlogger.info('Contember Cloud running')\n\t\t} else {\n\t\t\tlogger.info(`Contember API running on http://localhost:${port}`)\n\t\t}\n\t\tif (initializedProjects.length) {\n\t\t\tlogger.info(`Initialized projects: ${initializedProjects.join(', ')}`)\n\t\t}\n\t}\n\n\tconst startApplication = async () => {\n\t\tconst httpServerPromise = container.application.listen()\n\t\tterminationJobs.push(async () => {\n\t\t\tawait (await httpServerPromise).close()\n\t\t\tlogger.info('API server terminated')\n\t\t})\n\t\tawait httpServerPromise\n\t}\n\n\tconst startWorker = async (workerName: string) => {\n\t\tconst worker = container.applicationWorkers.getWorker(workerName)\n\t\tconst runningWorker = worker.run({\n\t\t\tlogger,\n\t\t\tonError: e => {\n\t\t\t\tlogger.crit(e)\n\t\t\t\tprocess.exit(1)\n\t\t\t},\n\t\t})\n\t\tterminationJobs.push(async () => {\n\t\t\t;(await runningWorker).end()\n\t\t})\n\t\tawait runningWorker\n\t\tlogger.info(`Contember Worker ${workerName} started.`)\n\t}\n\n\tconst applicationWorker = serverConfig.applicationWorker\n\tif (applicationWorker && applicationWorker !== 'all') {\n\t\tawait startWorker(applicationWorker)\n\t\tif (isClusterMode) {\n\t\t\tnotifyWorkerStarted()\n\t\t}\n\t} else if (isClusterMode) {\n\t\tif (cluster.isMaster) {\n\t\t\tlogger.info(`Master ${process.pid} is running`)\n\t\t\tconst workerManager = new WorkerManager()\n\t\t\tterminationJobs.push(async ({ signal }) => {\n\t\t\t\tawait workerManager.terminate(signal)\n\t\t\t\tlogger.info('Workers terminated')\n\t\t\t})\n\n\t\t\tawait workerManager.start({ workerCount })\n\n\t\t\tif (applicationWorker === 'all') {\n\t\t\t\tfor (const workerName of container.applicationWorkers.getWorkerNames()) {\n\t\t\t\t\tawait workerManager.start({\n\t\t\t\t\t\tworkerCount,\n\t\t\t\t\t\tenv: {\n\t\t\t\t\t\t\tCONTEMBER_APPLICATION_WORKER: workerName,\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t\tprintStarted()\n\t\t} else {\n\t\t\tlogger.info(`Starting worker ${process.pid}`)\n\n\t\t\t// this line somehow ensures, that worker waits for termination of all jobs\n\t\t\tprocess.on('disconnect', () => timeout(0))\n\n\t\t\tawait startApplication()\n\t\t\tnotifyWorkerStarted()\n\t\t}\n\t} else {\n\t\tawait startApplication()\n\t\tif (applicationWorker === 'all') {\n\t\t\tfor (const workerName of container.applicationWorkers.getWorkerNames()) {\n\t\t\t\tawait startWorker(workerName)\n\t\t\t}\n\t\t}\n\t\tprintStarted()\n\t}\n})().catch(e => {\n\tlogger.crit(e)\n\tprocess.exit(1)\n})\n"],"names":["createDefaultLogger","isDebugMode","getServerVersion","printStartInfo","resolveServerConfig","serverConfigSchema","createSentryLoggerHandler","os","getClusterProcessType","createContainer","listenOnProcessTermination","cluster","notifyWorkerStarted","WorkerManager","timeout"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"start.js","sources":["../../../packages/engine-server/src/start.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport {\n\tcreateContainer,\n\tcreateDefaultLogger,\n\tcreateSentryLoggerHandler,\n\tgetServerVersion,\n\tisDebugMode,\n\tlistenOnProcessTermination,\n\tprintStartInfo,\n\tresolveServerConfig,\n\tserverConfigSchema,\n\tTerminationJob,\n} from '@contember/engine-http'\nimport loadPlugins from './loadPlugins'\nimport cluster from 'node:cluster'\nimport * as os from 'node:os'\nimport { timeout } from './utils'\nimport { getClusterProcessType, notifyWorkerStarted, WorkerManager } from './cluster'\n\nconst logger = createDefaultLogger()\nprocess.on('warning', message => {\n\tlogger.warn(message)\n})\n;(async () => {\n\tconst isDebug = isDebugMode()\n\n\tconst version = await getServerVersion()\n\tprintStartInfo({ version, isDebug }, logger)\n\tconst plugins = await loadPlugins()\n\tconst { serverConfig, projectConfigResolver, tenantConfigResolver } = await resolveServerConfig({ plugins, serverConfigSchema })\n\n\tif (process.argv[2] === 'validate') {\n\t\tprocess.exit(0)\n\t}\n\n\tconst sentryhandler = createSentryLoggerHandler(serverConfig.logging?.sentry?.dsn)\n\tif (sentryhandler !== null) {\n\t\tlogger.addHandler(sentryhandler)\n\t}\n\n\tconst workerConfig = serverConfig.workerCount || 1\n\n\tconst workerCount = workerConfig === 'auto' ? os.cpus().length : Number(workerConfig)\n\tconst isClusterMode = serverConfig.workerCount !== undefined\n\n\tconst processType = getClusterProcessType(isClusterMode)\n\n\tconst container = createContainer({\n\t\tdebugMode: isDebug,\n\t\tserverConfig,\n\t\tprojectConfigResolver,\n\t\ttenantConfigResolver,\n\t\tplugins,\n\t\tprocessType,\n\t\tversion,\n\t\tlogger,\n\t})\n\n\tlet initializedProjects: string[] = []\n\tconst terminationJobs: TerminationJob[] = []\n\tlistenOnProcessTermination(terminationJobs, logger)\n\n\tif (cluster.isMaster) {\n\t\tconst monitoringPort = serverConfig.monitoringPort\n\t\tconst monitoringServer = container.monitoringKoa.listen(monitoringPort, () => {\n\t\t\tlogger.info(`Monitoring running on http://localhost:${monitoringPort}`)\n\t\t})\n\t\tterminationJobs.push(async () => {\n\t\t\tawait new Promise<any>(resolve => monitoringServer.close(resolve))\n\t\t\tlogger.info('Monitoring server terminated')\n\t\t})\n\t\tif (!serverConfig.projectGroup) {\n\t\t\tinitializedProjects = await container.initializer.initialize()\n\t\t}\n\t}\n\n\tconst port = serverConfig.port\n\tconst printStarted = () => {\n\t\tif (serverConfig.projectGroup) {\n\t\t\tlogger.info('Contember Cloud running')\n\t\t} else {\n\t\t\tlogger.info(`Contember API running on http://localhost:${port}`)\n\t\t}\n\t\tif (initializedProjects.length) {\n\t\t\tlogger.info(`Initialized projects: ${initializedProjects.join(', ')}`)\n\t\t}\n\t}\n\n\tconst startApplication = async () => {\n\t\tconst httpServerPromise = container.application.listen()\n\t\tterminationJobs.push(async () => {\n\t\t\tawait (await httpServerPromise).close()\n\t\t\tlogger.info('API server terminated')\n\t\t})\n\t\tawait httpServerPromise\n\t}\n\n\tconst startWorker = async (workerName: string) => {\n\t\tconst worker = container.applicationWorkers.getWorker(workerName)\n\t\tconst runningWorker = worker.run({\n\t\t\tlogger,\n\t\t\tonError: e => {\n\t\t\t\tlogger.crit(e)\n\t\t\t\tprocess.exit(1)\n\t\t\t},\n\t\t})\n\t\tterminationJobs.push(async () => {\n\t\t\t(await runningWorker).end()\n\t\t})\n\t\tawait runningWorker\n\t\tlogger.info(`Contember Worker ${workerName} started.`)\n\n\t}\n\n\tconst applicationWorker = serverConfig.applicationWorker\n\tif (applicationWorker && applicationWorker !== 'all') {\n\t\tawait startWorker(applicationWorker)\n\t\tif (isClusterMode) {\n\t\t\tnotifyWorkerStarted()\n\t\t}\n\t} else if (isClusterMode) {\n\t\tif (cluster.isMaster) {\n\t\t\tlogger.info(`Master ${process.pid} is running`)\n\t\t\tconst workerManager = new WorkerManager()\n\t\t\tterminationJobs.push(async ({ signal }) => {\n\t\t\t\tawait workerManager.terminate(signal)\n\t\t\t\tlogger.info('Workers terminated')\n\t\t\t})\n\n\t\t\tawait workerManager.start({ workerCount })\n\n\t\t\tif (applicationWorker === 'all') {\n\t\t\t\tfor (const workerName of container.applicationWorkers.getWorkerNames()) {\n\t\t\t\t\tawait workerManager.start({\n\t\t\t\t\t\tworkerCount, env: {\n\t\t\t\t\t\t\tCONTEMBER_APPLICATION_WORKER: workerName,\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t\tprintStarted()\n\t\t} else {\n\t\t\tlogger.info(`Starting worker ${process.pid}`)\n\n\t\t\t// this line somehow ensures, that worker waits for termination of all jobs\n\t\t\tprocess.on('disconnect', () => timeout(0))\n\n\t\t\tawait startApplication()\n\t\t\tnotifyWorkerStarted()\n\t\t}\n\t} else {\n\t\tawait startApplication()\n\t\tif (applicationWorker === 'all') {\n\t\t\tfor (const workerName of container.applicationWorkers.getWorkerNames()) {\n\t\t\t\tawait startWorker(workerName)\n\t\t\t}\n\t\t}\n\t\tprintStarted()\n\t}\n\n})().catch(e => {\n\tlogger.crit(e)\n\tprocess.exit(1)\n})\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"start.js","sources":["../../../packages/engine-server/src/start.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport {\n\tcreateContainer,\n\tcreateDefaultLogger,\n\tcreateSentryLoggerHandler,\n\tgetServerVersion,\n\tisDebugMode,\n\tlistenOnProcessTermination,\n\tprintStartInfo,\n\tresolveServerConfig,\n\tserverConfigSchema,\n\tTerminationJob,\n} from '@contember/engine-http'\nimport loadPlugins from './loadPlugins'\nimport cluster from 'node:cluster'\nimport * as os from 'node:os'\nimport { timeout } from './utils'\nimport { getClusterProcessType, notifyWorkerStarted, WorkerManager } from './cluster'\n\nconst logger = createDefaultLogger()\nprocess.on('warning', message => {\n\tlogger.warn(message)\n})\n;(async () => {\n\tconst isDebug = isDebugMode()\n\n\tconst version = await getServerVersion()\n\tprintStartInfo({ version, isDebug }, logger)\n\tconst plugins = await loadPlugins()\n\tconst { serverConfig, projectConfigResolver, tenantConfigResolver } = await resolveServerConfig({ plugins, serverConfigSchema })\n\n\tif (process.argv[2] === 'validate') {\n\t\tprocess.exit(0)\n\t}\n\n\tconst sentryhandler = createSentryLoggerHandler(serverConfig.logging?.sentry?.dsn)\n\tif (sentryhandler !== null) {\n\t\tlogger.addHandler(sentryhandler)\n\t}\n\n\tconst workerConfig = serverConfig.workerCount || 1\n\n\tconst workerCount = workerConfig === 'auto' ? os.cpus().length : Number(workerConfig)\n\tconst isClusterMode = serverConfig.workerCount !== undefined\n\n\tconst processType = getClusterProcessType(isClusterMode)\n\n\tconst container = createContainer({\n\t\tdebugMode: isDebug,\n\t\tserverConfig,\n\t\tprojectConfigResolver,\n\t\ttenantConfigResolver,\n\t\tplugins,\n\t\tprocessType,\n\t\tversion,\n\t\tlogger,\n\t})\n\n\tlet initializedProjects: string[] = []\n\tconst terminationJobs: TerminationJob[] = []\n\tlistenOnProcessTermination(terminationJobs, logger)\n\n\tif (cluster.isMaster) {\n\t\tconst monitoringPort = serverConfig.monitoringPort\n\t\tconst monitoringServer = container.monitoringKoa.listen(monitoringPort, () => {\n\t\t\tlogger.info(`Monitoring running on http://localhost:${monitoringPort}`)\n\t\t})\n\t\tterminationJobs.push(async () => {\n\t\t\tawait new Promise<any>(resolve => monitoringServer.close(resolve))\n\t\t\tlogger.info('Monitoring server terminated')\n\t\t})\n\t\tif (!serverConfig.projectGroup) {\n\t\t\tinitializedProjects = await container.initializer.initialize()\n\t\t}\n\t}\n\n\tconst port = serverConfig.port\n\tconst printStarted = () => {\n\t\tif (serverConfig.projectGroup) {\n\t\t\tlogger.info('Contember Cloud running')\n\t\t} else {\n\t\t\tlogger.info(`Contember API running on http://localhost:${port}`)\n\t\t}\n\t\tif (initializedProjects.length) {\n\t\t\tlogger.info(`Initialized projects: ${initializedProjects.join(', ')}`)\n\t\t}\n\t}\n\n\tconst startApplication = async () => {\n\t\tconst httpServerPromise = container.application.listen()\n\t\tterminationJobs.push(async () => {\n\t\t\tawait (await httpServerPromise).close()\n\t\t\tlogger.info('API server terminated')\n\t\t})\n\t\tawait httpServerPromise\n\t}\n\n\tconst startWorker = async (workerName: string) => {\n\t\tconst worker = container.applicationWorkers.getWorker(workerName)\n\t\tconst runningWorker = worker.run({\n\t\t\tlogger,\n\t\t\tonError: e => {\n\t\t\t\tlogger.crit(e)\n\t\t\t\tprocess.exit(1)\n\t\t\t},\n\t\t})\n\t\tterminationJobs.push(async () => {\n\t\t\t;(await runningWorker).end()\n\t\t})\n\t\tawait runningWorker\n\t\tlogger.info(`Contember Worker ${workerName} started.`)\n\t}\n\n\tconst applicationWorker = serverConfig.applicationWorker\n\tif (applicationWorker && applicationWorker !== 'all') {\n\t\tawait startWorker(applicationWorker)\n\t\tif (isClusterMode) {\n\t\t\tnotifyWorkerStarted()\n\t\t}\n\t} else if (isClusterMode) {\n\t\tif (cluster.isMaster) {\n\t\t\tlogger.info(`Master ${process.pid} is running`)\n\t\t\tconst workerManager = new WorkerManager()\n\t\t\tterminationJobs.push(async ({ signal }) => {\n\t\t\t\tawait workerManager.terminate(signal)\n\t\t\t\tlogger.info('Workers terminated')\n\t\t\t})\n\n\t\t\tawait workerManager.start({ workerCount })\n\n\t\t\tif (applicationWorker === 'all') {\n\t\t\t\tfor (const workerName of container.applicationWorkers.getWorkerNames()) {\n\t\t\t\t\tawait workerManager.start({\n\t\t\t\t\t\tworkerCount,\n\t\t\t\t\t\tenv: {\n\t\t\t\t\t\t\tCONTEMBER_APPLICATION_WORKER: workerName,\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t\tprintStarted()\n\t\t} else {\n\t\t\tlogger.info(`Starting worker ${process.pid}`)\n\n\t\t\t// this line somehow ensures, that worker waits for termination of all jobs\n\t\t\tprocess.on('disconnect', () => timeout(0))\n\n\t\t\tawait startApplication()\n\t\t\tnotifyWorkerStarted()\n\t\t}\n\t} else {\n\t\tawait startApplication()\n\t\tif (applicationWorker === 'all') {\n\t\t\tfor (const workerName of container.applicationWorkers.getWorkerNames()) {\n\t\t\t\tawait startWorker(workerName)\n\t\t\t}\n\t\t}\n\t\tprintStarted()\n\t}\n})().catch(e => {\n\tlogger.crit(e)\n\tprocess.exit(1)\n})\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"cluster.d.ts","sourceRoot":"","sources":["../../src/cluster.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAG9C,eAAO,MAAM,qBAAqB,GAAI,eAAe,OAAO,KAAG,WACsB,CAAA;AAErF,MAAM,MAAM,WAAW,GACpB,YAAY,GACZ,eAAe,GACf,eAAe,CAAA;AAIlB,eAAO,MAAM,aAAa,GAAI,QAAQ,MAAM,EAAE,WAAW,MAAM,qBAoB9D,CAAA;AAED,eAAO,MAAM,mBAAmB,2BAG7B,CAAA;AAEH,qBAAa,aAAa;IAEzB,OAAO,CAAC,aAAa,CAAQ;IAE7B,OAAO,CAAC,OAAO,CAAyB;IAE3B,KAAK,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;YAY7E,WAAW;IAeZ,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAqB7D"}
1
+ {"version":3,"file":"cluster.d.ts","sourceRoot":"","sources":["../../src/cluster.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAG9C,eAAO,MAAM,qBAAqB,GAAI,eAAe,OAAO,KAAG,WACsB,CAAA;AAErF,MAAM,MAAM,WAAW,GACpB,YAAY,GACZ,eAAe,GACf,eAAe,CAAA;AAIlB,eAAO,MAAM,aAAa,GAAI,QAAQ,MAAM,EAAE,WAAW,MAAM,qBAoB9D,CAAA;AAED,eAAO,MAAM,mBAAmB,2BAG7B,CAAA;AAEH,qBAAa,aAAa;IACzB,OAAO,CAAC,aAAa,CAAQ;IAE7B,OAAO,CAAC,OAAO,CAAyB;IAE3B,KAAK,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;YAY7E,WAAW;IAcZ,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAqB7D"}