{- Copyright (c) Meta Platforms, Inc. and affiliates. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. -} module Glean.Util.Periodic ( doPeriodically, doPeriodicallySynchronised ) where import Control.Exception import Control.Monad import Util.Control.Exception import Util.Log import Util.Time -- | Run an action every t seconds. If the action throws an -- exception, log and swallow it, and then wait t seconds before -- retrying. doPeriodically :: DiffTimePoints -> IO () -> IO () doPeriodically period action = mask $ \restore -> forever $ handler restore period $ do t0 <- getTimePoint action t <- getElapsedTime t0 delay (addDiffTimePoints period (negate t)) -- | Run an action every t seconds from epoch. If the action throws an -- exception, log and swallow it, and then wait t seconds before -- retrying. doPeriodicallySynchronised :: DiffTimePoints -> IO () -> IO () doPeriodicallySynchronised period action = mask $ \restore -> forever $ handler restore period $ do now <- getEpochTime let nanosSinceEpoch = fromIntegral $ toEpochNanos now nanosSinceLastTick = nanosSinceEpoch `rem` toDiffNanos period durationSinceLastTick = nanoseconds $ fromIntegral nanosSinceLastTick durationToNextTick = addDiffTimePoints period (negate durationSinceLastTick) delay durationToNextTick action handler :: (t -> IO ()) -> DiffTimePoints -> t -> IO () handler restore period action = do r <- tryAll (restore action) case r of Left e -> do logError (show e); delay period; return () Right () -> return ()