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:
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 ExecutionReport
s 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 ExecutionReport
s 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?
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.