@contember/engine-server 1.1.0-beta.3 → 1.2.0-alpha.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.
Files changed (126) hide show
  1. package/dist/src/MasterContainer.d.ts +12 -25
  2. package/dist/src/MasterContainer.d.ts.map +1 -1
  3. package/dist/src/MasterContainer.js +36 -80
  4. package/dist/src/MasterContainer.js.map +1 -1
  5. package/dist/src/bootstrap/Initializer.d.ts +3 -3
  6. package/dist/src/bootstrap/Initializer.d.ts.map +1 -1
  7. package/dist/src/bootstrap/Initializer.js +15 -6
  8. package/dist/src/bootstrap/Initializer.js.map +1 -1
  9. package/dist/src/config/config.d.ts +5 -4
  10. package/dist/src/config/config.d.ts.map +1 -1
  11. package/dist/src/config/config.js +2 -2
  12. package/dist/src/config/config.js.map +1 -1
  13. package/dist/src/config/configSchema.d.ts +45 -11
  14. package/dist/src/config/configSchema.d.ts.map +1 -1
  15. package/dist/src/config/configSchema.js +20 -18
  16. package/dist/src/config/configSchema.js.map +1 -1
  17. package/dist/src/config/configTemplate.d.ts.map +1 -1
  18. package/dist/src/config/configTemplate.js +23 -0
  19. package/dist/src/config/configTemplate.js.map +1 -1
  20. package/dist/src/index.d.ts +9 -3
  21. package/dist/src/index.d.ts.map +1 -1
  22. package/dist/src/index.js +23 -4
  23. package/dist/src/index.js.map +1 -1
  24. package/dist/src/project/ProjectContainer.js +1 -1
  25. package/dist/src/project/ProjectContainer.js.map +1 -1
  26. package/dist/src/project/ProjectContainerResolver.d.ts +6 -3
  27. package/dist/src/project/ProjectContainerResolver.d.ts.map +1 -1
  28. package/dist/src/project/ProjectContainerResolver.js +4 -16
  29. package/dist/src/project/ProjectContainerResolver.js.map +1 -1
  30. package/dist/src/projectGroup/ProjectGroupContainer.d.ts +2 -1
  31. package/dist/src/projectGroup/ProjectGroupContainer.d.ts.map +1 -1
  32. package/dist/src/projectGroup/ProjectGroupContainer.js +8 -4
  33. package/dist/src/projectGroup/ProjectGroupContainer.js.map +1 -1
  34. package/dist/src/projectGroup/ProjectGroupResolver.d.ts +7 -0
  35. package/dist/src/projectGroup/ProjectGroupResolver.d.ts.map +1 -0
  36. package/dist/src/projectGroup/ProjectGroupResolver.js +13 -0
  37. package/dist/src/projectGroup/ProjectGroupResolver.js.map +1 -0
  38. package/dist/src/start.js +15 -112
  39. package/dist/src/start.js.map +1 -1
  40. package/dist/src/tsconfig.tsbuildinfo +1 -1
  41. package/dist/src/utils/index.d.ts +0 -4
  42. package/dist/src/utils/index.d.ts.map +1 -1
  43. package/dist/src/utils/index.js +0 -4
  44. package/dist/src/utils/index.js.map +1 -1
  45. package/dist/src/utils/serverStartup.d.ts +31 -0
  46. package/dist/src/utils/serverStartup.d.ts.map +1 -0
  47. package/dist/src/utils/serverStartup.js +42 -0
  48. package/dist/src/utils/serverStartup.js.map +1 -0
  49. package/dist/src/utils/serverTermination.d.ts +12 -0
  50. package/dist/src/utils/serverTermination.d.ts.map +1 -0
  51. package/dist/src/utils/serverTermination.js +26 -0
  52. package/dist/src/utils/serverTermination.js.map +1 -0
  53. package/dist/tests/e2e/http.test.js +74 -157
  54. package/dist/tests/e2e/http.test.js.map +1 -1
  55. package/dist/tests/e2e/requests.d.ts +4 -0
  56. package/dist/tests/e2e/requests.d.ts.map +1 -0
  57. package/dist/tests/e2e/requests.js +59 -0
  58. package/dist/tests/e2e/requests.js.map +1 -0
  59. package/dist/tests/e2e/tester.d.ts +19 -0
  60. package/dist/tests/e2e/tester.d.ts.map +1 -0
  61. package/dist/tests/e2e/tester.js +99 -0
  62. package/dist/tests/e2e/tester.js.map +1 -0
  63. package/dist/tests/tsconfig.tsbuildinfo +1 -1
  64. package/esbuild.js +7 -14
  65. package/package.json +20 -20
  66. package/src/MasterContainer.ts +58 -110
  67. package/src/bootstrap/Initializer.ts +16 -6
  68. package/src/config/config.ts +7 -5
  69. package/src/config/configSchema.ts +30 -33
  70. package/src/config/configTemplate.ts +23 -0
  71. package/src/index.ts +15 -2
  72. package/src/project/ProjectContainer.ts +1 -1
  73. package/src/project/ProjectContainerResolver.ts +4 -17
  74. package/src/projectGroup/ProjectGroupContainer.ts +12 -3
  75. package/src/projectGroup/ProjectGroupResolver.ts +12 -0
  76. package/src/start.ts +18 -127
  77. package/src/utils/index.ts +0 -4
  78. package/src/utils/serverStartup.ts +42 -0
  79. package/src/utils/serverTermination.ts +20 -0
  80. package/tests/e2e/http.test.ts +84 -150
  81. package/tests/e2e/requests.ts +71 -0
  82. package/tests/e2e/tester.ts +118 -0
  83. package/alpine.dockerfile +0 -30
  84. package/debian.dockerfile +0 -27
  85. package/dist/src/http/CollectHttpMetricsMiddelware.d.ts +0 -5
  86. package/dist/src/http/CollectHttpMetricsMiddelware.d.ts.map +0 -1
  87. package/dist/src/http/CollectHttpMetricsMiddelware.js +0 -36
  88. package/dist/src/http/CollectHttpMetricsMiddelware.js.map +0 -1
  89. package/dist/src/http/ShowMetricsMiddleware.d.ts +0 -4
  90. package/dist/src/http/ShowMetricsMiddleware.d.ts.map +0 -1
  91. package/dist/src/http/ShowMetricsMiddleware.js +0 -20
  92. package/dist/src/http/ShowMetricsMiddleware.js.map +0 -1
  93. package/dist/src/http/index.d.ts +0 -3
  94. package/dist/src/http/index.d.ts.map +0 -1
  95. package/dist/src/http/index.js +0 -19
  96. package/dist/src/http/index.js.map +0 -1
  97. package/dist/src/projectGroup/ProjectGroupContainerResolver.d.ts +0 -12
  98. package/dist/src/projectGroup/ProjectGroupContainerResolver.d.ts.map +0 -1
  99. package/dist/src/projectGroup/ProjectGroupContainerResolver.js +0 -36
  100. package/dist/src/projectGroup/ProjectGroupContainerResolver.js.map +0 -1
  101. package/dist/src/utils/cluster.d.ts +0 -9
  102. package/dist/src/utils/cluster.d.ts.map +0 -1
  103. package/dist/src/utils/cluster.js +0 -47
  104. package/dist/src/utils/cluster.js.map +0 -1
  105. package/dist/src/utils/dbMetrics.d.ts +0 -16
  106. package/dist/src/utils/dbMetrics.d.ts.map +0 -1
  107. package/dist/src/utils/dbMetrics.js +0 -98
  108. package/dist/src/utils/dbMetrics.js.map +0 -1
  109. package/dist/src/utils/timeout.d.ts +0 -2
  110. package/dist/src/utils/timeout.d.ts.map +0 -1
  111. package/dist/src/utils/timeout.js +0 -8
  112. package/dist/src/utils/timeout.js.map +0 -1
  113. package/dist/src/utils/tuple.d.ts +0 -2
  114. package/dist/src/utils/tuple.d.ts.map +0 -1
  115. package/dist/src/utils/tuple.js +0 -6
  116. package/dist/src/utils/tuple.js.map +0 -1
  117. package/jasmine.json +0 -7
  118. package/src/http/CollectHttpMetricsMiddelware.ts +0 -32
  119. package/src/http/ShowMetricsMiddleware.ts +0 -12
  120. package/src/http/index.ts +0 -2
  121. package/src/projectGroup/ProjectGroupContainerResolver.ts +0 -47
  122. package/src/utils/cluster.ts +0 -40
  123. package/src/utils/dbMetrics.ts +0 -111
  124. package/src/utils/timeout.ts +0 -4
  125. package/src/utils/tuple.ts +0 -1
  126. package/tslint.json +0 -14
@@ -1,2 +0,0 @@
1
- export declare const tuple: <T extends unknown[]>(...args: T) => T;
2
- //# sourceMappingURL=tuple.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tuple.d.ts","sourceRoot":"","sources":["../../../src/utils/tuple.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,KAAK,wCAA4C,CAAA"}
@@ -1,6 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.tuple = void 0;
4
- const tuple = (...args) => args;
5
- exports.tuple = tuple;
6
- //# sourceMappingURL=tuple.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tuple.js","sourceRoot":"","sources":["../../../src/utils/tuple.ts"],"names":[],"mappings":";;;AAAO,MAAM,KAAK,GAAG,CAAsB,GAAG,IAAO,EAAE,EAAE,CAAC,IAAI,CAAA;AAAjD,QAAA,KAAK,SAA4C"}
package/jasmine.json DELETED
@@ -1,7 +0,0 @@
1
- {
2
- "spec_files": [
3
- "dist/tests/cases/**/*.js"
4
- ],
5
- "stopSpecOnExpectationFailure": false,
6
- "random": false
7
- }
@@ -1,32 +0,0 @@
1
- import { KoaMiddleware, ModuleInfoMiddlewareState, ProjectInfoMiddlewareState } from '@contember/engine-http'
2
- import prom from 'prom-client'
3
- import { GraphQLKoaState } from '@contember/engine-http'
4
-
5
- export const createColllectHttpMetricsMiddleware = (
6
- registry: prom.Registry,
7
- ): KoaMiddleware<Partial<ProjectInfoMiddlewareState & ModuleInfoMiddlewareState & GraphQLKoaState>> => {
8
- const requestSummary = new prom.Histogram({
9
- name: 'contember_http_duration_seconds',
10
- help: 'Incoming HTTP requests statistics by http_method (OPTIONS requests are ignored), http_code, contember_project (or "unknown" for undefined project), contember_project_group (or "unknown" for undefined project group), contember_module (system, tenant, content, unknown) and graphql_operation (query, mutation, unknown)',
11
- registers: [registry],
12
- labelNames: ['http_method', 'http_code', 'contember_project', 'contember_project_group', 'contember_module', 'graphql_operation'],
13
- buckets: [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10],
14
- })
15
-
16
- return async (ctx, next) => {
17
- const end = ctx.method === 'OPTIONS' ? () => null : requestSummary.startTimer()
18
- try {
19
- await next()
20
- } finally {
21
- const labels = {
22
- http_method: ctx.method,
23
- http_code: ctx.status,
24
- contember_project: ctx.state.project || 'unknown',
25
- contember_project_group: ctx.state.projectGroup || 'unknown',
26
- contember_module: ctx.state.module || 'unknown',
27
- graphql_operation: ctx.state.graphql?.operationName || 'unknown',
28
- }
29
- end(labels)
30
- }
31
- }
32
- }
@@ -1,12 +0,0 @@
1
- import { KoaMiddleware, route } from '@contember/engine-http'
2
- import prom from 'prom-client'
3
-
4
- export const createShowMetricsMiddleware = (registry: prom.Registry): KoaMiddleware<any> => {
5
- return route('/metrics', async ctx => {
6
- if (registry instanceof prom.AggregatorRegistry) {
7
- ctx.body = await registry.clusterMetrics()
8
- } else {
9
- ctx.body = registry.metrics()
10
- }
11
- })
12
- }
package/src/http/index.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from './CollectHttpMetricsMiddelware'
2
- export * from './ShowMetricsMiddleware'
@@ -1,47 +0,0 @@
1
- import { TenantConfigResolver } from '../config/tenantConfigResolver'
2
- import {
3
- ProjectGroupContainer,
4
- ProjectGroupContainerResolver as ProjectGroupContainerResolverInterface,
5
- } from '@contember/engine-http'
6
- import { ProjectGroupContainerFactory } from './ProjectGroupContainer'
7
- import { PromiseMap } from '@contember/engine-common'
8
- import { isDeepStrictEqual } from 'util'
9
-
10
- interface ContainerWithMeta {
11
- container: ProjectGroupContainer
12
- cleanups: (() => void)[]
13
- inputConfig: any
14
- }
15
-
16
- export class ProjectGroupContainerResolver implements ProjectGroupContainerResolverInterface {
17
- private containers = new PromiseMap<string | undefined, ContainerWithMeta>()
18
-
19
- public readonly onCreate: ((container: ProjectGroupContainer, slug: string | undefined) => void | (() => void))[] = []
20
-
21
- constructor(
22
- private readonly configResolver: TenantConfigResolver,
23
- private readonly containerFactory: ProjectGroupContainerFactory,
24
- ) {}
25
-
26
- public async getProjectGroupContainer(slug: string | undefined, config: any = {}): Promise<ProjectGroupContainer> {
27
- const existing = this.containers.get(slug)
28
- if (existing) {
29
- const existingAwaited = await existing
30
- if (isDeepStrictEqual(config, existingAwaited.inputConfig)) {
31
- return existingAwaited.container
32
- }
33
- existingAwaited.cleanups.forEach(it => it())
34
- this.containers.delete(slug)
35
- }
36
- return (await this.containers.fetch(slug, async slug => {
37
- const container = this.containerFactory.create({
38
- config: this.configResolver(slug, config),
39
- slug,
40
- })
41
- const cleanups = this.onCreate.map(it => it(container, slug) || (() => null))
42
- // eslint-disable-next-line no-console
43
- await container.tenantContainer.migrationsRunner.run(console.log)
44
- return { container, inputConfig: config, cleanups }
45
- })).container
46
- }
47
- }
@@ -1,40 +0,0 @@
1
- import cluster from 'cluster'
2
- import { timeout } from './timeout'
3
-
4
- export const getClusterProcessType = (isClusterMode: boolean) =>
5
- !isClusterMode ? ProcessType.singleNode : cluster.isMaster ? ProcessType.clusterMaster : ProcessType.clusterWorker
6
-
7
- export enum ProcessType {
8
- singleNode,
9
- clusterMaster,
10
- clusterWorker,
11
- }
12
-
13
- const MSG_WORKER_STARTED = 'msg_worker_started'
14
-
15
- export const waitForWorker = (timeoutMs: number) => {
16
- let ok = false
17
- return Promise.race([
18
- new Promise(async resolve => {
19
- const listener = ({}, message: any) => {
20
- if ('type' in message && message.type === MSG_WORKER_STARTED) {
21
- ok = true
22
- resolve(null)
23
- cluster.removeListener('message', listener)
24
- }
25
- }
26
- await cluster.on('message', listener)
27
- }),
28
- timeout(timeoutMs).then(() => {
29
- if (!ok) {
30
- throw new Error('Worker start timed out')
31
- }
32
- return true
33
- }),
34
- ])
35
- }
36
-
37
- export const notifyWorkerStarted = () =>
38
- process.send?.({
39
- type: MSG_WORKER_STARTED,
40
- })
@@ -1,111 +0,0 @@
1
- import prom from 'prom-client'
2
- import { Connection, EventManager } from '@contember/database'
3
-
4
- const labelNames = ['contember_project' as const, 'contember_module' as const, 'contember_project_group' as const]
5
- type LabelNames = typeof labelNames[number]
6
- type Labels = { [K in LabelNames]: string }
7
- type DatabaseMetricsEntry = {
8
- connection: Connection.PoolStatusProvider & Connection.Queryable
9
- labels: Labels
10
- }
11
- type Unregistrar = () => void
12
- type DatabaseMetricsRegistrar = (entry: DatabaseMetricsEntry) => Unregistrar
13
-
14
- export const createDbMetricsRegistrar = (registry: prom.Registry): DatabaseMetricsRegistrar => {
15
- const dbPoolCollectorInner = createSingleDbPoolMetricsCollector(registry)
16
- const entries = new Set<DatabaseMetricsEntry>()
17
- const collector = () => {
18
- for (const entry of entries) {
19
- dbPoolCollectorInner(entry.connection, entry.labels)
20
- }
21
- }
22
- registry.registerCollector(collector)
23
- const sqlMetricsRegistrar = createSqlMetricsRegistrar(registry)
24
- return entry => {
25
- entries.add(entry)
26
- const sqlMetricsUnregistrar = sqlMetricsRegistrar(entry.connection, entry.labels)
27
- return () => {
28
- entries.delete(entry)
29
- sqlMetricsUnregistrar()
30
- }
31
- }
32
- }
33
-
34
- const createSingleDbPoolMetricsCollector = (registry: prom.Registry) => {
35
-
36
- const totalCount = new prom.Gauge({
37
- registers: [registry],
38
- name: `contember_db_pool_total_count`,
39
- help: 'The total number of clients existing within the pool by contember_module (tenant or content; system is not used since it uses the same connection) and contember_project for contember_module=content.',
40
- labelNames,
41
- })
42
- const idleCount = new prom.Gauge({
43
- registers: [registry],
44
- name: `contember_db_pool_idle_count`,
45
- help: 'The number of clients which are not checked out but are currently idle in the pool by contember_module (tenant or content; system is not used since it uses the same connection) and contember_project for contember_module=content.',
46
- labelNames,
47
- })
48
- const waitingCount = new prom.Gauge({
49
- registers: [registry],
50
- name: `contember_db_pool_waiting_count`,
51
- help: 'The number of queued requests waiting on a client when all clients are checked out. It can be helpful to monitor this number to see if you need to adjust the size of the pool by contember_module (tenant or content; system is not used since it uses the same connection) and contember_project for contember_module=content.',
52
- labelNames,
53
- })
54
- const maxCount = new prom.Gauge({
55
- registers: [registry],
56
- name: `contember_db_pool_max_count`,
57
- help: 'Maximum number of clients the pool should contain by contember_module (tenant or content; system is not used since it uses the same connection) and contember_project for contember_module=content.',
58
- labelNames,
59
- })
60
-
61
- return (db: Connection.PoolStatusProvider, labels: Labels) => {
62
- const poolInfo = db.getPoolStatus()
63
- totalCount.set(labels, poolInfo.totalCount)
64
- idleCount.set(labels, poolInfo.idleCount)
65
- waitingCount.set(labels, poolInfo.waitingCount)
66
- maxCount.set(labels, poolInfo.maxCount)
67
- }
68
- }
69
- type SqlMetricsRegistrar = (
70
- connection: Connection.Queryable,
71
- labels: Labels,
72
- ) => Unregistrar
73
- const createSqlMetricsRegistrar = (registry: prom.Registry): SqlMetricsRegistrar => {
74
- const sqlDuration = new prom.Histogram({
75
- name: 'contember_sql_duration_ms',
76
- help: 'Executed SQL queries by contember_module (system, tenant, content or unknown) and contember_project (or "unknown" for unknown project)',
77
- registers: [registry],
78
- labelNames,
79
- buckets: [1, 2, 5, 10, 25, 50, 100, 250, 500, 1000],
80
- })
81
- const sqlErrorRate = new prom.Counter({
82
- name: 'contember_sql_error_count',
83
- help: 'Failed SQL queries by contember_module (system, tenant, content or unknown) and contember_project (or "unknown" for unknown project)',
84
- labelNames,
85
- registers: [registry],
86
- })
87
-
88
- return (connection, labels) => {
89
- const queryEndCallback: EventManager.ListenerTypes[EventManager.Event.queryEnd] = ({ meta }, { timing }) => {
90
- sqlDuration.observe(
91
- {
92
- ...labels,
93
- contember_module: meta.module || labels.contember_module,
94
- },
95
- timing ? timing.selfDuration / 1000 : 0,
96
- )
97
- }
98
- const queryErrorCallback: EventManager.ListenerTypes[EventManager.Event.queryError] = ({ meta }) => {
99
- sqlErrorRate.inc({
100
- ...labels,
101
- contember_module: meta.module || labels.contember_module,
102
- })
103
- }
104
- connection.eventManager.on(EventManager.Event.queryEnd, queryEndCallback)
105
- connection.eventManager.on(EventManager.Event.queryError, queryErrorCallback)
106
- return () => {
107
- connection.eventManager.removeListener(EventManager.Event.queryEnd, queryEndCallback)
108
- connection.eventManager.removeListener(EventManager.Event.queryError, queryErrorCallback)
109
- }
110
- }
111
- }
@@ -1,4 +0,0 @@
1
- export const timeout = (ms: number) =>
2
- new Promise(resolve => {
3
- setTimeout(resolve, ms)
4
- })
@@ -1 +0,0 @@
1
- export const tuple = <T extends unknown[]>(...args: T) => args
package/tslint.json DELETED
@@ -1,14 +0,0 @@
1
- {
2
- "defaultSeverity": "error",
3
- "extends": ["tslint:recommended"],
4
- "jsRules": {},
5
- "rules": {
6
- "interface-name": [true, "never-prefix"],
7
- "object-literal-sort-keys": [false],
8
- "trailing-comma": [false],
9
- "semicolon": [true, "never"],
10
- "arrow-parens": [true, "ban-single-arg-parens"],
11
- "one-line": [true, "check-catch", "check-finally", "check-else"]
12
- },
13
- "rulesDirectory": []
14
- }