import { Effects } from "../types" import { CheckResult } from "./checkFns/CheckResult" import { HealthReceipt } from "./HealthReceipt" import { Trigger } from "../trigger" import { TriggerInput } from "../trigger/TriggerInput" import { defaultTrigger } from "../trigger/defaultTrigger" import { once } from "../util/once" import { Overlay } from "../util/Overlay" import { object, unknown } from "ts-matches" import * as T from "../types" export type HealthCheckParams = { effects: Effects name: string image: { id: keyof Manifest["images"] & T.ImageId sharedRun?: boolean } trigger?: Trigger fn(overlay: Overlay): Promise | CheckResult onFirstSuccess?: () => unknown | Promise } export function healthCheck( o: HealthCheckParams, ) { new Promise(async () => { const overlay = await Overlay.of(o.effects, o.image) try { let currentValue: TriggerInput = { hadSuccess: false, } const getCurrentValue = () => currentValue const trigger = (o.trigger ?? defaultTrigger)(getCurrentValue) const triggerFirstSuccess = once(() => Promise.resolve( "onFirstSuccess" in o && o.onFirstSuccess ? o.onFirstSuccess() : undefined, ), ) for ( let res = await trigger.next(); !res.done; res = await trigger.next() ) { try { const { status, message } = await o.fn(overlay) await o.effects.setHealth({ name: o.name, id: o.name, result: status, message: message || "", }) currentValue.hadSuccess = true currentValue.lastResult = "success" await triggerFirstSuccess().catch((err) => { console.error(err) }) } catch (e) { await o.effects.setHealth({ name: o.name, id: o.name, result: "failure", message: asMessage(e) || "", }) currentValue.lastResult = "failure" } } } finally { await overlay.destroy() } }) return {} as HealthReceipt } function asMessage(e: unknown) { if (object({ message: unknown }).test(e)) return String(e.message) const value = String(e) if (value.length == null) return null return value }