A successful OnixS::FIX::Session::send call does not guarantee that the counterparty has received the message. The following applies whether the session is connected or disconnected:
| Stage | Meaning |
|---|---|
| Local send processing | A normal return means the call completed without reporting an exception. It may serialize and store the message or write it to the socket, but does not wait for counterparty acknowledgment. See Understanding Send Latency. |
| Storage | How long messages remain available and whether they survive a restart depend on storage and logging settings. Memory-based Session Storage loses messages when the process stops. Asynchronous File-Based Session Storage writes in another thread, so returning from send does not guarantee that the message has been written to disk. |
| Transmission | Outbound callbacks and socket writes do not confirm that the counterparty's application received the message. A disconnected send does not transmit the application message to the counterparty. |
| Resending | After reconnecting, the counterparty must request the messages. They must still be available in session storage, meet the conditions below, and be allowed by the callback. See Resending queue size for storage limits. |
To determine whether the counterparty accepted the message, check its application response, such as an Execution Report for the order; successful sending or resending does not confirm acceptance.
When the Engine receives a Resend Request (2) from the counterparty (e.g. due to a sequence number mismatch), OnixS::FIX::ISessionListener::onResendingStarted indicates that resend processing is starting.
The requested messages must still be available in session storage and must be original messages: PossDupFlag(43) must be absent or N. The Engine skips messages marked as possible duplicates and administrative messages other than Reject(35=3).
If these conditions are met and a listener is attached, the Engine invokes the applicable OnixS::FIX::ISessionListener::onResendRequest overload, passing the message as its parameter. With multiple listeners attached, the first callback returning true allows the message to be resent; subsequent listeners are not called for that message.
Attaching a listener does not enable resending by itself. Both onResendRequest overloads return false by default. Without a listener, or when all callbacks return false, the Engine sends SequenceReset-GapFill (4) instead of resending the requested message. A gap fill advances the counterparty's expected sequence number without delivering the skipped message. Override the callback and return true only for messages that your application and counterparty allow to be resent; return false, for example, for an aged or stale order.
If onResendRequest throws, the Engine reports OnixS::FIX::ErrorReason::ExceptionInEventHandler through OnixS::FIX::ISessionListener::onError and sends a gap fill instead of resending that message.
OnixS::FIX::ISessionListener::onResendingFinished indicates that resend processing has completed.
The runnable Resending Messages Sample demonstrates no listener (case 1), a callback returning false (case 2), and a callback returning true (case 3). The Code Example below shows how to skip stale messages.
FIX Engine will send Resend Request (2) message if the sequence number of the incoming message is greater than expected.
There is one important parameter: OnixS::FIX::EngineSettings::resendingQueueSize. This parameter will specify how much messages can be resent if a counterparty requests them. For example, this parameter is set to 1000, and the counterparty sends a ResendRequest message with sequence numbers rage 1-2000. In this case, the session will send a SequenceReset-GapFill (4) message for range 1-1000, and messages 1001-2000 can be resent if they meet the conditions above and a callback returns true. If this parameter is zero, no messages will be resent.
In accordance with the FIX protocol there are two options for dealing with gaps:
The default behavior of the FIX Engine corresponds to the first option. In this mode, when a sequence gap is detected, the FIX Engine sends the Resend Request (2) for all messages and waits for the reply. All newer incoming messages are ignored until the reply is received. In order to report the new messages anyway, you can use OnixS::FIX::Session::reportNewMessagesWhileWaitingForMissedMessages setting. After the reply is received (first message with the PossDupFlag (tag #43) flag), there should not be any newer original messages until all requested messages are received, otherwise, each such a message will cause a new resend request. Therefore, it can increase the network load and make difficulties for the sequence synchronization.
In order to activate the second option of the resend functionality you need to set the OnixS::FIX::Session::requestOnlyMissedMessages setting to true. In this mode, when a sequence gap is detected, the FIX Engine sends the Resend Request (2) only for missed messages. All newer incoming messages are stored in the incoming message gap queue and they are processed when all requested messages are received. You can limit the size of this queue by the OnixS::FIX::Session::incomingMessageGapQueueMaximumSize setting.
To check all aspects of the resend functionality one may run the Resending Messages Sample from the FIX Engine distribution package.
The resending process can take time, especially if the number of resending messages is large. During the resend process, the session reads sending messages from the summary log file, deserializes them, and resends them to the counterparty. This process is thread-safe and is executed under the session's lock. As a result, session methods can be blocked until the resend process is completed. Therefore, it makes sense not to call the session's methods and not to pressure the session by sending new messages during this period. OnixS::FIX::ISessionListener::onResendingStarted / OnixS::FIX::ISessionListener::onResendingFinished callbacks can be used to detect the start/finish of the resending process and implement the necessary logic. Additionally, one can use the OnixS::FIX::EngineSettings::resendingBatchSize setting. It allows to set the maximum number of messages sent in reply to the Resend Request(2) before temporarily releasing the session’s lock.