Details
Description
sessionClosed() called by AbstractIoHandler can call disconnect() on Session before a logout message has been processed by the EventHandlingSession. (This was witnessed with a SingleThreadedEventHandlingStrategy).
The disconnect() call on Session results in logonSent being set to false in SessionState. If this happens before SingleThreadedEventHandlingStrategy calls next(Message) on the Session object, the logout message will subsequently throw a SessionException in validLogonState() (as logonSent is now false). And the message will not reach the application.
This is problematic in the scenario where an ECN is informing us in a logout message of an issue with sequence numbers. The message is not received and the appropriate action can't take place,
This is an example of the occurrence from our logs with Reuters:
20140731-10:44:42.662 INFO [SocketConnectorIoProcessor-1.0] quickfix.Session - [XXX/YYY->TR MATCHING/FXM] Disconnecting: IO Session closed
20140731-10:44:42.663 ERROR [QFJ Message Processor] quickfixj.errorEvent - XXX/YYY->TR MATCHING/FXM: quickfix.SessionException Logon state is not valid for message (MsgType=5)
One possible suggestion would be to check the EventHandlingStrategy queue size and delay the sessionClosed call if there are outstanding events.
E.g. in InitiatorIoHandler
@Override
public void sessionClosed(IoSession ioSession) throws Exception {
while (eventHandlingStrategy.getQueueSize() > 0) {
log.info("Delaying sessionClosed while " + eventHandlingStrategy.getQueueSize() + " event(s) "
+ "are processed");
try
catch (InterruptedException e)
{ log.warn("sessionClosed dealy was interrupted"); } }
super.sessionClosed(ioSession);
}
Perhaps there are better approaches. Is this a known race condition?