restart semantics

This commit is contained in:
Keagan McClelland
2020-08-04 18:41:15 -06:00
parent 364a4433cd
commit d8a3ace841
2 changed files with 32 additions and 19 deletions

View File

@@ -30,7 +30,6 @@ import Startlude
import Control.Monad.Logger (liftLoc, runLoggingT) import Control.Monad.Logger (liftLoc, runLoggingT)
import Data.Aeson import Data.Aeson
import Data.Default import Data.Default
import Data.IORef
import Database.Persist.Postgresql (createPostgresqlPool, pgConnStr, pgPoolSize, runSqlPool, runMigration) import Database.Persist.Postgresql (createPostgresqlPool, pgConnStr, pgPoolSize, runSqlPool, runMigration)
import Language.Haskell.TH.Syntax (qLocation) import Language.Haskell.TH.Syntax (qLocation)
import Network.Wai import Network.Wai
@@ -76,7 +75,8 @@ makeFoundation appSettings = do
-- subsite. -- subsite.
appLogger <- newStdoutLoggerSet defaultBufSize >>= makeYesodLogger appLogger <- newStdoutLoggerSet defaultBufSize >>= makeYesodLogger
appWebServerThreadId <- newIORef Nothing appWebServerThreadId <- newEmptyMVar
appShouldRestartWeb <- newMVar False
appCompatibilityMap <- decode . toS <$> readFile (appCompatibilityPath appSettings) >>= \case appCompatibilityMap <- decode . toS <$> readFile (appCompatibilityPath appSettings) >>= \case
Nothing -> panic "invalid compatibility config" Nothing -> panic "invalid compatibility config"
@@ -172,9 +172,10 @@ appMain = do
-- allow environment variables to override -- allow environment variables to override
useEnv useEnv
-- Generate the foundation from the settings -- Generate the foundation from the settings
makeFoundation settings >>= startApp makeFoundation settings >>= \f -> do
forkIO $ restartWeb f
startApp f
startApp :: RegistryCtx -> IO () startApp :: RegistryCtx -> IO ()
startApp foundation = do startApp foundation = do
@@ -190,6 +191,7 @@ startApp foundation = do
when shouldRenew $ do when shouldRenew $ do
putStrLn @Text "Renewing SSL Certs." putStrLn @Text "Renewing SSL Certs."
renewSslCerts renewSslCerts
liftIO $ restartWeb foundation
liftIO $ sleep 86_400 liftIO $ sleep 86_400
startWeb foundation startWeb foundation
@@ -197,15 +199,28 @@ startApp foundation = do
startWeb :: RegistryCtx -> IO () startWeb :: RegistryCtx -> IO ()
startWeb foundation = do startWeb foundation = do
app <- makeApplication foundation app <- makeApplication foundation
let AppSettings{..} = appSettings foundation startWeb' app
putStrLn @Text $ "Launching Web Server on port " <> show appPort where
action <- async $ runTLS startWeb' app = do
(tlsSettings sslCertLocation sslKeyLocation) let AppSettings{..} = appSettings foundation
(warpSettings foundation) putStrLn @Text $ "Launching Web Server on port " <> show appPort
app action <- async $ runTLS
(tlsSettings sslCertLocation sslKeyLocation)
(warpSettings foundation)
app
setWebProcessThreadId (asyncThreadId action) foundation setWebProcessThreadId (asyncThreadId action) foundation
wait action void $ waitCatch action
shouldRestart <- takeMVar (appShouldRestartWeb foundation)
when shouldRestart $ do
putMVar (appShouldRestartWeb foundation) False
putStrLn @Text "Restarting Web Server"
startWeb' app
restartWeb :: RegistryCtx -> IO ()
restartWeb foundation = do
void $ swapMVar (appShouldRestartWeb foundation) True
shutdownWeb foundation
shutdownAll :: [ThreadId] -> IO () shutdownAll :: [ThreadId] -> IO ()
shutdownAll threadIds = do shutdownAll threadIds = do
@@ -215,10 +230,8 @@ shutdownAll threadIds = do
-- Careful, you should always spawn this within forkIO so as to avoid accidentally killing the running process -- Careful, you should always spawn this within forkIO so as to avoid accidentally killing the running process
shutdownWeb :: RegistryCtx -> IO () shutdownWeb :: RegistryCtx -> IO ()
shutdownWeb RegistryCtx{..} = do shutdownWeb RegistryCtx{..} = do
mThreadId <- readIORef appWebServerThreadId threadId <- takeMVar appWebServerThreadId
for_ mThreadId $ \tid -> do killThread threadId
killThread tid
writeIORef appWebServerThreadId Nothing
-------------------------------------------------------------- --------------------------------------------------------------
-- Functions for DevelMain.hs (a way to run the RegistryCtx from GHCi) -- Functions for DevelMain.hs (a way to run the RegistryCtx from GHCi)

View File

@@ -10,7 +10,6 @@ import Startlude
import Control.Monad.Logger ( LogSource ) import Control.Monad.Logger ( LogSource )
import qualified Data.HashMap.Strict as HM import qualified Data.HashMap.Strict as HM
import Data.IORef
import Database.Persist.Sql import Database.Persist.Sql
import Lib.Registry import Lib.Registry
import Yesod.Core import Yesod.Core
@@ -30,13 +29,14 @@ import Yesod.Persist.Core
data RegistryCtx = RegistryCtx data RegistryCtx = RegistryCtx
{ appSettings :: AppSettings { appSettings :: AppSettings
, appLogger :: Logger , appLogger :: Logger
, appWebServerThreadId :: IORef (Maybe ThreadId) , appWebServerThreadId :: MVar ThreadId
, appShouldRestartWeb :: MVar Bool
, appCompatibilityMap :: HM.HashMap AppVersion AppVersion , appCompatibilityMap :: HM.HashMap AppVersion AppVersion
, appConnPool :: ConnectionPool , appConnPool :: ConnectionPool
} }
setWebProcessThreadId :: ThreadId -> RegistryCtx -> IO () setWebProcessThreadId :: ThreadId -> RegistryCtx -> IO ()
setWebProcessThreadId tid a = writeIORef (appWebServerThreadId a) . Just $ tid setWebProcessThreadId tid a = putMVar (appWebServerThreadId a) $ tid
-- This is where we define all of the routes in our application. For a full -- This is where we define all of the routes in our application. For a full
-- explanation of the syntax, please see: -- explanation of the syntax, please see: