protected abstract void LogToDatabase(string strMessage); // Add other parameters later. private void ReadTargetsFromDatabase() { List <Target> lstEnabledTargets = new List <Target>(); MySqlConnection con = DatabaseConnectionProvider.GetMySqlConnection(); // ThAW TO_DO 2009/08/26 : Use a Select command that only selects enabled targets that are associated with enabled accounts. string strCommandText = Target.SelectAllCommand; using (MySqlCommand cmd = new MySqlCommand(strCommandText, con)) { using (MySqlDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { Target target = new Target(reader, false); // Do not close the reader after constructing the object if (target.Enabled) { lstEnabledTargets.Add(target); } } } } foreach (Target target in lstEnabledTargets) { target.FinishConstruction(con); m_pqWaitingTargets.Enqueue(target); LogToConsole(string.Format(@"Constructed and enqueued the enabled target named '{0}'", target.Name)); } }
public void Run() { LogToConsole(@"Flare main loop: start"); lock (this) { m_eServiceStatus = FlareServiceStatus.Started; } try { m_pqWaitingTargets.Clear(); m_qTargetsReadyForTesting.Clear(); ReadTargetsFromDatabase(); MySqlConnection con = DatabaseConnectionProvider.GetMySqlConnection(); m_lstAllContacts = Contact.GetAllContacts(con); m_dictSystemConfigurationEntries = SystemConfigurationEntry.GetDictionary(con); if (m_pqWaitingTargets.IsEmpty()) { LogToConsole(@"Aborting: The priority queue is empty; there are no servers to monitor."); return; } // The main loop begins here. TimeSpan tsOneSecond = new TimeSpan(0, 0, 1); TimeSpan tsLoopPeriod = new TimeSpan(0, 0, 1); bool bLimitNumberOfMainLoopIterations = (NumberOfMainLoopIterations > 0); LogToConsole(@"Starting the main loop..."); for (int nMainLoopIterationNumber = 0; !bLimitNumberOfMainLoopIterations || nMainLoopIterationNumber < NumberOfMainLoopIterations; ++nMainLoopIterationNumber) { DateTime dtNow = DateTime.UtcNow; LogToConsole(string.Format(@"It is now {0}.", dtNow.ToLongTimeString())); if (m_pqWaitingTargets.IsEmpty()) { LogToConsole(@"The priority queue is empty; sleeping for one second."); System.Threading.Thread.Sleep(tsOneSecond); continue; } Target targetHead = m_pqWaitingTargets.Peek(); LogToConsole(string.Format(@"The target at the head of the queue ('{0}') is due to be tested at {1}.", targetHead.Name, targetHead.DateTimeOfNextMonitor.ToLongTimeString())); if (dtNow < targetHead.DateTimeOfNextMonitor) { TimeSpan tsDifference = targetHead.DateTimeOfNextMonitor - dtNow; TimeSpan tsTimeSpanToSleep = (tsDifference < tsLoopPeriod) ? tsDifference : tsLoopPeriod; LogToConsole(string.Format(@"It is not yet time to test the target at the head of the queue. Sleeping for {0} seconds and {1} milliseconds...", tsTimeSpanToSleep.Seconds, tsTimeSpanToSleep.Milliseconds)); System.Threading.Thread.Sleep(tsTimeSpanToSleep); continue; } lock (m_qTargetsReadyForTesting) { m_qTargetsReadyForTesting.Enqueue(m_pqWaitingTargets.Dequeue()); } #if MULTITHREAD_TARGET_TESTING // Note: There is also a delegate named ParameterizedThreadStart; perhaps it may be useful // in allowing us to pass a TargetInfo object as a parameter, thus avoiding the m_qTargetsReadyForTesting queue. Thread thread = new Thread(new ThreadStart(ThreadMain_TestTarget)); thread.Start(); #else ThreadMain_TestTarget(); #endif lock (this) { if (m_eServiceStatus == FlareServiceStatus.StopRequested) { break; } } } } catch (Exception ex) { LogToConsole(string.Format(@"{0} caught: {1}", ex.GetType().FullName, ex.Message)); } lock (this) { m_eServiceStatus = FlareServiceStatus.Stopped; } LogToConsole(@"Flare main loop: end"); }
private void ThreadMain_TestTarget() { LogToConsole(@"**** Thread starting ****"); Target target = null; lock (m_qTargetsReadyForTesting) { if (m_qTargetsReadyForTesting.Count <= 0) { // Throw an exception when we attempt to Dequeue() ? return; } target = m_qTargetsReadyForTesting.Dequeue(); } LogToConsole(string.Format(@"Testing the target {0} (at {1}).", target.Name, target.URL)); // In a separate thread: // - HTTP Post to the target // - Handle any errors (by logging to a database and sending e-mail(s)) // - Re-enqueue the TargetInfo object while the priority queue is locked. TargetLogRecord tlr = null; switch (target.MonitorType) { case MonitorType.eHTTPGet: tlr = GetFromTarget(target); break; case MonitorType.eHTTPPost: tlr = PostToTarget(target); break; case MonitorType.ePing: tlr = PingTarget(target); break; // Default case: Throw an exception? } if (tlr != null) { MySqlConnection con = DatabaseConnectionProvider.GetMySqlConnection(); tlr.Insert(con); target.UpdateLastTargetLogID(tlr.LogID, con); if (tlr.Status == TargetLogRecordStatus.Fail) { // Send an e-mail to each of the target's account's contacts. SendFailureNotificationEmails(target, tlr); } } //target.LastMonitoredAt = DateTime.UtcNow; target.UpdateLastMonitoredAt(DateTime.UtcNow, DatabaseConnectionProvider.GetMySqlConnection()); target.DateTimeOfNextMonitor = target.LastMonitoredAt.Value + target.MonitorIntervalAsTimeSpan; // or += target.MonitorIntervalAsTimeSpan; // Update the target's LastMonitoredAt in the database m_pqWaitingTargets.Enqueue(target); LogToConsole(string.Format(@"The target {0} has been dequeued, bumped, and re-enqueued.", target.Name)); LogToConsole(@"**** Thread ending ****"); }