Skip to content

Commit 7a2292a

Browse files
committed
Log exceptions to a logger provided when creating.
Closes #1.
1 parent ef1cec9 commit 7a2292a

File tree

3 files changed

+47
-24
lines changed

3 files changed

+47
-24
lines changed

periodic.cabal

+1-2
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@ library
2626

2727
test-suite periodic-test
2828
type: exitcode-stdio-1.0
29-
hs-source-dirs: test
29+
hs-source-dirs: test, src
3030
main-is: Spec.hs
3131
build-depends: base
32-
, periodic
3332
, text
3433
, time
3534
, hedis

src/System/Periodic.hs

+22-10
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,24 @@ newtype Name = Name Text
3030
newtype CheckInterval = CheckInterval Seconds
3131
newtype LockTimeout = LockTimeout Seconds
3232

33+
type Logger = Text -> IO ()
3334
data Scheduler = Scheduler { schedulerName :: Name
3435
, schedulerRedisConn :: R.Connection
3536
, schedulerTasks :: MVar [(Text, Period, IO ())]
3637
, schedulerCheckInterval :: CheckInterval
3738
, schedulerLockTimout :: LockTimeout
39+
, schedulerLogger :: Logger
3840
}
3941

40-
create :: Name -> R.Connection -> CheckInterval -> LockTimeout -> IO Scheduler
41-
create name rconn check lock = do mv <- newMVar []
42-
return $ Scheduler name rconn mv check lock
42+
create :: Name
43+
-> R.Connection
44+
-> CheckInterval
45+
-> LockTimeout
46+
-> (Text -> IO ())
47+
-> IO Scheduler
48+
create name rconn check lock logger =
49+
do mv <- newMVar []
50+
return $ Scheduler name rconn mv check lock logger
4351

4452
addTask :: Scheduler -> Text -> Period -> IO () -> IO ()
4553
addTask scheduler job when act =
@@ -49,10 +57,10 @@ addTask scheduler job when act =
4957
lockTimeout = 10 * 3600
5058

5159
run :: Scheduler -> IO ()
52-
run (Scheduler (Name nm) rconn mv (CheckInterval (Seconds check)) lock) = forever $
60+
run (Scheduler (Name nm) rconn mv (CheckInterval (Seconds check)) lock logger) = forever $
5361
do now <- getCurrentTime
5462
tasks <- readMVar mv
55-
mapM_ (tryRunTask lock nm rconn now) tasks
63+
mapM_ (tryRunTask logger lock nm rconn now) tasks
5664
threadDelay (check * 1000000)
5765

5866
lastStartedKey pname name =
@@ -61,7 +69,7 @@ lockedKey pname name =
6169
T.encodeUtf8 $ pname <> "-" <> name <> "-running-at"
6270

6371
destroy :: Scheduler -> IO ()
64-
destroy (Scheduler (Name nm) rconn mv _ _) =
72+
destroy (Scheduler (Name nm) rconn mv _ _ _) =
6573
do tasks <- readMVar mv
6674
R.runRedis rconn $
6775
R.del (concatMap (\(tnm,_,_) ->
@@ -80,7 +88,6 @@ collapseNumberBoolFalse (Right (Just 1)) = True
8088
collapseNumberBoolFalse (Right (Just 0)) = False
8189

8290

83-
8491
parseUnixTime s = let Right (n, d) = decode s in posixSecondsToUTCTime $ fromRational $ n % d
8592

8693
renderUnixTime t = let r = toRational . utcTimeToPOSIXSeconds $ t in encode (numerator r, denominator r)
@@ -103,8 +110,8 @@ shouldRun _ (Every (Seconds n)) (Just last) locked now
103110
shouldRun lock period last locked now = False
104111

105112

106-
tryRunTask :: LockTimeout -> Text -> R.Connection -> UTCTime -> (Text, Period, IO ()) -> IO ()
107-
tryRunTask timeout pname rconn now (name, period, task) =
113+
tryRunTask :: Logger -> LockTimeout -> Text -> R.Connection -> UTCTime -> (Text, Period, IO ()) -> IO ()
114+
tryRunTask logger timeout pname rconn now (name, period, task) =
108115
do lastStarted <- fmap parseUnixTime . collapseError <$>
109116
R.runRedis rconn
110117
(R.get (lastStartedKey pname name))
@@ -134,7 +141,12 @@ tryRunTask timeout pname rconn now (name, period, task) =
134141
putMVar x (Just e)))
135142
res <- takeMVar x
136143
case res of
137-
Just e -> print $ "Exception raised: " <> show e
144+
Just e -> logger $ T.concat ["periodic["
145+
,pname
146+
,"::"
147+
,name
148+
,"] error: "
149+
,T.pack (show e)]
138150
Nothing -> return ()
139151
R.runRedis rconn $ R.del [lockedKey pname name]
140152
return ()

test/Spec.hs

+24-12
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ runNThreads :: Int -> Int -> Scheduler -> IO ()
2323
runNThreads n delay sched = do threads <- replicateM n (forkIO $ run sched)
2424
threadDelay delay
2525
mapM_ killThread threads
26+
27+
createSch :: T.Text -> IO Scheduler
28+
createSch n = createSch' n print
29+
30+
createSch' :: T.Text -> Logger -> IO Scheduler
31+
createSch' n l = do rconn <- R.connect R.defaultConnectInfo
32+
create (Name n) rconn (CheckInterval (Seconds 1)) (LockTimeout (Seconds 1000)) l
33+
2634
main :: IO ()
2735
main = hspec $
2836
do describe "shouldRun" $
@@ -39,8 +47,7 @@ main = hspec $
3947
describe "simple job" $
4048
do it "should run " $
4149
do mvar <- newMVar 0
42-
rconn <- R.connect R.defaultConnectInfo
43-
scheduler <- create (Name "simple-1") rconn (CheckInterval (Seconds 1)) (LockTimeout (Seconds 1000))
50+
scheduler <- createSch "simple-1"
4451
addTask scheduler "job" (Every (Seconds 100)) (modifyMVarMasked_ mvar (return . (+1)))
4552

4653
runNThreads 1 30000 scheduler
@@ -50,17 +57,15 @@ main = hspec $
5057
1 `shouldBe` v
5158
it "should only run once per scheduled time" $
5259
do mvar <- newMVar 0
53-
rconn <- R.connect R.defaultConnectInfo
54-
scheduler <- create (Name "simple-2") rconn (CheckInterval (Seconds 1)) (LockTimeout (Seconds 1000))
60+
scheduler <- createSch "simple-2"
5561
addTask scheduler "job" (Every (Seconds 100)) (modifyMVarMasked_ mvar (return . (+1)))
5662
runNThreads 3 100000 scheduler
5763
destroy scheduler
5864
v <- takeMVar mvar
5965
v `shouldBe` 1
6066
it "should run at each time point" $
6167
do mvar <- newMVar 0
62-
rconn <- R.connect R.defaultConnectInfo
63-
scheduler <- create (Name "simple-3") rconn (CheckInterval (Seconds 1)) (LockTimeout (Seconds 1000))
68+
scheduler <- createSch "simple-3"
6469
addTask scheduler "job" (Every (Seconds 2)) (modifyMVarMasked_ mvar (return . (+1)))
6570
runNThreads 3 4000000 scheduler
6671
destroy scheduler
@@ -70,8 +75,7 @@ main = hspec $
7075
(v == 3 || v == 2) `shouldBe` True
7176
it "should run at scheduled time" $
7277
do mvar <- newMVar 0
73-
rconn <- R.connect R.defaultConnectInfo
74-
scheduler <- create (Name "simple-4") rconn (CheckInterval (Seconds 1)) (LockTimeout (Seconds 1000))
78+
scheduler <- createSch "simple-4"
7579
seconds <- utctDayTime <$> getCurrentTime
7680
addTask scheduler "job" (Daily (Time seconds)) (modifyMVarMasked_ mvar (return . (+1)))
7781
runNThreads 1 4000000 scheduler
@@ -80,8 +84,7 @@ main = hspec $
8084
v `shouldBe` 1
8185
it "should not run at an unscheduled time" $
8286
do mvar <- newMVar 0
83-
rconn <- R.connect R.defaultConnectInfo
84-
scheduler <- create (Name "simple-4") rconn (CheckInterval (Seconds 1)) (LockTimeout (Seconds 1000))
87+
scheduler <- createSch "simple-4"
8588
now <- getCurrentTime
8689
let seconds = utctDayTime $ addUTCTime 3600 now
8790
addTask scheduler "job" (Daily (Time seconds)) (modifyMVarMasked_ mvar (return . (+1)))
@@ -92,8 +95,7 @@ main = hspec $
9295
describe "error handling" $
9396
do it "should keep running jobs if one throws an exception" $
9497
do mvar <- newMVar 0
95-
rconn <- R.connect R.defaultConnectInfo
96-
scheduler <- create (Name "error-1") rconn (CheckInterval (Seconds 1)) (LockTimeout (Seconds 1000))
98+
scheduler <- createSch' "error-1" (const $ return ())
9799
addTask scheduler "job-error" (Every (Seconds 100)) (error "blowing up")
98100
thread <- forkIO $ run scheduler
99101
threadDelay 300000
@@ -103,3 +105,13 @@ main = hspec $
103105
destroy scheduler
104106
v <- takeMVar mvar
105107
1 `shouldBe` v
108+
it "should send exception to logger" $
109+
do mvar <- newMVar []
110+
scheduler <- createSch' "error-1" (\t -> modifyMVarMasked_ mvar (return . (t:)))
111+
addTask scheduler "job-error" (Every (Seconds 100)) (error "blowing up")
112+
thread <- forkIO $ run scheduler
113+
threadDelay 500000
114+
killThread thread
115+
destroy scheduler
116+
v <- takeMVar mvar
117+
length v `shouldBe` 1

0 commit comments

Comments
 (0)