33 lines
980 B
Haskell
33 lines
980 B
Haskell
module Utils.Sql
|
|
( setSerializable
|
|
) where
|
|
|
|
import ClassyPrelude.Yesod
|
|
|
|
import Database.Persist.Sql
|
|
|
|
import Database.PostgreSQL.Simple (SqlError(SqlError), sqlErrorHint)
|
|
import Control.Monad.Catch (handleIf)
|
|
|
|
import Data.Time.Clock
|
|
|
|
setSerializable :: (MonadLogger m, MonadCatch m, MonadBase IO m, MonadIO m) => ReaderT SqlBackend m a -> ReaderT SqlBackend m a
|
|
setSerializable act = setSerializable' (0 :: Integer)
|
|
where
|
|
act' = [executeQQ|SET TRANSACTION ISOLATION LEVEL SERIALIZABLE|] *> act
|
|
|
|
setSerializable' (min 10 -> logBackoff) =
|
|
handleIf
|
|
(\SqlError{sqlErrorHint} -> "The transaction might succeed if retried." `isInfixOf` sqlErrorHint)
|
|
(\e -> do
|
|
let
|
|
delay :: NominalDiffTime
|
|
delay = 1e-3 * 2 ^ logBackoff
|
|
$logWarnS "Sql" $ tshow (delay, e)
|
|
transactionUndo
|
|
threadDelay . round $ delay * 1e6
|
|
setSerializable' (succ logBackoff)
|
|
)
|
|
act'
|
|
|