#ifndef __AlertMainControl_h_ #define __AlertMainControl_h_ #include #include #include "../../shared/ThreadClass.h" #include "../../shared/TwoDLookup.h" #include "PushAlerts.h" #include "AlertMatricies.h" /* AlertMainControl puts together a lot of the reconfigurable pieces that are * found in other units. This creates a thread for the data nodes, and another * to send messages to the database. When requested, it will create the alert * matrices in the right thread, and load these from various config files. * * This class contains a lot of potential for configuration. The constructor * sets off the list of things that always have to happen. But a separate * normalStart() function takes care of loading the standard configuration. * Potentially there could be other start routines, and the smaller routines * that implement normalStart() could be exposed. However, that all may be * overkill since normalStart() can be configured by two input files. */ class AlertMainControl : private ThreadClass, private DataNodeListener { private: enum { /* This is the normal test phase. As soon as we start the app, we do * some standard tests, like trying to attach to the datafeed. If there's * a problem, we'll know about it right away, rather than waiting until * we actually need something. (The test might be 6pm, and the real start * may be at 4am, so this is much more convenient.) With TAL and eSignal, * the initial connection was the most likely thing to fail. */ mtStartTest, /* Request some data from the market data proxy. We break this into * small pieces so this program won't be unresponsive for a long period * of time. */ mtPreload, /* Start the alerts. */ mtNormalStart, /* This is used by the datanode system to put things into this thread. * Typically the timers and the various data providers run in different * threads. But most of the alert logic runs in our thread. */ mtDataNodeEvent, /* Standard. */ mtQuit }; RequestQueue _incoming; PushAlertsThread _pushAlertsThread; TwoDArray _config; std::map< std::string, AlertMatrix * > _matrix; DataNodeManager _dataNodeManager; void loadAlertsTypes(AlertMatrix *matrix, std::string const &requirements); void normalStartImpl(std::string configFileName, std::string symbolListFileName); static std::string defaultSymbolListFile(); AlertMatrix *findMatrix(std::string const &name); void fillAlertTypesByRequirements(std::string const &requirements); void onWakeup(int msgId); std::vector< std::string > _toPreload; void initializePreLoad(); void scheduleNextPreLoadStep(); void doNextPreLoadStep(); protected: void threadFunction(); public: // This can be called from any thread. // This connects to the data provider and requests some streaming data. This // is based // on they way we tested realtick, but it's not as comprehensive. We request // data just to see if it will make us crash or lock up. We are not actually // looking at the data. This will probably be sufficient, and would // definately have helped with some of the problems I've seen. // // The plan is to add the realtick style test back. The // ../../new_market_data_proxy will send a special $TEST symbol once a minute // so we can check to see if we are connected and we can measure the latency // of that connection. // // startTest() might also request other data from the market data proxy. // The process of requesting specific symbols can be slow. This process and // the market data proxy are both slower than we'd like in this regard. // Notice that we have a special mode that helps TIQ connect a lot faster. // Notice that we don't know for certain how slow the market data proxy is, // but we do know that restarting one of these process (an alert server, // not a TIQ server) will slow down the data going to other servers. :( // That is one of the main things we want to fix with // ../../new_market_data_proxy. We might not know the exact symbols that // we need to follow until the last minute. But if we start by requesting // the same symbols we followed yesterday, that will be very close. Notice // that requesting the same data a second time is very efficient. We look // up a string in a std::map, and we increment a reference count. The market // data proxy doesn't know or care about the second request. // // The idea is to call this as soon as the program start, and to call // normalStart() when we want the alerts to start. void startTest(); // This can be called from any thread. // Calling this before midnight could cause trouble. void normalStart(std::string const &configFileName = "", std::string const &symbolListFileName = ""); // This can be called from any thread. void gracefulShutdown() { _dataNodeManager.gracefulShutdown(); } DataNodeManager &getDataNodeManager() { return _dataNodeManager; } AlertMainControl(); ~AlertMainControl(); }; #endif