fix(hal-service): don't keep a cassette layout the dispenser refused
setCassettes updated bays and dispenserInitData before re-initialising the device, deliberately, so that "subsequent dispense calls see the new layout even if the dispenser re-init is slow / fails". With the re-init failing every time on douro, that meant the app kept a layout the hardware had never taken, the operator-config consumer logged "Applied ops", and a cassettes-state event went out to the operator advertising it. The douro spent the afternoon reporting bay1:100x60 bay2:200x0 while the device was still running the boot-time 100x50/200x50. A dispense in that state picks bays by a layout the device does not share. Roll the in-memory layout back when the re-init throws, and let the error propagate as before. Reversing that earlier choice deliberately: a stale but honest layout beats a fresh but fictional one when the difference is which cassette pays out. Also await dispenser.close() here and in cleanup(), now that close() reports completion. Closes #118
This commit is contained in:
parent
5fc1fbc9e8
commit
47d3d0b237
1 changed files with 29 additions and 22 deletions
|
|
@ -376,12 +376,10 @@ export async function initializeHal(config: HalConfig): Promise<HalInstance> {
|
|||
setCassettes: async (cassettes: CassetteConfig[]): Promise<void> => {
|
||||
console.log(
|
||||
'[HAL] Hot-reloading cassette layout:',
|
||||
cassettes
|
||||
.map((c) => `bay${c.position}:${c.denomination}×${c.count ?? 0}`)
|
||||
.join(', ')
|
||||
cassettes.map((c) => `bay${c.position}:${c.denomination}×${c.count ?? 0}`).join(', ')
|
||||
)
|
||||
// Rebuild bays first so subsequent dispense calls see the new layout
|
||||
// even if the dispenser re-init is slow / fails.
|
||||
const previousBays = bays
|
||||
const previousInitData = dispenserInitData
|
||||
bays = cassettes
|
||||
.slice()
|
||||
.sort((a, b) => a.position - b.position)
|
||||
|
|
@ -391,31 +389,40 @@ export async function initializeHal(config: HalConfig): Promise<HalInstance> {
|
|||
count: c.count ?? 0,
|
||||
}))
|
||||
dispenserInitData = { fiatCode: valConfig.fiatCode, cassettes }
|
||||
// Close + re-init the dispenser so its internal per-bay state matches
|
||||
// the new layout. Errors here surface to the caller (operator-config
|
||||
// consumer) — the renderer can decide whether to retry.
|
||||
// Close + re-init the dispenser so its internal per-bay state matches the
|
||||
// new layout. close() now resolves only once the port is really closed,
|
||||
// so the re-open below cannot race it (aiolabs/bitspire#118).
|
||||
//
|
||||
// On failure, roll the in-memory layout back. This reverses an earlier
|
||||
// deliberate choice to keep the new bays "even if the dispenser re-init
|
||||
// is slow / fails": with the re-init failing every time on douro, the app
|
||||
// kept a layout the device had never taken and the operator-config
|
||||
// consumer went on to publish a cassettes-state event advertising it. A
|
||||
// subsequent dispense would then pick bays by a layout the hardware does
|
||||
// not share. Better to surface the failure and stay truthful about what
|
||||
// the device is actually running.
|
||||
try {
|
||||
dispenser.close()
|
||||
} catch (err) {
|
||||
console.warn('[HAL] Dispenser close during setCassettes raised:', err)
|
||||
}
|
||||
await dispenser.close()
|
||||
await dispenser.init(dispenserInitData)
|
||||
} catch (err) {
|
||||
bays = previousBays
|
||||
dispenserInitData = previousInitData
|
||||
console.error('[HAL] Dispenser re-init failed; keeping the previous cassette layout:', err)
|
||||
throw err
|
||||
}
|
||||
console.log('[HAL] Dispenser re-initialized with new cassettes')
|
||||
},
|
||||
|
||||
cleanup: async () => {
|
||||
return new Promise<void>((resolve) => {
|
||||
validator?.disable()
|
||||
validator?.lightOff()
|
||||
dispenser.close()
|
||||
if (validator) {
|
||||
validator.close((err?: Error) => {
|
||||
await dispenser.close()
|
||||
if (!validator) return
|
||||
await new Promise<void>((resolve) => {
|
||||
validator?.close((err?: Error) => {
|
||||
if (err) console.error('[HAL] Validator close error:', err)
|
||||
resolve()
|
||||
})
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue