Skip to content

Persist can cause store to get into inconsistent state #447

@imirkin

Description

@imirkin

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions