Search code examples
javasessionquickfixquickfixj

Message queue behavior in QuickFIX/J for disconnected clients


I wanted to clarify a behavior of QuickFIX/J (FIX 4.2) under the following scenario. There are two parties involved in this QuickFIX/J communication:

  1. A client initiator, called I.
  2. Our firm's acceptor program, called A.

When I logs onto A, they exchange FIX messages with tag 35=A. Once a connection is established, I starts to submit orders. There may be a point however, where I disconnects unexpectedly, at which point A decides to send cancels for all of the open orders of I (this is valid, because A has no idea why I failed or when I would come back alive).

Note that this entire cancel-on-disconnect procedure is initiated and handled by A alone - it gets initiated from A's onLogout(...) method and handled by its normal order management mechanisms. A single 35=F message gets generated for each of the open orders of I, and an ExecutionReport (35=8) gets generated on each successful cancel.

When I comes back alive, these ExecutionReports must be delivered to I somehow so that it becomes aware all its previous orders have been cancelled. I had an impression that QuickFIX/J's message queue implementation handles this without an application-level aid. All QuickFIX messages are ensured for delivery to counter-parties (http://permalink.gmane.org/gmane.comp.finance.quickfix.devel/169).

Contrary to my understanding, however, no ExecutionReports were not shown in A's QuickFIX logs, or delivered to I when I reconnected, resulting I to be unaware that its previous orders have been cancelled. I noticed that logging does not occur because of the following source code of the sendRaw(Message message, int num) method of Session in QuickFIX/J:

/**
 * Send the message
 *
 * @param message is the message to send
 * @param num is the seq num of the message to send, if 0, the next expected sender seqnum is used.
 * @return
 */
private boolean sendRaw(Message message, int num) {
    ...
        } else {
            try {
                application.toApp(message, sessionID);
            } catch (final DoNotSend e) {
                return false;
            } catch (final Throwable t) {
                logApplicationException("toApp()", t);
            }
            messageString = message.toString();
            if (isLoggedOn()) { // happens only if session is connected
                result = send(messageString); // logging happens within "send"
            }
        }
    ...
}

The session was not logged on while ExecutionReport messages were being generated for cancels initiated by I's disconnect, and therefore it never hit the send(messageString); and no logging happened. I believe no message got queued (based on the fact that I does not receive any messages when it comes back alive) for the same reason.

Our firm made many implementations based on the belief that QuickFIX/J guarantees all messages to be delivered without a loss, but my observation on the scenario above speaks otherwise.

How is QuickFIX/J's message queue expected to behave in this scenario, when a session is not logged on? Should it queue messages regardless, waiting to be sent once the session becomes available again in the future, or stop queuing for the duration while the session is down?


Solution

  • Just at the end of the private boolean sendRaw(Message message, int num) method there is this code:

    if (num == 0) {
        final int msgSeqNum = header.getInt(MsgSeqNum.FIELD);
        if (persistMessages) {
            state.set(msgSeqNum, messageString);
        }
        state.incrNextSenderMsgSeqNum();
    }
    

    The state.set(msgSeqNum, messageString) will call messageStore.set(sequence, message) which actually stores the message for later delivery if the session is not connected.

    As far as I know, all messages will be queued until the session successfully logs on.