Best Practices#
Follow these recommendations to build robust, production-ready OUCH 5.0 applications.
Session Management#
Always Attach Listeners Before Login#
Recommended: Use start_with_listeners() or async_start_with_listeners() to prevent race conditions where messages arrive before listeners are ready:
Session session(io_ctx, settings);
// Recommended: Attach listeners and login atomically
session.start_with_listeners("", 0, std::chrono::milliseconds(2000),
[](Session* s, std::uint64_t seq, const OrderAccepted* msg) {
// Handle OrderAccepted
});
Alternative: If you need to attach listeners separately, attach them before calling login() or async_login():
Session session(io_ctx, settings);
// Attach listeners FIRST
session.attach_listener(/* handlers */);
// Then login (must be from non-IOContext thread to avoid deadlock)
session.login("", 0, std::chrono::milliseconds(2000));
Use Async Operations#
Prefer async operations (async_login, async_terminate) for non-blocking code:
// Good: Non-blocking
session.async_login("", 0, std::chrono::milliseconds(2000),
[](std::uint64_t seq, const std::error_code& ec) {
// Handle result
});
// Avoid: Blocking (unless necessary)
// session.login("", 0, std::chrono::milliseconds(2000));
UserRefNum Management#
Always Recover After Reconnection#
Always recover UserRefNum after reconnection using AccountQueryRequest:
void on_established(Session* s) {
// Recover UserRefNum immediately after connection
AccountQueryRequest query;
s->send_message(&query);
}
void on_account_query_response(Session* s, std::uint64_t seq, const AccountQueryResponse* msg) {
UInt32 next_user_ref_num = msg->get_next_user_ref_num();
s->get_user_refnum_generator().reset(next_user_ref_num);
}
Use Persistence in Production#
Enable UserRefNum persistence for production applications:
Settings settings;
UserRefNumGenerator::PersistenceSettings persistence;
persistence.file_path_ = "./user_refnum.dat";
persistence.save_interval_ = std::chrono::seconds(5);
settings.user_refnum_persistence_ = persistence;
Message Buffering#
Enable for Production#
Enable message buffering for production applications that need retransmission:
OutboundMessageBufferSettings buffer_settings;
buffer_settings.max_messages_ = 10000;
buffer_settings.max_bytes_ = 10 * 1024 * 1024;
buffer_settings.track_acknowledgments_ = true;
settings.buffer_settings_ = buffer_settings;
settings.auto_retransmit_on_reconnect_ = true;
Mark Messages as Acknowledged (Optional)#
Consider marking messages as acknowledged when you receive responses to optimize retransmission volume. This is optional - according to OUCH 5.0 specification, the exchange will ignore retransmitted messages with UserRefNum lower than the last processed one (benign retransmission), so acknowledgment tracking is an optimization, not a requirement.
void on_order_accepted(Session* s, std::uint64_t seq, const OrderAccepted* msg) {
if (auto* buffer = s->get_message_buffer()) {
buffer->mark_acknowledged(msg->get_user_ref_num());
}
}
Error Handling#
Check All Return Values#
Always check return values from send_message():
std::error_code ec = session.send_message(&order);
if (ec) {
std::cerr << "Failed to send order: " << ec.message() << std::endl;
// Handle error
}
See Error Handling Guide for detailed information on possible errors and handling recommendations.
Handle All Message Types#
Handle all message types you care about, or use a fallback handler:
session.attach_listener(
[](Session* s, std::uint64_t seq, const OrderAccepted* msg) {
// Handle OrderAccepted
},
[](Session* s, std::uint64_t seq, const Rejected* msg) {
// Handle Rejected
},
// ... other handlers ...
[](Session* s, std::uint64_t seq, const MessageView& msg) {
// Fallback for unhandled message types
std::cout << "Unhandled message type: " << msg.message_type() << std::endl;
}
);
Thread Safety#
See Thread Safety Guide for comprehensive information on thread safety requirements, including:
Operations that can be called from any thread vs. IOContext’s thread
Using
IOContext::post()for cross-thread accessThread safety for UserRefNum generator and message buffer
Best practices for multi-threaded applications
Complete examples
Order State Tracking#
Track Order State in Your Application#
Maintain your own order state tracking:
struct OrderState {
UInt32 user_ref_num_;
UInt32 quantity_;
UInt32 executed_quantity_;
OrderStatus status_;
};
std::map<UInt32, OrderState> order_states_;
void on_order_accepted(Session* s, std::uint64_t seq, const OrderAccepted* msg) {
UInt32 user_ref_num = msg->get_user_ref_num();
order_states_[user_ref_num] = OrderState{
user_ref_num,
msg->get_quantity(),
0,
OrderStatus::Accepted
};
}
Performance#
Configure CPU Affinity#
Pin threads to specific cores for performance-critical applications:
// Configure IOContext with specific CPU
// CPU affinity mask: bitmask where bit N = CPU core N
// Examples: 0x1 = CPU 0, 0x2 = CPU 1, 0x4 = CPU 2, 0x8 = CPU 3
// Combine cores: 0x3 = CPUs 0 and 1, 0x5 = CPUs 0 and 2
auto io_ctx = std::make_shared<IOContext>(
IOContext::Settings{"main", 0x1, false} // CPU 0 (0x1 = bit 0 set)
);
Avoid Blocking in Handlers#
Never perform blocking operations in message handlers:
// Bad: Blocking operation in handler
void on_order_accepted(Session* s, std::uint64_t seq, const OrderAccepted* msg) {
std::this_thread::sleep_for(std::chrono::seconds(1)); // DON'T DO THIS
}
// Good: Non-blocking handler
void on_order_accepted(Session* s, std::uint64_t seq, const OrderAccepted* msg) {
// Process immediately, or post to another thread for heavy processing
process_order_accepted(msg);
}
Code Organization#
Use Type-Safe Message Types#
Always use strongly-typed message types:
// Good: Type-safe
EnterOrder order;
order.set_user_ref_num(user_ref_num);
// Avoid: Manual message construction
// (unless absolutely necessary)
Use Price Type#
Always use the Price type for prices:
// Good: Type-safe price
order.set_price(Price::from_double(150.50));
// Avoid: Raw integer manipulation
// order.set_price_raw(1505000);
Testing#
Test Reconnection Scenarios#
Test your application’s behavior during reconnection:
Network disconnection
Server restart
UserRefNum recovery
Message retransmission
Test Error Conditions#
Test error handling:
Rejected orders
Cancel rejects
Connection failures