Skip to content

Commit b3332d4

Browse files
authored
Merge pull request Sofie-Automation#1533 from nrkno/feat/health-endpoints-upstream
Add health endpoints to Mos- & Playout-Gateway
2 parents 9bd232e + 18af79f commit b3332d4

File tree

11 files changed

+455
-39
lines changed

11 files changed

+455
-39
lines changed

packages/mos-gateway/src/connector.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,27 @@ import {
55
PeripheralDeviceId,
66
loadCertificatesFromDisk,
77
CertificatesConfig,
8+
stringifyError,
9+
HealthConfig,
10+
HealthEndpoints,
11+
IConnector,
812
} from '@sofie-automation/server-core-integration'
913

1014
export interface Config {
1115
certificates: CertificatesConfig
1216
device: DeviceConfig
1317
core: CoreConfig
1418
mos: MosConfig
19+
health: HealthConfig
1520
}
1621
export interface DeviceConfig {
1722
deviceId: PeripheralDeviceId
1823
deviceToken: string
1924
}
20-
export class Connector {
25+
export class Connector implements IConnector {
26+
public initialized = false
27+
public initializedError: string | undefined = undefined
28+
2129
private mosHandler: MosHandler | undefined
2230
private coreHandler: CoreHandler | undefined
2331
private _config: Config | undefined
@@ -38,11 +46,18 @@ export class Connector {
3846
this._logger.info('Initializing Core...')
3947
await this.initCore(certificates)
4048

49+
if (!this.coreHandler) throw Error('coreHandler is undefined!')
50+
51+
new HealthEndpoints(this, this.coreHandler, config.health)
52+
4153
this._logger.info('Initializing Mos...')
4254
await this.initMos()
4355

4456
this._logger.info('Initialization done')
57+
this.initialized = true
4558
} catch (e: any) {
59+
this.initializedError = stringifyError(e)
60+
4661
this._logger.error('Error during initialization:', e, e.stack)
4762

4863
this._logger.info('Shutting down in 10 seconds!')

packages/mos-gateway/src/coreHandler.ts

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
stringifyError,
1111
PeripheralDevicePubSub,
1212
PeripheralDevicePubSubCollectionsNames,
13+
ICoreHandler,
1314
} from '@sofie-automation/server-core-integration'
1415
import * as Winston from 'winston'
1516

@@ -29,14 +30,16 @@ export interface CoreConfig {
2930
/**
3031
* Represents a connection between mos-integration and Core
3132
*/
32-
export class CoreHandler {
33+
export class CoreHandler implements ICoreHandler {
3334
core: CoreConnection | undefined
3435
logger: Winston.Logger
3536
public _observers: Array<Observer<any>> = []
37+
public connectedToCore = false
3638
private _deviceOptions: DeviceConfig
3739
private _coreMosHandlers: Array<CoreMosDeviceHandler> = []
3840
private _onConnected?: () => any
3941
private _isInitialized = false
42+
private _isDestroyed = false
4043
private _executedFunctions = new Set<PeripheralDeviceCommandId>()
4144
private _coreConfig?: CoreConfig
4245
private _certificates?: Buffer[]
@@ -54,10 +57,12 @@ export class CoreHandler {
5457

5558
this.core.onConnected(() => {
5659
this.logger.info('Core Connected!')
60+
this.connectedToCore = true
5761
if (this._isInitialized) this.onConnectionRestored()
5862
})
5963
this.core.onDisconnected(() => {
6064
this.logger.info('Core Disconnected!')
65+
this.connectedToCore = false
6166
})
6267
this.core.onError((err) => {
6368
this.logger.error('Core Error: ' + (typeof err === 'string' ? err : err.message || err.toString()))
@@ -74,31 +79,45 @@ export class CoreHandler {
7479
}
7580
await this.core.init(ddpConfig)
7681

77-
if (!this.core) {
78-
throw Error('core is undefined!')
79-
}
80-
81-
this.core
82-
.setStatus({
83-
statusCode: StatusCode.GOOD,
84-
// messages: []
85-
})
86-
.catch((e) => this.logger.warn('Error when setting status:' + e))
87-
// nothing
88-
8982
await this.setupSubscriptionsAndObservers()
9083

9184
this._isInitialized = true
85+
86+
await this.updateCoreStatus()
87+
}
88+
getCoreStatus(): {
89+
statusCode: StatusCode
90+
messages: string[]
91+
} {
92+
let statusCode = StatusCode.GOOD
93+
const messages: string[] = []
94+
95+
if (!this._isInitialized) {
96+
statusCode = StatusCode.BAD
97+
messages.push('Starting up...')
98+
}
99+
if (this._isDestroyed) {
100+
statusCode = StatusCode.FATAL
101+
messages.push('Shut down')
102+
}
103+
return {
104+
statusCode,
105+
messages,
106+
}
92107
}
108+
async updateCoreStatus(): Promise<void> {
109+
if (!this.core) throw Error('core is undefined!')
110+
111+
await this.core.setStatus(this.getCoreStatus())
112+
}
113+
93114
async dispose(): Promise<void> {
115+
this._isDestroyed = true
94116
if (!this.core) {
95117
throw Error('core is undefined!')
96118
}
97119

98-
await this.core.setStatus({
99-
statusCode: StatusCode.FATAL,
100-
messages: ['Shutting down'],
101-
})
120+
await this.updateCoreStatus()
102121

103122
await Promise.all(
104123
this._coreMosHandlers.map(async (cmh: CoreMosDeviceHandler) => {

packages/mos-gateway/src/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ let deviceToken: string = process.env.DEVICE_TOKEN || ''
1414
let disableWatchdog: boolean = process.env.DISABLE_WATCHDOG === '1' || false
1515
let unsafeSSL: boolean = process.env.UNSAFE_SSL === '1' || false
1616
const certs: string[] = (process.env.CERTIFICATES || '').split(';') || []
17+
let healthPort: number | undefined = parseInt(process.env.HEALTH_PORT + '') || undefined
1718
let debug = false
1819
let printHelp = false
1920

@@ -46,6 +47,8 @@ process.argv.forEach((val) => {
4647
} else if (val.match(/-unsafeSSL/i)) {
4748
// Will cause the Node applocation to blindly accept all certificates. Not recommenced unless in local, controlled networks.
4849
unsafeSSL = true
50+
} else if (prevProcessArg.match(/-healthPort/i)) {
51+
healthPort = parseInt(val)
4952
}
5053
prevProcessArg = nextPrevProcessArg + ''
5154
})
@@ -207,6 +210,9 @@ const config: Config = {
207210
port: port,
208211
watchdog: !disableWatchdog,
209212
},
213+
health: {
214+
port: healthPort,
215+
},
210216
mos: {
211217
self: {
212218
debug: debug,

packages/playout-gateway/src/config.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ let influxUser: string | undefined = process.env.INFLUX_USER || 'sofie'
2020
let influxPassword: string | undefined = process.env.INFLUX_PASSWORD || undefined
2121
let influxDatabase: string | undefined = process.env.INFLUX_DB || 'sofie'
2222

23+
let healthPort: number | undefined = parseInt(process.env.HEALTH_PORT + '') || undefined
24+
2325
let prevProcessArg = ''
2426
process.argv.forEach((val) => {
2527
val = val + ''
@@ -50,14 +52,18 @@ process.argv.forEach((val) => {
5052
influxPassword = val
5153
} else if (prevProcessArg.match(/-influxDatabase/i)) {
5254
influxDatabase = val
55+
} else if (prevProcessArg.match(/-healthPort/i)) {
56+
healthPort = parseInt(val)
5357

5458
// arguments with no options:
5559
} else if (val.match(/-disableWatchdog/i)) {
5660
disableWatchdog = true
5761
} else if (val.match(/-disableAtemUpload/i)) {
5862
disableAtemUpload = true
5963
} else if (val.match(/-unsafeSSL/i)) {
60-
// Will cause the Node applocation to blindly accept all certificates. Not recommenced unless in local, controlled networks.
64+
// Will cause the Node application to blindly accept all certificates.
65+
// Not recommenced unless in local, controlled networks.
66+
// Instead use "-certificates cert1 cert2"
6167
unsafeSSL = true
6268
}
6369
prevProcessArg = nextPrevProcessArg + ''
@@ -85,6 +91,9 @@ const config: Config = {
8591
password: influxPassword,
8692
database: influxDatabase,
8793
},
94+
health: {
95+
port: healthPort,
96+
},
8897
}
8998

9099
export { config, logPath, logLevel, disableWatchdog, disableAtemUpload }

packages/playout-gateway/src/connector.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ import {
66
CertificatesConfig,
77
PeripheralDeviceId,
88
loadCertificatesFromDisk,
9+
stringifyError,
10+
HealthConfig,
11+
HealthEndpoints,
12+
IConnector,
913
} from '@sofie-automation/server-core-integration'
1014

1115
export interface Config {
@@ -14,13 +18,17 @@ export interface Config {
1418
core: CoreConfig
1519
tsr: TSRConfig
1620
influx: InfluxConfig
21+
health: HealthConfig
1722
}
1823

1924
export interface DeviceConfig {
2025
deviceId: PeripheralDeviceId
2126
deviceToken: string
2227
}
23-
export class Connector {
28+
export class Connector implements IConnector {
29+
public initialized = false
30+
public initializedError: string | undefined = undefined
31+
2432
private tsrHandler: TSRHandler | undefined
2533
private coreHandler: CoreHandler | undefined
2634
private _logger: Logger
@@ -38,6 +46,8 @@ export class Connector {
3846

3947
this._logger.info('Initializing Core...')
4048
this.coreHandler = new CoreHandler(this._logger, config.device)
49+
new HealthEndpoints(this, this.coreHandler, config.health)
50+
4151
await this.coreHandler.init(config.core, this._certificates)
4252
this._logger.info('Core initialized')
4353

@@ -47,12 +57,15 @@ export class Connector {
4757
this._logger.info('TSR initialized')
4858

4959
this._logger.info('Initialization done')
60+
this.initialized = true
5061
return
5162
} catch (e: any) {
5263
this._logger.error('Error during initialization:')
5364
this._logger.error(e)
5465
this._logger.error(e.stack)
5566

67+
this.initializedError = stringifyError(e)
68+
5669
try {
5770
if (this.coreHandler) {
5871
this.coreHandler.destroy().catch(this._logger.error)

packages/playout-gateway/src/coreHandler.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
stringifyError,
1212
PeripheralDevicePubSub,
1313
PeripheralDevicePubSubCollectionsNames,
14+
ICoreHandler,
1415
} from '@sofie-automation/server-core-integration'
1516
import { MediaObject, DeviceOptionsAny, ActionExecutionResult } from 'timeline-state-resolver'
1617
import _ from 'underscore'
@@ -40,7 +41,7 @@ export interface MemoryUsageReport {
4041
/**
4142
* Represents a connection between the Gateway and Core
4243
*/
43-
export class CoreHandler {
44+
export class CoreHandler implements ICoreHandler {
4445
core!: CoreConnection
4546
logger: Logger
4647
public _observers: Array<Observer<any>> = []
@@ -59,6 +60,8 @@ export class CoreHandler {
5960
private _statusInitialized = false
6061
private _statusDestroyed = false
6162

63+
public connectedToCore = false
64+
6265
constructor(logger: Logger, deviceOptions: DeviceConfig) {
6366
this.logger = logger
6467
this._deviceOptions = deviceOptions
@@ -73,11 +76,13 @@ export class CoreHandler {
7376

7477
this.core.onConnected(() => {
7578
this.logger.info('Core Connected!')
79+
this.connectedToCore = true
7680

7781
if (this._onConnected) this._onConnected()
7882
})
7983
this.core.onDisconnected(() => {
8084
this.logger.warn('Core Disconnected!')
85+
this.connectedToCore = false
8186
})
8287
this.core.onError((err: any) => {
8388
this.logger.error('Core Error: ' + (typeof err === 'string' ? err : err.message || err.toString() || err))
@@ -375,9 +380,12 @@ export class CoreHandler {
375380

376381
return Object.fromEntries(this._tsrHandler.getDebugStates().entries())
377382
}
378-
async updateCoreStatus(): Promise<any> {
383+
getCoreStatus(): {
384+
statusCode: StatusCode
385+
messages: string[]
386+
} {
379387
let statusCode = StatusCode.GOOD
380-
const messages: Array<string> = []
388+
const messages: string[] = []
381389

382390
if (!this._statusInitialized) {
383391
statusCode = StatusCode.BAD
@@ -387,11 +395,13 @@ export class CoreHandler {
387395
statusCode = StatusCode.BAD
388396
messages.push('Shut down')
389397
}
390-
391-
return this.core.setStatus({
392-
statusCode: statusCode,
393-
messages: messages,
394-
})
398+
return {
399+
statusCode,
400+
messages,
401+
}
402+
}
403+
async updateCoreStatus(): Promise<any> {
404+
return this.core.setStatus(this.getCoreStatus())
395405
}
396406
}
397407

packages/server-core-integration/package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,17 @@
6969
"rundown",
7070
"production"
7171
],
72+
"devDependencies": {
73+
"@types/koa": "^3.0.0",
74+
"@types/koa__router": "^12.0.4"
75+
},
7276
"dependencies": {
77+
"@koa/router": "^14.0.0",
7378
"@sofie-automation/shared-lib": "1.53.0-in-development",
7479
"ejson": "^2.2.3",
7580
"faye-websocket": "^0.11.4",
7681
"got": "^11.8.6",
82+
"koa": "^3.0.1",
7783
"tslib": "^2.8.1",
7884
"underscore": "^1.13.7"
7985
},

packages/server-core-integration/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
export * from './lib/coreConnection.js'
22
export * from './lib/configManifest.js'
33
export * from './lib/ddpClient.js'
4+
export * from './lib/gateway-types.js'
5+
export * from './lib/health.js'
46
export * from './lib/methods.js'
57
export * from './lib/process.js'
68
export { SubscriptionId } from './lib/subscriptions.js'
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { StatusCode } from '@sofie-automation/shared-lib/dist/lib/status'
2+
3+
export interface IConnector {
4+
initialized: boolean
5+
initializedError: string | undefined
6+
}
7+
8+
export interface ICoreHandler {
9+
getCoreStatus: () => { statusCode: StatusCode; messages: string[] }
10+
connectedToCore: boolean
11+
}

0 commit comments

Comments
 (0)