Skip to content

backend-db: Actually catch serialization errors to retry them#131

Open
3noch wants to merge 3 commits intodevelopfrom
eac@fix-serializable-retry
Open

backend-db: Actually catch serialization errors to retry them#131
3noch wants to merge 3 commits intodevelopfrom
eac@fix-serializable-retry

Conversation

@3noch
Copy link
Collaborator

@3noch 3noch commented May 7, 2020

Todo:

  • Tests

@3noch 3noch force-pushed the eac@fix-serializable-retry branch from b322cfa to 355e222 Compare May 7, 2020 18:11
deriving (Functor, Applicative, Monad, MonadThrow, MonadLogger)
deriving (Functor, Applicative, Monad, MonadCatch.MonadThrow, MonadLogger)
-- NOTE: We *intentionally* leave out
-- - 'MonadCatch' so you can't accidentally mask a serialization error from the outer retry logic.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

um

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

haha that's confusing.... I'll import MonadThrow unqualified.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than leaving out the typeclass, wouldn't it be better to provide a custom implementation that gives the behavior we want?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What behavior would that be? A catch that just catches SqlSerializationError first and rethrows it before running your handler? I suppose that would ensure this error is never masked.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that wouldn't be technically law-abiding

catch (throwM e) f = f e

Presumably this law is for all e and f. If we "unmasked" SqlSerializationError in catch then any f :: SqlSerializationError -> m a would not result in f e but an exception.

How much do we care...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FTR:

instance MonadCatch Serializable where
  catch m f = MonadCatch.catches m
    [ MonadCatch.Handler $ \(e :: SqlSerializationError) -> MonadCatch.throwM e -- Never let a handler mask this exception
    , MonadCatch.Handler f
    ]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could make it (kinda) law-abiding again by also changing our throwM i think. it would be tricky and almost certainly not worthwhile for what it actually buys. I'm just not sure we actually want MonadCatch here though, particularly since also any other SqlError could cause the transaction to abort and would need to be handled specially if you don't abort the Serializable action also ...

@3noch 3noch force-pushed the eac@fix-serializable-retry branch from 355e222 to e0fd1f2 Compare May 7, 2020 20:44
@3noch 3noch force-pushed the eac@fix-serializable-retry branch from e0fd1f2 to ee08d02 Compare May 7, 2020 20:45
@3noch 3noch force-pushed the eac@fix-serializable-retry branch from 2c53fe5 to 026ff08 Compare May 7, 2020 21:55
-- | Like 'Pg.withTransactionModeRetry' but polymorphic over exception type.
-- Copied from https://github.com/phadej/postgresql-simple/blob/e02684f9c38acf736ac590b36b919000a2b45bc4/src/Database/PostgreSQL/Simple/Transaction.hs#L156-L174
withTransactionModeRetry' :: forall e a. E.Exception e => Pg.TransactionMode -> (e -> Bool) -> Pg.Connection -> IO a -> IO a
withTransactionModeRetry' mode shouldRetry conn act =
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably not worth copying this impl just to get the polymorphic exception handling.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevermind, upstream uses SqlError. But I could upstream this version.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been merged. So we can point at original repo now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants