Message Throttling
Many venues have limits of sending messages per time unit (throttling). If an application sends messages too often, then they can be rejected.
To not exceeds the limits, there is the Throttle() method. This method performs the throttling of a session. It must be called before each of a send function call. If the count of messages per a time unit exceeds a throttling limit, the function will be blocked until the given time interval is passed.
The ThrottlingLimit(int, TimeSpan) method is used to set throttling limit parameters:
Example
const int MessagesPerSecondLimit = 10;
TimeSpan ThrottlingInterval = TimeSpan.FromSeconds(1);
const string AcceptorHost = "localhost";
const int AcceptorPort = 5000;
Message order = new Message("D", ProtocolVersion.Fix44);
Session session = new Session("Sender", "Target", ProtocolVersion.Fix44);
// Set throttling limit parameters.
session.ThrottlingLimit(MessagesPerSecondLimit, ThrottlingInterval);
session.LogonAsInitiator(AcceptorHost, AcceptorPort);
// Emulate some sending flow of an application.
for (int counter = 0; 100 > counter; ++counter)
{
// This method must be called before each of a send function call.
// If the count of messages (10 in our case) per a time unit (1 sec in our case) exceeds a throttling limit,
// this function will be blocked until the given time interval is passed.
session.Throttle();
// A regular send call, which should be throttled.
session.Send(order);
}
Also, there is the TryThrottle(bool) method. It checks the throttling of a session, but it does not block the execution.
If the count of messages per time unit exceeds the throttling limit, the function returns the delay until the sending becomes possible.
Otherwise, it returns Zero. The resetWhenDelay
flag indicates if the calculation of messages per throttling interval should be reset and started again when a delay is returned.
This method can be helpful when one needs to detect that the message's rate exceeds the limit and react in some specific way:
Example
// Emulate some sending flow of an application.
for (int counter = 0; 100 > counter; ++counter)
{
// This method must be called before each of a send function call.
// If the count of messages per time unit exceeds the throttling limit, the function returns the delay until the action becomes possible.
// Otherwise, it returns TimeSpan.Zero.
var delay = session.TryThrottle();
if (delay != TimeSpan.Zero)
{
Console.WriteLine($"$The message's rate exceeds the limit. {delay} milliseconds should be passed until the sending becomes possible.");
// Wait for the 'delay' interval or do some another specific actions if necessary.
}
// A regular send call, which should be throttled.
session.Send(order);
}
Additionally, the Throttler class can simplify implementing the throttling (rate limiting) in specific scenarios. This class has similar Throttle() / TryThrottle(bool) methods that can be used similarly. However, unlike the session's functionality, different throttler objects with different throttling limit parameters can be created and used independently of a session. This can help to implement the throttling on the acceptor's side or perform the different throttling for different message types:
Example
const int OrderSinglePerSecondLimit = 10;
const int OrderCancelRequestPerSecondLimit = 10;
TimeSpan ThrottlingInterval = TimeSpan.FromSeconds(1);
Session acceptor = new Session("Sender", "Target", ProtocolVersion.Fix44);
Throttler orderSingleThrottler = new(OrderSinglePerSecondLimit, ThrottlingInterval);
Throttler orderCancelRequestThrottler = new(OrderCancelRequestPerSecondLimit, ThrottlingInterval);
acceptor.OutboundApplicationMessage += (object sender, MessageEventArgs e) =>
{
// This method must be called before each action that should be throttled.
if (e.Message.Type == MsgType.NewOrderSingle && orderSingleThrottler.TryThrottle() != TimeSpan.Zero)
((Session)sender).SendReject(e.Message.SeqNum, "The OrderSingle message's rate exceeds the limit.");
// This method must be called before each action that should be throttled.
if (e.Message.Type == MsgType.OrderCancelRequest && orderCancelRequestThrottler.TryThrottle() != TimeSpan.Zero)
((Session)sender).SendReject(e.Message.SeqNum, "The OrderCancelRequest message's rate exceeds the limit.");
};
See Also
- The Throttling Buy Side and Throttling Sell Side from the FIX Engine distribution package