commit 84a7307cd1eb5d243fbbd35e1f3f853ffe950018
parent be7ee69398cc6aef5989dcf92340e7fc323517a6
Author: mtmn <miro@haravara.org>
Date: Mon, 1 Jun 2026 21:08:40 +0200
fix: guarantee lock release in db transaction
Diffstat:
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/src/Db.purs b/src/Db.purs
@@ -20,7 +20,7 @@ import Data.Time.Duration (Milliseconds(..))
import Data.Tuple (Tuple(..))
import Data.UUID (genUUID, toString) as UUID
import Effect (Effect)
-import Effect.Aff (Aff, delay, makeAff, nonCanceler, try)
+import Effect.Aff (Aff, bracket, delay, makeAff, nonCanceler, try)
import Effect.Aff.AVar (AVar)
import Effect.Aff.AVar as Avar
import Effect.Class (liftEffect)
@@ -117,12 +117,10 @@ backupDb conn dbFile s3cfg intervalMs slug = forever do
pure unit
-- Acquires the write lock, runs the action inside a transaction, then releases.
--- The lock is always released: on success, on action failure (rollback), and on
--- BEGIN/COMMIT failure. This prevents deadlock if the database throws unexpectedly.
+-- Uses bracket to guarantee lock release even on fiber kill, preventing deadlocks.
withTransaction :: forall a. Connection -> AVar Unit -> Aff a -> Aff a
-withTransaction conn lock action = do
- Avar.take lock
- result <- try do
+withTransaction conn lock action =
+ bracket (Avar.take lock) (\_ -> Avar.put unit lock) \_ -> do
run conn "BEGIN TRANSACTION" []
r <- try action
case r of
@@ -132,10 +130,6 @@ withTransaction conn lock action = do
Right v -> do
void $ try $ run conn "COMMIT" []
pure v
- Avar.put unit lock
- case result of
- Left err -> throwError err
- Right v -> pure v
queryAll :: Connection -> String -> Array Foreign -> Aff (Array Json)
queryAll conn sql params = makeAff \cb -> do