This sample demonstrates all aspects of the session scheduler functionality.
#include "../../Common/Helpers.h"
#include "../../Common/Settings.h"
using namespace Settings;
namespace {
{
public:
void onInboundApplicationMsg(Message &, Session *) final {}
};
};
struct SchedulingTimeSpan {
{
public:
: span_(span) {
}
int span() const {
return span_;
}
private:
int span_;
};
};
{
constexpr int SecondsPerMinute = 60;
constexpr int MinutesPerHour = 60;
constexpr int HoursPerDay = 24;
constexpr int SecondsPerHour = SecondsPerMinute * MinutesPerHour;
constexpr int SecondsPerDay = HoursPerDay * SecondsPerHour;
int sinceMidnight = (time.
sinceMidnight() + seconds.span()) % SecondsPerDay;
if(sinceMidnight < 0)
sinceMidnight += SecondsPerDay;
sinceMidnight / SecondsPerHour,
(sinceMidnight / SecondsPerMinute) % MinutesPerHour,
sinceMidnight % SecondsPerMinute);
}
{
void onStateChange(SessionState::Enum newState, SessionState::Enum ,
Session * session) final {
std::cout << static_cast<const std::string &>(*session) << " changed its state to " <<
SessionState::toString(newState) << '.' << std::endl;
}
void onInboundApplicationMsg(Message &, Session *) final {
;
}
};
{
public:
SchedulingIssueDetector() : failed_(false)
{
}
bool failed() const
{
return failed_;
}
void onLoggingOut(const SessionScheduler & , Session * , bool * ) final
{}
void onInitiatorConnecting(const SessionScheduler & , Session * , const Counterparty & ) final
{}
void onWarning(const SessionScheduler & , Session * session, const std::string & warningReason) final
{
std::cout << "Scheduler reported a warning for the session " << static_cast<const std::string &>(*session) << ": " << warningReason;
}
void onError(const SessionScheduler & , Session * session, const std::string & errorReason) final
{
recordFailure();
std::cout << "Error occurred while scheduling session " << static_cast<const std::string &>(*session) << ": " << errorReason;
}
private:
void recordFailure()
{
failed_ = true;
}
mutable OnixS::Threading::Mutex failureMutex_;
bool failed_;
};
class Sample
{
public:
explicit Sample(SchedulerThreadingModel::Enum model):
threadingModel_(model),
reactor_(threadingModel_ == SchedulerThreadingModel::ExternalThread ? new TCPStandard::Stack() : nullptr),
engineShutdownGuard_(reactor_.get()),
shutdownState_(ShutdownRequired)
{
representYourself();
initializeFixEngine();
constructSessions();
constructScheduler();
}
~Sample() noexcept
{
if(shutdownState_ == ShutdownComplete)
return;
shutdownForException();
}
void shutdown()
{
shutdownComponents();
shutdownState_ = ShutdownComplete;
}
void run() {
acceptor_->resetLocalSequenceNumbers();
initiator_->resetLocalSequenceNumbers();
acceptor_->logonAsAcceptor();
std::cout << "Scheduling Initiator session " << static_cast<const std::string &>
(*initiator_) << " for automatic connection." << std::endl;
SessionSchedule initiatorSchedule = constructShortTimeActivitySchedule();
InitiatorConnectionSettings initiatorConnectivity("localhost", ListenPort);
scheduler_->add(initiator_.get(), initiatorSchedule, initiatorConnectivity);
std::cout << "Waiting for activity on scheduled session " << static_cast<const std::string &>
(*initiator_) << '.' << std::endl << std::endl;
waitUntilState(initiator_.get(), SessionState::Active);
waitUntilState(initiator_.get(), SessionState::Disconnected);
std::cout << std::endl << "Removing Initiator session " << static_cast<const std::string &>
(*initiator_) << " from scheduling service." << std::endl;
scheduler_->remove(initiator_.get());
acceptor_->logout();
}
void useConfigurationFile() {
initiator_->resetLocalSequenceNumbers();
SessionSchedulerOptions schedulerOptions;
SessionScheduler scheduler(schedulerOptions);
scheduler.add(initiator_.get(), "ScheduleId", "ConnectionId");
scheduler.remove(initiator_.get());
}
private:
enum ShutdownState
{
ShutdownRequired,
ShutdownComplete
};
SchedulerThreadingModel::Enum threadingModel_;
EngineShutdownGuard engineShutdownGuard_;
ShutdownState shutdownState_;
MySessionListener acceptorListener_;
SessionStateChangeTracer initiatorStateChangeTracer_;
SchedulingIssueDetector schedulingIssueDetector_;
void shutdownComponents()
{
scheduler_.reset();
initiator_->shutdown();
initiator_.reset();
acceptor_->shutdown();
acceptor_.reset();
}
{
if(session.get() == nullptr)
return;
try
{
session->shutdown();
}
catch(const std::exception & ex)
{
std::clog << "Session shutdown failed during exception cleanup: " << ex.what() << std::endl;
}
catch(...)
{
std::clog << "Session shutdown failed during exception cleanup with an unknown error." << std::endl;
}
session.reset();
}
void shutdownForException() noexcept
{
scheduler_.reset();
shutdownSessionForException(initiator_);
shutdownSessionForException(acceptor_);
}
void constructScheduler() {
SessionSchedulerOptions schedulerOptions;
scheduler_.reset(new SessionScheduler(schedulerOptions));
}
void constructSessions() {
acceptor_.reset(new Session(TargetCompId, SenderCompId, FixProtocolVersion, &acceptorListener_));
initiator_.reset(new Session(reactor_.get(), SenderCompId, TargetCompId, FixProtocolVersion, &initiatorStateChangeTracer_));
}
static SessionSchedule constructShortTimeActivitySchedule() {
TimeOfDay now = TimeOfDay::now();
TimeOfDay logonTime = now + SchedulingTimeSpan::Seconds(5);
TimeOfDay logoutTime = logonTime + SchedulingTimeSpan::Seconds(sessionActivityTimeInSeconds());
{
logonTime = TimeOfDay::midnight();
logoutTime = logonTime + SchedulingTimeSpan::Seconds(sessionActivityTimeInSeconds());
}
return SessionSchedule(
DayOfWeek::Monday,
DayOfWeek::Sunday,
logonTime,
logoutTime,
SessionDuration::Day,
SequenceNumberResetPolicy::Never);
}
void waitUntilState(Session * session, SessionState::Enum state) {
const unsigned oneSecondPause = 1000;
const int spinWaitMicrosecondPause = 10;
while(session->
state() != state)
{
if(schedulingIssueDetector_.failed())
throw std::runtime_error("Session scheduling failed.");
if(threadingModel_ == SchedulerThreadingModel::DedicatedThreads)
else
{
scheduler_->dispatchEvents();
reactor_->dispatchEvents();
}
}
}
static void initializeFixEngine() {
EngineSettings settings;
Engine::init(settings);
}
static int sessionActivityTimeInSeconds() {
return 30;
}
void representYourself() {
std::cout << "OnixS C++ FIX Engine Session Scheduling Sample with " << SchedulerThreadingModel::toString(threadingModel_) << "." << std::endl << std::endl;
std::cout << "Usage: SessionScheduler threadingModel[DedicatedThreads][ExternalThread]" << std::endl << std::endl;
}
};
int main(int argc, char * argv[])
{
try {
const std::string
ThreadingModel = (argc > 1 ? argv[1] :
"DedicatedThreads");
sample.run();
sample.shutdown();
std::cout << std::endl << "Done." << std::endl;
return 0;
}
catch(const std::exception & ex) {
processSampleException(ex.what());
return 1;
}
}