quickfixgo / quickfix

The Go FIX Protocol Library :rocket:

Home Page:https://www.quickfixgo.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Persist can cause store to get into inconsistent state

imirkin opened this issue · comments

Let's say that one is using the sql store. Persist looks like this:

func (s *session) persist(seqNum int, msgBytes []byte) error {
        if !s.DisableMessagePersist {
                if err := s.store.SaveMessage(seqNum, msgBytes); err != nil {
                        return err
                }
        }

        return s.store.IncrNextSenderMsgSeqNum()
}

So it will save the message to the messages table, and after that, update the outgoing seqnum in the sessions table.

However if the process is terminated in the middle (or there's a database error), you can end up with the message in the messages table, but the outgoing seqnum will still be the old one in the sessions table. Ideally there'd be some transactionality here, but the interfaces don't have anything like that.

This causes problems when the process is restarted and tries to send a message. It will insert another message into the messages table, which will fail due to a primary key constraint.

I believe a reasonable solution would be to flip those two around. In the failure case outlined, you'll just have burned a seqnum, which seems like a reasonable thing to do in such an exceptional situation.

Sure, if you're comfortable tackling this, feel free. Adding a test that fails would be a good start as well.