-
Notifications
You must be signed in to change notification settings - Fork 57
fix: /healthz and /readyz wait for initial device connection (SOFIE-4325)
#1730
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -81,9 +81,9 @@ export class MosHandler { | |
| private _logger: Winston.Logger | ||
| private _disposed = false | ||
| private _settings?: MosGatewayConfig | ||
| private _coreHandler: CoreHandler | undefined | ||
| private _coreHandler!: CoreHandler | ||
| private _observers: Array<Observer<any>> = [] | ||
| private _triggerupdateDevicesTimeout: any = null | ||
| private _triggerUpdateDevicesTimeout: any = null | ||
| private mosTypes: MosTypes | ||
|
|
||
| public static async create( | ||
|
|
@@ -119,9 +119,6 @@ export class MosHandler { | |
| } | ||
| } | ||
| */ | ||
| if (!coreHandler) { | ||
| throw Error('coreHandler is undefined!') | ||
| } | ||
|
|
||
| if (!coreHandler.core) { | ||
| throw Error('coreHandler.core is undefined!') | ||
|
|
@@ -133,15 +130,14 @@ export class MosHandler { | |
|
|
||
| this.mosTypes = getMosTypes(this.strict) | ||
|
|
||
| await this._updateDevices() | ||
|
|
||
| if (!this._coreHandler) throw Error('_coreHandler is undefined!') | ||
| this._coreHandler.onConnected(() => { | ||
| coreHandler.onConnected(() => { | ||
| // This is called whenever a connection to Core has been (re-)established | ||
| this.setupObservers() | ||
| this.sendStatusOfAllMosDevices() | ||
| }) | ||
| this.setupObservers() | ||
|
|
||
| this.triggerUpdateDevices() | ||
| } | ||
|
Comment on lines
+140
to
141
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Startup now hides fatal MOS init/config errors
Suggested fix private async init(config: MosConfig, coreHandler: CoreHandler): Promise<void> {
this.mosOptions = config
this._coreHandler = coreHandler
...
this.mosTypes = getMosTypes(this.strict)
+ // Fail fast on invalid MOS configuration, but still avoid waiting for device connections
+ await this._initMosConnection()
+
coreHandler.onConnected(() => {
this.setupObservers()
this.sendStatusOfAllMosDevices()
})
this.setupObservers()
this.triggerUpdateDevices()
}Also applies to: 214-217 🤖 Prompt for AI Agents |
||
| async dispose(): Promise<void> { | ||
| this._disposed = true | ||
|
|
@@ -209,10 +205,13 @@ export class MosHandler { | |
| this._logger.debug('test log debug') | ||
| } | ||
| } | ||
| if (this._triggerupdateDevicesTimeout) { | ||
| clearTimeout(this._triggerupdateDevicesTimeout) | ||
| this.triggerUpdateDevices() | ||
| } | ||
| private triggerUpdateDevices() { | ||
| if (this._triggerUpdateDevicesTimeout) { | ||
| clearTimeout(this._triggerUpdateDevicesTimeout) | ||
| } | ||
| this._triggerupdateDevicesTimeout = setTimeout(() => { | ||
| this._triggerUpdateDevicesTimeout = setTimeout(() => { | ||
| this._updateDevices().catch((e) => { | ||
| this._logger.error(stringifyError(e)) | ||
| }) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ordering regression:
setupObservers()now runs before_initMosConnection()and can NPE onthis.mos.Previously
init()awaited_updateDevices()(which awaits_initMosConnection()), sothis.moswas always defined before any observer/_deviceOptionsChangedcould run. After this change, the call order ininit()is:setupObservers()(line 137) — synchronously invokes_deviceOptionsChanged()at line 172.triggerUpdateDevices()(line 139) — schedules_updateDevices()(and therefore_initMosConnection()) ~20 ms later.If the peripheral device's
deviceSettings.debugLoggingdiffers from the defaultthis.debugLogging = false,_deviceOptionsChanged()enters the branch at line 186 and reaches line 191:this.mosis stillundefinedhere, soinit()will throw andMosHandler.create()will reject — which is exactly the boot-failure mode this PR is trying to remove for/healthzand/readyz. The same race exists for any peripheralDevice observer event that fires inside the 20 ms window before_updateDevices()initializesthis.mos.Either initialize the MOS connection eagerly (without awaiting device connections) before observers run, or guard
_deviceOptionsChanged()so it toleratesthis.mosbeing undefined at this stage. Sketch:🛡️ Suggested guard in
_deviceOptionsChangedif (this.debugLogging !== settings.debugLogging) { this._logger.info('Changing debugLogging to ' + settings.debugLogging) this.debugLogging = !!settings.debugLogging - if (!this.mos) { - throw Error('mos is undefined!') - } - this.mos.setDebug(this.debugLogging) + // `this.mos` may not yet exist if observers fire before _initMosConnection completes; + // the value will be applied on next change once mos is initialized. + this.mos?.setDebug(this.debugLogging)🤖 Prompt for AI Agents