From c030267a77ff2d422d5ff9481260f3fda2cc3a20 Mon Sep 17 00:00:00 2001 From: Mats Rauhala Date: Thu, 20 Aug 2026 19:57:35 +0300 Subject: [PATCH] Supervise workers and make auth failures fatal --- src/HomeAssistant/Runtime.hs | 16 ++++++++++------ src/HomeAssistant/Runtime/Connection.hs | 6 ++++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/HomeAssistant/Runtime.hs b/src/HomeAssistant/Runtime.hs index c0f7dc4..163d422 100644 --- a/src/HomeAssistant/Runtime.hs +++ b/src/HomeAssistant/Runtime.hs @@ -14,15 +14,16 @@ module HomeAssistant.Runtime ) where import AFRP (Event (..), Mealy (..)) -import Control.Concurrent.Async (mapConcurrently_) +import Control.Concurrent.Async (async, waitAny) import Control.Concurrent.STM (atomically, dupTChan, readTChan) import Data.Aeson (Value) import qualified Data.Text as T import Data.Time (getCurrentTime) -import Data.Void (Void) +import Data.Void (Void, absurd) import HomeAssistant.Controller (HASS, HASSEff (..), lightController) import HomeAssistant.Runtime.Bus import HomeAssistant.Runtime.Connection (readerAction, writerAction) +import HomeAssistant.Runtime.Supervisor (defaultBackoff, supervised) import Network.Socket (withSocketsDo) import System.Environment (getEnv) @@ -53,10 +54,13 @@ defaultMain :: IO () defaultMain = withSocketsDo $ do token <- getEnv "HA_TOKEN" bus <- newBus 0 - mapConcurrently_ id $ - [ readerAction "last-resort-redux" 8123 token bus - , writerAction bus - ] ++ map (runController bus) controllers + let workers = + [ ("reader", readerAction "last-resort-redux" 8123 token bus) + , ("writer", writerAction bus) + ] ++ [ (name, runController bus c) | c@(Controller name _) <- controllers ] + as <- mapM (\(name, act) -> async (supervised name defaultBackoff act)) workers + (_, v) <- waitAny as + absurd v dryRunHassEval :: CallIdGen -> HASSEff a -> IO a dryRunHassEval gen = \case diff --git a/src/HomeAssistant/Runtime/Connection.hs b/src/HomeAssistant/Runtime/Connection.hs index a242468..1c85500 100644 --- a/src/HomeAssistant/Runtime/Connection.hs +++ b/src/HomeAssistant/Runtime/Connection.hs @@ -15,6 +15,7 @@ import Control.Concurrent.STM , writeTChan , writeTVar ) +import Control.Exception.Annotated (throw) import Control.Lens ((^?)) import Control.Monad (forever) import Data.Aeson (Value, eitherDecode, encode, object, (.=)) @@ -24,6 +25,7 @@ import qualified Data.Text as T import Data.Void (Void) import HomeAssistant.Controller (Service (..)) import HomeAssistant.Runtime.Bus +import HomeAssistant.Runtime.Supervisor (Fatal (..)) import qualified Network.WebSockets as WS -- | Connect, authenticate, subscribe, then receive and broadcast forever. @@ -53,7 +55,7 @@ expectType :: T.Text -> Value -> IO () expectType expected msg = case msg ^? key "type" . _String of Just t | t == expected -> pure () - _ -> fail $ "expected " <> T.unpack expected <> ", got: " <> show msg + _ -> throw (Fatal $ "expected " <> expected <> ", got: " <> T.pack (show msg)) subscribe :: Bus -> WS.Connection -> IO () subscribe bus conn = do @@ -77,7 +79,7 @@ receiveJSON :: WS.Connection -> IO Value receiveJSON conn = do msg <- WS.receiveData conn case eitherDecode msg of - Left err -> fail $ "Invalid JSON from Home Assistant: " ++ err + Left err -> throw (Fatal $ "Invalid JSON from Home Assistant: " <> T.pack err) Right x -> pure x writerAction :: Bus -> IO Void