Add schedule module move some ExceptTs around

This commit is contained in:
Paul Brinkmeier
2025-09-20 15:18:01 +02:00
parent 368bbb0124
commit 67127fd28d
8 changed files with 111 additions and 55 deletions
+55 -36
View File
@@ -11,10 +11,10 @@
module Main (main) where
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Except (ExceptT (..), runExceptT)
import Control.Monad.Trans.Except (ExceptT (..), catchE, runExceptT)
import Data.Proxy (Proxy (..))
import Data.Text (Text)
import Data.Time (Day, toGregorian)
import Data.Time (Day, addDays, toGregorian)
import GHC.Generics (Generic)
import Network.HTTP.Media ((//), (/:))
import Network.HTTP.Types (Status (..), mkStatus, status200)
@@ -54,10 +54,12 @@ import qualified Text.Blaze.Html5 as H
import qualified Text.Blaze.Html5.Attributes as A
import Envy (type (=@!), type (=@@), type (?))
import Yore.DB (DayFile (..))
import Yore.DB (DB, DayFile (..))
import Yore.Error (Error (..))
import Yore.Schedule (schedule)
import Yore.Time (addYears, getCurrentDay, getSecondsUntilMidnight)
import Control.Concurrent (forkIO)
import Control.Monad (forM, forM_)
import Data.Bifunctor (Bifunctor (..))
import qualified Envy
@@ -93,7 +95,37 @@ main = do
Right c ->
pure c
let
db <- DB.initDB cfg.yoreDb
_ <-
runExceptT $
catchE
( DB.withConn db $ \conn -> do
dayThen <- getTodayWithYearOffset (-100)
indexDay cfg dayThen conn
)
(Log.error . show)
_ <- forkIO $ runIndexer cfg db
runServer cfg db
runIndexer :: Config -> DB -> IO ()
runIndexer cfg db = schedule (const True) $ do
_ <-
runExceptT $
catchE
( DB.withTransaction db $ \conn -> do
dayThen <- getTodayWithYearOffset (-100)
indexDay cfg dayThen conn
dayThen2 <- addDays 1 <$> getTodayWithYearOffset (-100)
indexDay cfg dayThen2 conn
)
(Log.error . show)
pure ()
runServer :: Config -> DB -> IO ()
runServer cfg db =
Warp.runSettings settings $ serve (Proxy @API) $ hoistServer (Proxy @API) nt $ server cfg db
where
settings =
foldr
($)
@@ -104,13 +136,6 @@ main = do
, Warp.setOnException onException
]
db <- DB.initDB cfg.yoreDb
DB.withConn db (runExceptT . indexDayWithOffset cfg (-100)) >>= \case
Left err -> Log.error $ show err
Right _ -> pure ()
Warp.runSettings settings $ serve (Proxy @API) $ hoistServer (Proxy @API) nt $ server cfg db
where
logger req status _ = do
Log.info $
printf
@@ -166,20 +191,20 @@ handlerToRaw handler = Tagged $ \_ respond -> do
Right response ->
respond response
server :: Config -> DB.DB -> ServerT API (ExceptT Error IO)
server :: Config -> DB -> ServerT API (ExceptT Error IO)
server cfg db = rootR :<|> todayR :<|> apiTodayR
where
rootR = todayR 0
todayR issue = do
dateThen <- ExceptT get100YearsAgo
count <- ExceptT $ DB.withConn' db $ DB.getNumberOfIssues dateThen
dayFile <- ExceptT $ DB.withConn' db $ DB.getDayFileByIssue dateThen issue
count <- DB.withConn db $ DB.lift . DB.getNumberOfIssues dateThen
dayFile <- DB.withConn db $ DB.lift . DB.getDayFileByIssue dateThen issue
pure $ RootModel dateThen dayFile issue count
apiTodayR issue = handlerToRaw $ do
dateThen <- ExceptT get100YearsAgo
dayFile <- ExceptT $ DB.withConn' db $ DB.getDayFileByIssue dateThen issue
dayFile <- DB.withConn db $ DB.lift . DB.getDayFileByIssue dateThen issue
let fullPath = cfg.yoreDownloadDir </> dayFile.relative_path
secondsUntilMidnight <- liftIO getSecondsUntilMidnight
pure $
@@ -231,36 +256,30 @@ instance Accept HTML where
contentType _ = "text" // "html" /: ("charset", "utf-8")
get100YearsAgo :: IO (Either Error Day)
get100YearsAgo = getTodayWithYearOffset (-100)
get100YearsAgo = runExceptT $ getTodayWithYearOffset (-100)
getTodayWithYearOffset :: Integer -> IO (Either Error Day)
getTodayWithYearOffset :: Integer -> ExceptT Error IO Day
getTodayWithYearOffset offset =
first (GenericError . (Text.pack (printf "can't go back %s years: " (-offset)) <>)) . addYears offset <$> getCurrentDay
ExceptT $
first (GenericError . (Text.pack (printf "can't go back %s years: " (-offset)) <>)) . addYears offset <$> getCurrentDay
indexDayWithOffset :: Config -> Integer -> Opium.Connection -> ExceptT Error IO ()
indexDayWithOffset cfg offset conn = do
dayThen <- ExceptT $ getTodayWithYearOffset offset
runDb $ Opium.execute_ "BEGIN" conn
indexDay :: Config -> Day -> Opium.Connection -> ExceptT Error IO ()
indexDay cfg dayThen conn = do
-- Transaction-level lock released automatically after transaction
runDb $ Opium.execute_ "SELECT pg_advisory_xact_lock(42);" conn
mbDi <- runDb $ DB.readDayIndex dayThen conn
DB.lift $ Opium.execute_ "SELECT pg_advisory_xact_lock(42);" conn
mbDi <- DB.lift $ DB.readDayIndex dayThen conn
case mbDi of
Just _ ->
liftIO $ Log.info $ printf "index for %s already exists." (show dayThen)
Log.info $ printf "index for %s already exists." (show dayThen)
Nothing -> do
liftIO $ Log.info $ printf "scraping issues for %s" (show dayThen)
Log.info $ printf "scraping issues for %s" (show dayThen)
issues <- liftIO $ getIssuesByDay dayThen
paths <- forM issues $ \issue -> do
liftIO $ Log.info $ printf "downloading %s" issue.url
Log.info $ printf "downloading %s" issue.url
path <- liftIO $ downloadInto cfg.yoreDownloadDir issue.url
pure (issue.label, path)
liftIO $ Log.info "creating DB entries"
dayIndex <- runDb $ DB.createDayIndex dayThen conn
Log.info "creating DB entries"
dayIndex <- DB.lift $ DB.createDayIndex dayThen conn
forM_ paths $ \(text, url) ->
runDb $ DB.createDayFile dayIndex.day_index_id text url conn
runDb $ Opium.execute_ "COMMIT" conn
liftIO $ Log.info "done."
runDb :: IO (Either Opium.Error a) -> ExceptT Error IO a
runDb f =
ExceptT $ first DBError <$> f
DB.lift $ DB.createDayFile dayIndex.day_index_id text url conn
Log.info "done."