quickfixgo / quickfix

The Go FIX Protocol Library :rocket:

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

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Quickfix/Go resets sequence when using StartTime/EndTime

florian-besser opened this issue · comments

I'm raising this issue here as I don't have access to https://groups.google.com/g/quickfixgo

We configure our QuickFix/Go sessions like so:

BeginString=FIX.4.4
# Removed several irrelevant items
StartTime=07:03:00
EndTime=07:00:00

This (to me, as per docs) implies ResetOnLogon=N, ResetOnLogout=N, ResetOnDisconnect=N meaning I expect no session resets to happen. This is indeed true for e.g. us restarting Quickfix/Go, but there is one exception.

Whenever we hit 7AM UTC we see Quickfix/Go disconnect (correctly), followed by reconnection attempts at 7:03AM (also correct), except these reconnection attempts now use the wrong sequence number.

Expected behavior:
Reconnection attempts and future messages should use the next sequence number from before the disconnect.

Example: Before the disconnect our last outgoing message has sequence id 123. The next message (i.e. the logon at 7:03) should use sequence id 124

Observed behavior:
Quickfix/Go resets the sequence, the next sequence id is always 1.

This leads to our counterparty complaining that the sequence number is wrong.

I currently believe this is due to the following code:

func (sm *stateMachine) CheckSessionTime(session *session, now time.Time) {
	if !session.SessionTime.IsInRange(now) {
		if sm.IsSessionTime() {
			session.log.OnEvent("Not in session")
		}

		sm.State.ShutdownNow(session)
		sm.setState(session, notSessionTime{})

		if sm.notifyOnInSessionTime == nil {
			sm.notifyOnInSessionTime = make(chan interface{})
		}
		return
	}

	if !sm.IsSessionTime() {
		session.log.OnEvent("In session")
		sm.notifyInSessionTime()
		sm.setState(session, latentState{})
	}

	if !session.SessionTime.IsInSameRange(session.store.CreationTime(), now) {
		session.log.OnEvent("Session reset")
		sm.State.ShutdownNow(session)
		if err := session.dropAndReset(); err != nil {
			session.logError(err)
		}
		sm.setState(session, latentState{})
	}
}

Specifically the last if statement. From the code I don't see a way for us to configure this behavior and the library will always reset the sequence.