OnixS C++ FIX Engine 4.14.0
Users' manual and API documentation
Loading...
Searching...
No Matches
Resending Messages

Sending and Delivery

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.

Conditions for Resending Messages

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.

Under what conditions might FIX Engine send a Resend Request (35=2)?

FIX Engine will send Resend Request (2) message if the sequence number of the incoming message is greater than expected.

Note
According to the FIX specification, Resend Request (2) is sent by the receiving application to initiate the retransmission of messages. This function is utilized if a sequence number gap is detected, if the receiving application lost a message, or as a function of the initialization process.

Resending queue size

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.

Note
There is the corresponding OnixS::FIX::Session::resendingQueueSize setting, which can be used to change the resending queue size for a particular session. However, in any way, when a OnixS::FIX::Session object is created the resending queue is limited by the global OnixS::FIX::EngineSettings::resendingQueueSize setting. Therefore, the right way to use the OnixS::FIX::Session::resendingQueueSize setting is the following:

Two options of the resend functionality when the sequence gap is detected

In accordance with the FIX protocol there are two options for dealing with gaps:

  • Request all messages including the last message received.
  • Request for the specific message missed while maintaining an ordered list of all newer messages.

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.

Code Example

class ResendRequestListener : public ISessionListener
{
public:
bool isStale(const Message& message)
{
// Simple sending time based filtering of stale messages.
Timestamp previousSendingTime = message.getTimestamp(FIX42::Tags::SendingTime);
long long keepingTime = 30 * 60; // 30 minutes
bool isStale = (Timestamp::utc().totalSeconds() - previousSendingTime.totalSeconds()) >= keepingTime;
return isStale;
// More advanced filtering could take into account the message type and/or application-level contents.
}
bool onResendRequest(Message& message, Session*) override
{
std::cout << "Resend request for message " << message << std::endl;
bool allowResending = !isStale(message);
std::cout << "AllowResending=" << (allowResending ? "true" : "false") << std::endl;
return allowResending;
}
};

Process Large Sequence Numbers Intervals of Resend Requests

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.