@contember/engine-server 2.2.0-alpha.1 → 2.2.0-alpha.10

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.
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  const ActionsPlugin = require("@contember/engine-actions");
3
+ const PanelPlugin = require("@contember/engine-panel");
3
4
  const S3Plugin = require("@contember/engine-s3-plugin");
4
5
  const VimeoPlugin = require("@contember/engine-vimeo-plugin");
5
6
  function loadPlugins() {
6
- return Promise.resolve([new S3Plugin(), new VimeoPlugin(), new ActionsPlugin()]);
7
+ return Promise.resolve([new S3Plugin(), new VimeoPlugin(), new ActionsPlugin(), new PanelPlugin()]);
7
8
  }
8
9
  module.exports = loadPlugins;
9
10
  //# sourceMappingURL=loadPlugins.cjs.map
@@ -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,SAAA,GAAY,IAAI,YAAA,GAAe,IAAI,cAAA,CAAe,CAAC;AAChF;;"}
1
+ {"version":3,"file":"loadPlugins.cjs","sources":["../../../../packages/engine-server/src/loadPlugins.ts"],"sourcesContent":["import ActionsPlugin from '@contember/engine-actions'\nimport PanelPlugin from '@contember/engine-panel'\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(), new PanelPlugin()])\n}\n"],"names":[],"mappings":";;;;;AAMA,SAAwB,cAAiC;AACxD,SAAO,QAAQ,QAAQ,CAAC,IAAI,YAAY,IAAI,YAAA,GAAe,IAAI,cAAA,GAAiB,IAAI,YAAA,CAAa,CAAC;AACnG;;"}
@@ -1,8 +1,9 @@
1
1
  import ActionsPlugin from "@contember/engine-actions";
2
+ import PanelPlugin from "@contember/engine-panel";
2
3
  import S3Plugin from "@contember/engine-s3-plugin";
3
4
  import VimeoPlugin from "@contember/engine-vimeo-plugin";
4
5
  function loadPlugins() {
5
- return Promise.resolve([new S3Plugin(), new VimeoPlugin(), new ActionsPlugin()]);
6
+ return Promise.resolve([new S3Plugin(), new VimeoPlugin(), new ActionsPlugin(), new PanelPlugin()]);
6
7
  }
7
8
  export {
8
9
  loadPlugins as default
@@ -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,SAAA,GAAY,IAAI,YAAA,GAAe,IAAI,cAAA,CAAe,CAAC;AAChF;"}
1
+ {"version":3,"file":"loadPlugins.js","sources":["../../../../packages/engine-server/src/loadPlugins.ts"],"sourcesContent":["import ActionsPlugin from '@contember/engine-actions'\nimport PanelPlugin from '@contember/engine-panel'\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(), new PanelPlugin()])\n}\n"],"names":[],"mappings":";;;;AAMA,SAAwB,cAAiC;AACxD,SAAO,QAAQ,QAAQ,CAAC,IAAI,YAAY,IAAI,YAAA,GAAe,IAAI,cAAA,GAAiB,IAAI,YAAA,CAAa,CAAC;AACnG;"}
@@ -32,7 +32,7 @@ process.on("warning", (message) => {
32
32
  const version = await engineHttp.getServerVersion();
33
33
  engineHttp.printStartInfo({ version, isDebug }, logger);
34
34
  const plugins = await loadPlugins();
35
- const { serverConfig, projectConfigResolver, tenantConfigResolver } = await engineHttp.resolveServerConfig({ plugins, serverConfigSchema: engineHttp.serverConfigSchema });
35
+ const { serverConfig, projectConfigResolver, tenantConfigResolver, env } = await engineHttp.resolveServerConfig({ plugins, serverConfigSchema: engineHttp.serverConfigSchema });
36
36
  if (process.argv[2] === "validate") {
37
37
  process.exit(0);
38
38
  }
@@ -40,6 +40,7 @@ process.on("warning", (message) => {
40
40
  if (sentryhandler !== null) {
41
41
  logger.addHandler(sentryhandler);
42
42
  }
43
+ const telemetry = engineHttp.createTelemetry({ config: serverConfig.telemetry, logger, env });
43
44
  const workerConfig = serverConfig.workerCount || 1;
44
45
  const workerCount = workerConfig === "auto" ? os__namespace.cpus().length : Number(workerConfig);
45
46
  const isClusterMode = serverConfig.workerCount !== void 0;
@@ -49,14 +50,48 @@ process.on("warning", (message) => {
49
50
  serverConfig,
50
51
  projectConfigResolver,
51
52
  tenantConfigResolver,
53
+ env,
52
54
  plugins,
53
55
  processType,
54
56
  version,
55
- logger
57
+ logger,
58
+ tracer: telemetry.tracer
56
59
  });
57
60
  let initializedProjects = [];
58
61
  const terminationJobs = [];
59
- engineHttp.listenOnProcessTermination(terminationJobs, logger);
62
+ const finalTerminationJobs = [];
63
+ engineHttp.listenOnProcessTermination(terminationJobs, logger, {
64
+ sigtermDelayMs: processType === "clusterWorker" ? 0 : serverConfig.shutdownDelayMs,
65
+ finalJobs: finalTerminationJobs
66
+ });
67
+ const spanProcessor = telemetry.processor;
68
+ if (spanProcessor !== void 0) {
69
+ terminationJobs.push(async () => {
70
+ let timer;
71
+ let flushed = false;
72
+ try {
73
+ await Promise.race([
74
+ spanProcessor.forceFlush().then(() => {
75
+ flushed = true;
76
+ }),
77
+ new Promise((resolve) => {
78
+ timer = setTimeout(resolve, 5e3);
79
+ })
80
+ ]);
81
+ } finally {
82
+ if (timer !== void 0) {
83
+ clearTimeout(timer);
84
+ }
85
+ }
86
+ if (!flushed) {
87
+ logger.warn("Telemetry pre-shutdown flush timed out");
88
+ }
89
+ });
90
+ finalTerminationJobs.push(async () => {
91
+ await spanProcessor.shutdown();
92
+ logger.info("Telemetry shut down");
93
+ });
94
+ }
60
95
  if (cluster$1.isMaster) {
61
96
  const monitoringPort = serverConfig.monitoringPort;
62
97
  const monitoringServer = container.monitoringKoa.listen(monitoringPort, () => {
@@ -99,7 +134,7 @@ process.on("warning", (message) => {
99
134
  }
100
135
  });
101
136
  terminationJobs.push(async () => {
102
- (await runningWorker).end();
137
+ await (await runningWorker).end();
103
138
  });
104
139
  await runningWorker;
105
140
  logger.info(`Contember Worker ${workerName} started.`);
@@ -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.js'\nimport cluster from 'node:cluster'\nimport * as os from 'node:os'\nimport { timeout } from './utils.js'\nimport { getClusterProcessType, notifyWorkerStarted, WorkerManager } from './cluster.js'\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
+ {"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\tcreateTelemetry,\n\tgetServerVersion,\n\tisDebugMode,\n\tlistenOnProcessTermination,\n\tprintStartInfo,\n\tresolveServerConfig,\n\tserverConfigSchema,\n\tTerminationJob,\n} from '@contember/engine-http'\nimport loadPlugins from './loadPlugins.js'\nimport cluster from 'node:cluster'\nimport * as os from 'node:os'\nimport { timeout } from './utils.js'\nimport { getClusterProcessType, notifyWorkerStarted, WorkerManager } from './cluster.js'\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, env } = 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 telemetry = createTelemetry({ config: serverConfig.telemetry, logger, env })\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\tenv,\n\t\tplugins,\n\t\tprocessType,\n\t\tversion,\n\t\tlogger,\n\t\ttracer: telemetry.tracer,\n\t})\n\n\tlet initializedProjects: string[] = []\n\tconst terminationJobs: TerminationJob[] = []\n\tconst finalTerminationJobs: TerminationJob[] = []\n\t// A cluster worker is signalled by the master, which has already served the delay.\n\tlistenOnProcessTermination(terminationJobs, logger, {\n\t\tsigtermDelayMs: processType === 'clusterWorker' ? 0 : serverConfig.shutdownDelayMs,\n\t\tfinalJobs: finalTerminationJobs,\n\t})\n\n\tconst spanProcessor = telemetry.processor\n\tif (spanProcessor !== undefined) {\n\t\tterminationJobs.push(async () => {\n\t\t\tlet timer: ReturnType<typeof setTimeout> | undefined\n\t\t\tlet flushed = false\n\t\t\ttry {\n\t\t\t\tawait Promise.race([\n\t\t\t\t\tspanProcessor.forceFlush().then(() => {\n\t\t\t\t\t\tflushed = true\n\t\t\t\t\t}),\n\t\t\t\t\tnew Promise<void>(resolve => {\n\t\t\t\t\t\ttimer = setTimeout(resolve, 5000)\n\t\t\t\t\t}),\n\t\t\t\t])\n\t\t\t} finally {\n\t\t\t\tif (timer !== undefined) {\n\t\t\t\t\tclearTimeout(timer)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!flushed) {\n\t\t\t\tlogger.warn('Telemetry pre-shutdown flush timed out')\n\t\t\t}\n\t\t})\n\t\tfinalTerminationJobs.push(async () => {\n\t\t\tawait spanProcessor.shutdown()\n\t\t\tlogger.info('Telemetry shut down')\n\t\t})\n\t}\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\tawait (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","createTelemetry","os","getClusterProcessType","createContainer","listenOnProcessTermination","cluster","notifyWorkerStarted","WorkerManager","timeout"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { createDefaultLogger, isDebugMode, getServerVersion, printStartInfo, resolveServerConfig, serverConfigSchema, createSentryLoggerHandler, createContainer, listenOnProcessTermination } from "@contember/engine-http";
2
+ import { createDefaultLogger, isDebugMode, getServerVersion, printStartInfo, resolveServerConfig, serverConfigSchema, createSentryLoggerHandler, createTelemetry, createContainer, listenOnProcessTermination } from "@contember/engine-http";
3
3
  import loadPlugins from "./src/loadPlugins.js";
4
4
  import cluster from "node:cluster";
5
5
  import * as os from "node:os";
@@ -14,7 +14,7 @@ process.on("warning", (message) => {
14
14
  const version = await getServerVersion();
15
15
  printStartInfo({ version, isDebug }, logger);
16
16
  const plugins = await loadPlugins();
17
- const { serverConfig, projectConfigResolver, tenantConfigResolver } = await resolveServerConfig({ plugins, serverConfigSchema });
17
+ const { serverConfig, projectConfigResolver, tenantConfigResolver, env } = await resolveServerConfig({ plugins, serverConfigSchema });
18
18
  if (process.argv[2] === "validate") {
19
19
  process.exit(0);
20
20
  }
@@ -22,6 +22,7 @@ process.on("warning", (message) => {
22
22
  if (sentryhandler !== null) {
23
23
  logger.addHandler(sentryhandler);
24
24
  }
25
+ const telemetry = createTelemetry({ config: serverConfig.telemetry, logger, env });
25
26
  const workerConfig = serverConfig.workerCount || 1;
26
27
  const workerCount = workerConfig === "auto" ? os.cpus().length : Number(workerConfig);
27
28
  const isClusterMode = serverConfig.workerCount !== void 0;
@@ -31,14 +32,48 @@ process.on("warning", (message) => {
31
32
  serverConfig,
32
33
  projectConfigResolver,
33
34
  tenantConfigResolver,
35
+ env,
34
36
  plugins,
35
37
  processType,
36
38
  version,
37
- logger
39
+ logger,
40
+ tracer: telemetry.tracer
38
41
  });
39
42
  let initializedProjects = [];
40
43
  const terminationJobs = [];
41
- listenOnProcessTermination(terminationJobs, logger);
44
+ const finalTerminationJobs = [];
45
+ listenOnProcessTermination(terminationJobs, logger, {
46
+ sigtermDelayMs: processType === "clusterWorker" ? 0 : serverConfig.shutdownDelayMs,
47
+ finalJobs: finalTerminationJobs
48
+ });
49
+ const spanProcessor = telemetry.processor;
50
+ if (spanProcessor !== void 0) {
51
+ terminationJobs.push(async () => {
52
+ let timer;
53
+ let flushed = false;
54
+ try {
55
+ await Promise.race([
56
+ spanProcessor.forceFlush().then(() => {
57
+ flushed = true;
58
+ }),
59
+ new Promise((resolve) => {
60
+ timer = setTimeout(resolve, 5e3);
61
+ })
62
+ ]);
63
+ } finally {
64
+ if (timer !== void 0) {
65
+ clearTimeout(timer);
66
+ }
67
+ }
68
+ if (!flushed) {
69
+ logger.warn("Telemetry pre-shutdown flush timed out");
70
+ }
71
+ });
72
+ finalTerminationJobs.push(async () => {
73
+ await spanProcessor.shutdown();
74
+ logger.info("Telemetry shut down");
75
+ });
76
+ }
42
77
  if (cluster.isMaster) {
43
78
  const monitoringPort = serverConfig.monitoringPort;
44
79
  const monitoringServer = container.monitoringKoa.listen(monitoringPort, () => {
@@ -81,7 +116,7 @@ process.on("warning", (message) => {
81
116
  }
82
117
  });
83
118
  terminationJobs.push(async () => {
84
- (await runningWorker).end();
119
+ await (await runningWorker).end();
85
120
  });
86
121
  await runningWorker;
87
122
  logger.info(`Contember Worker ${workerName} started.`);
@@ -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.js'\nimport cluster from 'node:cluster'\nimport * as os from 'node:os'\nimport { timeout } from './utils.js'\nimport { getClusterProcessType, notifyWorkerStarted, WorkerManager } from './cluster.js'\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
+ {"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\tcreateTelemetry,\n\tgetServerVersion,\n\tisDebugMode,\n\tlistenOnProcessTermination,\n\tprintStartInfo,\n\tresolveServerConfig,\n\tserverConfigSchema,\n\tTerminationJob,\n} from '@contember/engine-http'\nimport loadPlugins from './loadPlugins.js'\nimport cluster from 'node:cluster'\nimport * as os from 'node:os'\nimport { timeout } from './utils.js'\nimport { getClusterProcessType, notifyWorkerStarted, WorkerManager } from './cluster.js'\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, env } = 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 telemetry = createTelemetry({ config: serverConfig.telemetry, logger, env })\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\tenv,\n\t\tplugins,\n\t\tprocessType,\n\t\tversion,\n\t\tlogger,\n\t\ttracer: telemetry.tracer,\n\t})\n\n\tlet initializedProjects: string[] = []\n\tconst terminationJobs: TerminationJob[] = []\n\tconst finalTerminationJobs: TerminationJob[] = []\n\t// A cluster worker is signalled by the master, which has already served the delay.\n\tlistenOnProcessTermination(terminationJobs, logger, {\n\t\tsigtermDelayMs: processType === 'clusterWorker' ? 0 : serverConfig.shutdownDelayMs,\n\t\tfinalJobs: finalTerminationJobs,\n\t})\n\n\tconst spanProcessor = telemetry.processor\n\tif (spanProcessor !== undefined) {\n\t\tterminationJobs.push(async () => {\n\t\t\tlet timer: ReturnType<typeof setTimeout> | undefined\n\t\t\tlet flushed = false\n\t\t\ttry {\n\t\t\t\tawait Promise.race([\n\t\t\t\t\tspanProcessor.forceFlush().then(() => {\n\t\t\t\t\t\tflushed = true\n\t\t\t\t\t}),\n\t\t\t\t\tnew Promise<void>(resolve => {\n\t\t\t\t\t\ttimer = setTimeout(resolve, 5000)\n\t\t\t\t\t}),\n\t\t\t\t])\n\t\t\t} finally {\n\t\t\t\tif (timer !== undefined) {\n\t\t\t\t\tclearTimeout(timer)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!flushed) {\n\t\t\t\tlogger.warn('Telemetry pre-shutdown flush timed out')\n\t\t\t}\n\t\t})\n\t\tfinalTerminationJobs.push(async () => {\n\t\t\tawait spanProcessor.shutdown()\n\t\t\tlogger.info('Telemetry shut down')\n\t\t})\n\t}\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\tawait (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,9 +1,10 @@
1
1
  "use strict";
2
2
  const ActionsPlugin = require("@contember/engine-actions");
3
+ const PanelPlugin = require("@contember/engine-panel");
3
4
  const S3Plugin = require("@contember/engine-s3-plugin");
4
5
  const VimeoPlugin = require("@contember/engine-vimeo-plugin");
5
6
  function loadPlugins() {
6
- return Promise.resolve([new S3Plugin(), new VimeoPlugin(), new ActionsPlugin()]);
7
+ return Promise.resolve([new S3Plugin(), new VimeoPlugin(), new ActionsPlugin(), new PanelPlugin()]);
7
8
  }
8
9
  module.exports = loadPlugins;
9
10
  //# sourceMappingURL=loadPlugins.cjs.map
@@ -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,SAAA,GAAY,IAAI,YAAA,GAAe,IAAI,cAAA,CAAe,CAAC;AAChF;;"}
1
+ {"version":3,"file":"loadPlugins.cjs","sources":["../../../../packages/engine-server/src/loadPlugins.ts"],"sourcesContent":["import ActionsPlugin from '@contember/engine-actions'\nimport PanelPlugin from '@contember/engine-panel'\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(), new PanelPlugin()])\n}\n"],"names":[],"mappings":";;;;;AAMA,SAAwB,cAAiC;AACxD,SAAO,QAAQ,QAAQ,CAAC,IAAI,YAAY,IAAI,YAAA,GAAe,IAAI,cAAA,GAAiB,IAAI,YAAA,CAAa,CAAC;AACnG;;"}
@@ -1,8 +1,9 @@
1
1
  import ActionsPlugin from "@contember/engine-actions";
2
+ import PanelPlugin from "@contember/engine-panel";
2
3
  import S3Plugin from "@contember/engine-s3-plugin";
3
4
  import VimeoPlugin from "@contember/engine-vimeo-plugin";
4
5
  function loadPlugins() {
5
- return Promise.resolve([new S3Plugin(), new VimeoPlugin(), new ActionsPlugin()]);
6
+ return Promise.resolve([new S3Plugin(), new VimeoPlugin(), new ActionsPlugin(), new PanelPlugin()]);
6
7
  }
7
8
  export {
8
9
  loadPlugins as default
@@ -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,SAAA,GAAY,IAAI,YAAA,GAAe,IAAI,cAAA,CAAe,CAAC;AAChF;"}
1
+ {"version":3,"file":"loadPlugins.js","sources":["../../../../packages/engine-server/src/loadPlugins.ts"],"sourcesContent":["import ActionsPlugin from '@contember/engine-actions'\nimport PanelPlugin from '@contember/engine-panel'\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(), new PanelPlugin()])\n}\n"],"names":[],"mappings":";;;;AAMA,SAAwB,cAAiC;AACxD,SAAO,QAAQ,QAAQ,CAAC,IAAI,YAAY,IAAI,YAAA,GAAe,IAAI,cAAA,GAAiB,IAAI,YAAA,CAAa,CAAC;AACnG;"}
@@ -32,7 +32,7 @@ process.on("warning", (message) => {
32
32
  const version = await engineHttp.getServerVersion();
33
33
  engineHttp.printStartInfo({ version, isDebug }, logger);
34
34
  const plugins = await loadPlugins();
35
- const { serverConfig, projectConfigResolver, tenantConfigResolver } = await engineHttp.resolveServerConfig({ plugins, serverConfigSchema: engineHttp.serverConfigSchema });
35
+ const { serverConfig, projectConfigResolver, tenantConfigResolver, env } = await engineHttp.resolveServerConfig({ plugins, serverConfigSchema: engineHttp.serverConfigSchema });
36
36
  if (process.argv[2] === "validate") {
37
37
  process.exit(0);
38
38
  }
@@ -40,6 +40,7 @@ process.on("warning", (message) => {
40
40
  if (sentryhandler !== null) {
41
41
  logger.addHandler(sentryhandler);
42
42
  }
43
+ const telemetry = engineHttp.createTelemetry({ config: serverConfig.telemetry, logger, env });
43
44
  const workerConfig = serverConfig.workerCount || 1;
44
45
  const workerCount = workerConfig === "auto" ? os__namespace.cpus().length : Number(workerConfig);
45
46
  const isClusterMode = serverConfig.workerCount !== void 0;
@@ -49,14 +50,48 @@ process.on("warning", (message) => {
49
50
  serverConfig,
50
51
  projectConfigResolver,
51
52
  tenantConfigResolver,
53
+ env,
52
54
  plugins,
53
55
  processType,
54
56
  version,
55
- logger
57
+ logger,
58
+ tracer: telemetry.tracer
56
59
  });
57
60
  let initializedProjects = [];
58
61
  const terminationJobs = [];
59
- engineHttp.listenOnProcessTermination(terminationJobs, logger);
62
+ const finalTerminationJobs = [];
63
+ engineHttp.listenOnProcessTermination(terminationJobs, logger, {
64
+ sigtermDelayMs: processType === "clusterWorker" ? 0 : serverConfig.shutdownDelayMs,
65
+ finalJobs: finalTerminationJobs
66
+ });
67
+ const spanProcessor = telemetry.processor;
68
+ if (spanProcessor !== void 0) {
69
+ terminationJobs.push(async () => {
70
+ let timer;
71
+ let flushed = false;
72
+ try {
73
+ await Promise.race([
74
+ spanProcessor.forceFlush().then(() => {
75
+ flushed = true;
76
+ }),
77
+ new Promise((resolve) => {
78
+ timer = setTimeout(resolve, 5e3);
79
+ })
80
+ ]);
81
+ } finally {
82
+ if (timer !== void 0) {
83
+ clearTimeout(timer);
84
+ }
85
+ }
86
+ if (!flushed) {
87
+ logger.warn("Telemetry pre-shutdown flush timed out");
88
+ }
89
+ });
90
+ finalTerminationJobs.push(async () => {
91
+ await spanProcessor.shutdown();
92
+ logger.info("Telemetry shut down");
93
+ });
94
+ }
60
95
  if (cluster$1.isMaster) {
61
96
  const monitoringPort = serverConfig.monitoringPort;
62
97
  const monitoringServer = container.monitoringKoa.listen(monitoringPort, () => {
@@ -99,7 +134,7 @@ process.on("warning", (message) => {
99
134
  }
100
135
  });
101
136
  terminationJobs.push(async () => {
102
- (await runningWorker).end();
137
+ await (await runningWorker).end();
103
138
  });
104
139
  await runningWorker;
105
140
  logger.info(`Contember Worker ${workerName} started.`);
@@ -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.js'\nimport cluster from 'node:cluster'\nimport * as os from 'node:os'\nimport { timeout } from './utils.js'\nimport { getClusterProcessType, notifyWorkerStarted, WorkerManager } from './cluster.js'\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
+ {"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\tcreateTelemetry,\n\tgetServerVersion,\n\tisDebugMode,\n\tlistenOnProcessTermination,\n\tprintStartInfo,\n\tresolveServerConfig,\n\tserverConfigSchema,\n\tTerminationJob,\n} from '@contember/engine-http'\nimport loadPlugins from './loadPlugins.js'\nimport cluster from 'node:cluster'\nimport * as os from 'node:os'\nimport { timeout } from './utils.js'\nimport { getClusterProcessType, notifyWorkerStarted, WorkerManager } from './cluster.js'\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, env } = 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 telemetry = createTelemetry({ config: serverConfig.telemetry, logger, env })\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\tenv,\n\t\tplugins,\n\t\tprocessType,\n\t\tversion,\n\t\tlogger,\n\t\ttracer: telemetry.tracer,\n\t})\n\n\tlet initializedProjects: string[] = []\n\tconst terminationJobs: TerminationJob[] = []\n\tconst finalTerminationJobs: TerminationJob[] = []\n\t// A cluster worker is signalled by the master, which has already served the delay.\n\tlistenOnProcessTermination(terminationJobs, logger, {\n\t\tsigtermDelayMs: processType === 'clusterWorker' ? 0 : serverConfig.shutdownDelayMs,\n\t\tfinalJobs: finalTerminationJobs,\n\t})\n\n\tconst spanProcessor = telemetry.processor\n\tif (spanProcessor !== undefined) {\n\t\tterminationJobs.push(async () => {\n\t\t\tlet timer: ReturnType<typeof setTimeout> | undefined\n\t\t\tlet flushed = false\n\t\t\ttry {\n\t\t\t\tawait Promise.race([\n\t\t\t\t\tspanProcessor.forceFlush().then(() => {\n\t\t\t\t\t\tflushed = true\n\t\t\t\t\t}),\n\t\t\t\t\tnew Promise<void>(resolve => {\n\t\t\t\t\t\ttimer = setTimeout(resolve, 5000)\n\t\t\t\t\t}),\n\t\t\t\t])\n\t\t\t} finally {\n\t\t\t\tif (timer !== undefined) {\n\t\t\t\t\tclearTimeout(timer)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!flushed) {\n\t\t\t\tlogger.warn('Telemetry pre-shutdown flush timed out')\n\t\t\t}\n\t\t})\n\t\tfinalTerminationJobs.push(async () => {\n\t\t\tawait spanProcessor.shutdown()\n\t\t\tlogger.info('Telemetry shut down')\n\t\t})\n\t}\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\tawait (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","createTelemetry","os","getClusterProcessType","createContainer","listenOnProcessTermination","cluster","notifyWorkerStarted","WorkerManager","timeout"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAqBA,MAAM,SAASA,WAAAA,oBAAA;AACf,QAAQ,GAAG,WAAW,CAAA,YAAW;AAChC,SAAO,KAAK,OAAO;AACpB,CAAC;AAAA,CACC,YAAY;AACb,QAAM,UAAUC,WAAAA,YAAA;AAEhB,QAAM,UAAU,MAAMC,4BAAA;AACtBC,aAAAA,eAAe,EAAE,SAAS,QAAA,GAAW,MAAM;AAC3C,QAAM,UAAU,MAAM,YAAA;AACtB,QAAM,EAAE,cAAc,uBAAuB,sBAAsB,QAAQ,MAAMC,+BAAoB,EAAE,SAAA,oBAASC,WAAAA,oBAAoB;AAEpI,MAAI,QAAQ,KAAK,CAAC,MAAM,YAAY;AACnC,YAAQ,KAAK,CAAC;AAAA,EACf;AAEA,QAAM,gBAAgBC,WAAAA,0BAA0B,aAAa,SAAS,QAAQ,GAAG;AACjF,MAAI,kBAAkB,MAAM;AAC3B,WAAO,WAAW,aAAa;AAAA,EAChC;AAEA,QAAM,YAAYC,WAAAA,gBAAgB,EAAE,QAAQ,aAAa,WAAW,QAAQ,KAAK;AAEjF,QAAM,eAAe,aAAa,eAAe;AAEjD,QAAM,cAAc,iBAAiB,SAASC,cAAG,OAAO,SAAS,OAAO,YAAY;AACpF,QAAM,gBAAgB,aAAa,gBAAgB;AAEnD,QAAM,cAAcC,QAAAA,sBAAsB,aAAa;AAEvD,QAAM,YAAYC,WAAAA,gBAAgB;AAAA,IACjC,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,UAAU;AAAA,EAAA,CAClB;AAED,MAAI,sBAAgC,CAAA;AACpC,QAAM,kBAAoC,CAAA;AAC1C,QAAM,uBAAyC,CAAA;AAE/CC,aAAAA,2BAA2B,iBAAiB,QAAQ;AAAA,IACnD,gBAAgB,gBAAgB,kBAAkB,IAAI,aAAa;AAAA,IACnE,WAAW;AAAA,EAAA,CACX;AAED,QAAM,gBAAgB,UAAU;AAChC,MAAI,kBAAkB,QAAW;AAChC,oBAAgB,KAAK,YAAY;AAChC,UAAI;AACJ,UAAI,UAAU;AACd,UAAI;AACH,cAAM,QAAQ,KAAK;AAAA,UAClB,cAAc,aAAa,KAAK,MAAM;AACrC,sBAAU;AAAA,UACX,CAAC;AAAA,UACD,IAAI,QAAc,CAAA,YAAW;AAC5B,oBAAQ,WAAW,SAAS,GAAI;AAAA,UACjC,CAAC;AAAA,QAAA,CACD;AAAA,MACF,UAAA;AACC,YAAI,UAAU,QAAW;AACxB,uBAAa,KAAK;AAAA,QACnB;AAAA,MACD;AACA,UAAI,CAAC,SAAS;AACb,eAAO,KAAK,wCAAwC;AAAA,MACrD;AAAA,IACD,CAAC;AACD,yBAAqB,KAAK,YAAY;AACrC,YAAM,cAAc,SAAA;AACpB,aAAO,KAAK,qBAAqB;AAAA,IAClC,CAAC;AAAA,EACF;AAEA,MAAIC,UAAQ,UAAU;AACrB,UAAM,iBAAiB,aAAa;AACpC,UAAM,mBAAmB,UAAU,cAAc,OAAO,gBAAgB,MAAM;AAC7E,aAAO,KAAK,0CAA0C,cAAc,EAAE;AAAA,IACvE,CAAC;AACD,oBAAgB,KAAK,YAAY;AAChC,YAAM,IAAI,QAAa,CAAA,YAAW,iBAAiB,MAAM,OAAO,CAAC;AACjE,aAAO,KAAK,8BAA8B;AAAA,IAC3C,CAAC;AACD,QAAI,CAAC,aAAa,cAAc;AAC/B,4BAAsB,MAAM,UAAU,YAAY,WAAA;AAAA,IACnD;AAAA,EACD;AAEA,QAAM,OAAO,aAAa;AAC1B,QAAM,eAAe,MAAM;AAC1B,QAAI,aAAa,cAAc;AAC9B,aAAO,KAAK,yBAAyB;AAAA,IACtC,OAAO;AACN,aAAO,KAAK,6CAA6C,IAAI,EAAE;AAAA,IAChE;AACA,QAAI,oBAAoB,QAAQ;AAC/B,aAAO,KAAK,yBAAyB,oBAAoB,KAAK,IAAI,CAAC,EAAE;AAAA,IACtE;AAAA,EACD;AAEA,QAAM,mBAAmB,YAAY;AACpC,UAAM,oBAAoB,UAAU,YAAY,OAAA;AAChD,oBAAgB,KAAK,YAAY;AAChC,aAAO,MAAM,mBAAmB,MAAA;AAChC,aAAO,KAAK,uBAAuB;AAAA,IACpC,CAAC;AACD,UAAM;AAAA,EACP;AAEA,QAAM,cAAc,OAAO,eAAuB;AACjD,UAAM,SAAS,UAAU,mBAAmB,UAAU,UAAU;AAChE,UAAM,gBAAgB,OAAO,IAAI;AAAA,MAChC;AAAA,MACA,SAAS,CAAA,MAAK;AACb,eAAO,KAAK,CAAC;AACb,gBAAQ,KAAK,CAAC;AAAA,MACf;AAAA,IAAA,CACA;AACD,oBAAgB,KAAK,YAAY;AAChC,aAAO,MAAM,eAAe,IAAA;AAAA,IAC7B,CAAC;AACD,UAAM;AACN,WAAO,KAAK,oBAAoB,UAAU,WAAW;AAAA,EACtD;AAEA,QAAM,oBAAoB,aAAa;AACvC,MAAI,qBAAqB,sBAAsB,OAAO;AACrD,UAAM,YAAY,iBAAiB;AACnC,QAAI,eAAe;AAClBC,kCAAA;AAAA,IACD;AAAA,EACD,WAAW,eAAe;AACzB,QAAID,UAAQ,UAAU;AACrB,aAAO,KAAK,UAAU,QAAQ,GAAG,aAAa;AAC9C,YAAM,gBAAgB,IAAIE,sBAAA;AAC1B,sBAAgB,KAAK,OAAO,EAAE,aAAa;AAC1C,cAAM,cAAc,UAAU,MAAM;AACpC,eAAO,KAAK,oBAAoB;AAAA,MACjC,CAAC;AAED,YAAM,cAAc,MAAM,EAAE,aAAa;AAEzC,UAAI,sBAAsB,OAAO;AAChC,mBAAW,cAAc,UAAU,mBAAmB,eAAA,GAAkB;AACvE,gBAAM,cAAc,MAAM;AAAA,YACzB;AAAA,YACA,KAAK;AAAA,cACJ,8BAA8B;AAAA,YAAA;AAAA,UAC/B,CACA;AAAA,QACF;AAAA,MACD;AACA,mBAAA;AAAA,IACD,OAAO;AACN,aAAO,KAAK,mBAAmB,QAAQ,GAAG,EAAE;AAG5C,cAAQ,GAAG,cAAc,MAAMC,MAAAA,QAAQ,CAAC,CAAC;AAEzC,YAAM,iBAAA;AACNF,kCAAA;AAAA,IACD;AAAA,EACD,OAAO;AACN,UAAM,iBAAA;AACN,QAAI,sBAAsB,OAAO;AAChC,iBAAW,cAAc,UAAU,mBAAmB,eAAA,GAAkB;AACvE,cAAM,YAAY,UAAU;AAAA,MAC7B;AAAA,IACD;AACA,iBAAA;AAAA,EACD;AACD,KAAK,MAAM,CAAA,MAAK;AACf,SAAO,KAAK,CAAC;AACb,UAAQ,KAAK,CAAC;AACf,CAAC;"}
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { createDefaultLogger, isDebugMode, getServerVersion, printStartInfo, resolveServerConfig, serverConfigSchema, createSentryLoggerHandler, createContainer, listenOnProcessTermination } from "@contember/engine-http";
2
+ import { createDefaultLogger, isDebugMode, getServerVersion, printStartInfo, resolveServerConfig, serverConfigSchema, createSentryLoggerHandler, createTelemetry, createContainer, listenOnProcessTermination } from "@contember/engine-http";
3
3
  import loadPlugins from "./src/loadPlugins.js";
4
4
  import cluster from "node:cluster";
5
5
  import * as os from "node:os";
@@ -14,7 +14,7 @@ process.on("warning", (message) => {
14
14
  const version = await getServerVersion();
15
15
  printStartInfo({ version, isDebug }, logger);
16
16
  const plugins = await loadPlugins();
17
- const { serverConfig, projectConfigResolver, tenantConfigResolver } = await resolveServerConfig({ plugins, serverConfigSchema });
17
+ const { serverConfig, projectConfigResolver, tenantConfigResolver, env } = await resolveServerConfig({ plugins, serverConfigSchema });
18
18
  if (process.argv[2] === "validate") {
19
19
  process.exit(0);
20
20
  }
@@ -22,6 +22,7 @@ process.on("warning", (message) => {
22
22
  if (sentryhandler !== null) {
23
23
  logger.addHandler(sentryhandler);
24
24
  }
25
+ const telemetry = createTelemetry({ config: serverConfig.telemetry, logger, env });
25
26
  const workerConfig = serverConfig.workerCount || 1;
26
27
  const workerCount = workerConfig === "auto" ? os.cpus().length : Number(workerConfig);
27
28
  const isClusterMode = serverConfig.workerCount !== void 0;
@@ -31,14 +32,48 @@ process.on("warning", (message) => {
31
32
  serverConfig,
32
33
  projectConfigResolver,
33
34
  tenantConfigResolver,
35
+ env,
34
36
  plugins,
35
37
  processType,
36
38
  version,
37
- logger
39
+ logger,
40
+ tracer: telemetry.tracer
38
41
  });
39
42
  let initializedProjects = [];
40
43
  const terminationJobs = [];
41
- listenOnProcessTermination(terminationJobs, logger);
44
+ const finalTerminationJobs = [];
45
+ listenOnProcessTermination(terminationJobs, logger, {
46
+ sigtermDelayMs: processType === "clusterWorker" ? 0 : serverConfig.shutdownDelayMs,
47
+ finalJobs: finalTerminationJobs
48
+ });
49
+ const spanProcessor = telemetry.processor;
50
+ if (spanProcessor !== void 0) {
51
+ terminationJobs.push(async () => {
52
+ let timer;
53
+ let flushed = false;
54
+ try {
55
+ await Promise.race([
56
+ spanProcessor.forceFlush().then(() => {
57
+ flushed = true;
58
+ }),
59
+ new Promise((resolve) => {
60
+ timer = setTimeout(resolve, 5e3);
61
+ })
62
+ ]);
63
+ } finally {
64
+ if (timer !== void 0) {
65
+ clearTimeout(timer);
66
+ }
67
+ }
68
+ if (!flushed) {
69
+ logger.warn("Telemetry pre-shutdown flush timed out");
70
+ }
71
+ });
72
+ finalTerminationJobs.push(async () => {
73
+ await spanProcessor.shutdown();
74
+ logger.info("Telemetry shut down");
75
+ });
76
+ }
42
77
  if (cluster.isMaster) {
43
78
  const monitoringPort = serverConfig.monitoringPort;
44
79
  const monitoringServer = container.monitoringKoa.listen(monitoringPort, () => {
@@ -81,7 +116,7 @@ process.on("warning", (message) => {
81
116
  }
82
117
  });
83
118
  terminationJobs.push(async () => {
84
- (await runningWorker).end();
119
+ await (await runningWorker).end();
85
120
  });
86
121
  await runningWorker;
87
122
  logger.info(`Contember Worker ${workerName} started.`);
@@ -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.js'\nimport cluster from 'node:cluster'\nimport * as os from 'node:os'\nimport { timeout } from './utils.js'\nimport { getClusterProcessType, notifyWorkerStarted, WorkerManager } from './cluster.js'\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
+ {"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\tcreateTelemetry,\n\tgetServerVersion,\n\tisDebugMode,\n\tlistenOnProcessTermination,\n\tprintStartInfo,\n\tresolveServerConfig,\n\tserverConfigSchema,\n\tTerminationJob,\n} from '@contember/engine-http'\nimport loadPlugins from './loadPlugins.js'\nimport cluster from 'node:cluster'\nimport * as os from 'node:os'\nimport { timeout } from './utils.js'\nimport { getClusterProcessType, notifyWorkerStarted, WorkerManager } from './cluster.js'\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, env } = 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 telemetry = createTelemetry({ config: serverConfig.telemetry, logger, env })\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\tenv,\n\t\tplugins,\n\t\tprocessType,\n\t\tversion,\n\t\tlogger,\n\t\ttracer: telemetry.tracer,\n\t})\n\n\tlet initializedProjects: string[] = []\n\tconst terminationJobs: TerminationJob[] = []\n\tconst finalTerminationJobs: TerminationJob[] = []\n\t// A cluster worker is signalled by the master, which has already served the delay.\n\tlistenOnProcessTermination(terminationJobs, logger, {\n\t\tsigtermDelayMs: processType === 'clusterWorker' ? 0 : serverConfig.shutdownDelayMs,\n\t\tfinalJobs: finalTerminationJobs,\n\t})\n\n\tconst spanProcessor = telemetry.processor\n\tif (spanProcessor !== undefined) {\n\t\tterminationJobs.push(async () => {\n\t\t\tlet timer: ReturnType<typeof setTimeout> | undefined\n\t\t\tlet flushed = false\n\t\t\ttry {\n\t\t\t\tawait Promise.race([\n\t\t\t\t\tspanProcessor.forceFlush().then(() => {\n\t\t\t\t\t\tflushed = true\n\t\t\t\t\t}),\n\t\t\t\t\tnew Promise<void>(resolve => {\n\t\t\t\t\t\ttimer = setTimeout(resolve, 5000)\n\t\t\t\t\t}),\n\t\t\t\t])\n\t\t\t} finally {\n\t\t\t\tif (timer !== undefined) {\n\t\t\t\t\tclearTimeout(timer)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!flushed) {\n\t\t\t\tlogger.warn('Telemetry pre-shutdown flush timed out')\n\t\t\t}\n\t\t})\n\t\tfinalTerminationJobs.push(async () => {\n\t\t\tawait spanProcessor.shutdown()\n\t\t\tlogger.info('Telemetry shut down')\n\t\t})\n\t}\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\tawait (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;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"}
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,kBAAmB,OAAO,KAAG,WACsB,CAAA;AAErF,MAAM,MAAM,WAAW,GACpB,YAAY,GACZ,eAAe,GACf,eAAe,CAAA;AAIlB,eAAO,MAAM,aAAa,WAAY,MAAM,aAAa,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,CAU1F;YAEa,WAAW;IAcZ,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAoB5D;CACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"loadPlugins.d.ts","sourceRoot":"","sources":["../../src/loadPlugins.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAA;AAIlD,MAAM,CAAC,OAAO,UAAU,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAEvD"}
1
+ {"version":3,"file":"loadPlugins.d.ts","sourceRoot":"","sources":["../../src/loadPlugins.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAA;AAIlD,MAAM,CAAC,OAAO,UAAU,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAEvD"}