/// <summary> /// The program point of entry /// </summary> public void Run() { this._reportGeneratorEngineList = new List<Thread>(); // While "controller" is required to run from the Service outside, then keep this Main thread "busy" while (this.RunProcess) { try { #region Controller child thread execution setup and running lock (this._reportGeneratorEngineList) { // If no more reports are busy generating, then smoke all temp files if (this._reportGeneratorEngineList.Count == 0) { string[] tempFiles = Directory.GetFiles(this._Configuration.TempFileDirectory); if (tempFiles != null && tempFiles.Length > 0) { for (int i = 0; i < tempFiles.Length; i++) { try { File.Delete(tempFiles[i]); } catch { } } } } // Remove all threads from the processing thread queue, that is not executing a report at the moment IList<Thread> finishedProcesses = this._reportGeneratorEngineList.Where(entity => (entity.ThreadState != System.Threading.ThreadState.Running && entity.ThreadState != System.Threading.ThreadState.Unstarted && entity.ThreadState != System.Threading.ThreadState.WaitSleepJoin)).ToList(); for (int i = 0; i < finishedProcesses.Count; i++) { Thread runner = finishedProcesses[i]; this._reportGeneratorEngineList.Remove(runner); runner = null; } // If any ReportStatusId == 2 and the ReportGenerationQueueId is not in the list // of threads that is executing the reports anymore, then 'RESET' the item, for regeneration // & increase the retry count using (GenerationDao generationDao = DataAccessFactory.Create<GenerationDao>()) { List<ReportGenerationQueue> processingReportList = generationDao.FindAll<ReportGenerationQueue>(queue => queue.ReportGenerationStatus == ReportStatus.Processing).ToList(); if (processingReportList != null && processingReportList.Count > 0) { foreach (ReportGenerationQueue item in processingReportList) { Thread runningApplication = this._reportGeneratorEngineList.FirstOrDefault(entity => entity.Name == item.ReportGenerationQueueId.ToString()); if (runningApplication == null) { // this item in set to running in DB, but is not in current executing threads anymore // hence this might be a report that generated a fatal exception, that can be recovered & rescheduled this.ReportQueueStatusService.UpdateReportGenerationQueue(new ReportGenerationQueueStatusDto() { NumberOfRetries = item.NumberOfRetries + 1, ReportStatus = ReportStatus.Queued }); } } } } // First the CanRunConcurrently = 0 (all the ALL reports) while (this._reportGeneratorEngineList.Count < this._Configuration.ParallelProcessCount) { using (GenerationDao generationDao = DataAccessFactory.Create<GenerationDao>()) { List<ReportGenerationQueue> scheduledReportList = generationDao .FindAll<ReportGenerationQueue>(queue => queue.ReportGenerationStatus == ReportStatus.Queued).OrderBy(entity => entity.ReportGenerationQueueId).ToList(); // This will limit the requested reports in the "DEVELOPMENT" environment to only execute the // current user that is running the process application scheduledReportList = this.FilterQueueForUser(scheduledReportList); ReportGenerationQueue queuedReport = scheduledReportList.FirstOrDefault(); if (queuedReport == null) { break; } this.ReportQueueStatusService.UpdateReportGenerationQueue(new ReportGenerationQueueStatusDto() { ReportGenerationQueueId = queuedReport.ReportGenerationQueueId, ReportStatus = ReportStatus.Processing }); // Create a report generator and parameters based on report type AbstractReportGenerator reportGenerator = null; try { reportGenerator = ReportGeneratorFactory.GetReportGenerator(queuedReport.ReportGenerationQueueId); } catch (Exception e) { AbstractReportGenerator.UpdateQueuedReportStatus( this.ReportQueueStatusService, queuedReport.ReportGenerationQueueId, ReportStatus.Failed, string.Format("ReportGeneratorFactory.GetReportGenerator: {0}", e.Message)); throw; } Thread hostedApp = new Thread(new ThreadStart(() => { try { reportGenerator.GenerateReport(); } catch (Exception e) { AdaptableErrorHandler.AdaptableErrorHandlerInstance.HandleError("Application", "GRP.ReportQueue.Processor.AbstractReportGenerator.Generate()", e); } })); // Thread hostedApp = new Thread(new ThreadStart(reportGenerator.GenerateReport)); hostedApp.Name = queuedReport.ReportGenerationQueueId.ToString(); hostedApp.Start(); this._reportGeneratorEngineList.Add(hostedApp); } } GC.Collect(); } #endregion System.Threading.Thread.Sleep(this.DatabaseQueuePollInterval); } catch (Exception ex) { // This is to stop the service from emailling the same message 1 million times // The error will only be logged if it does not exist yet or if the same error is older than 12 hour ErrorItem item = this._ErrorList.FirstOrDefault(entity => entity.ExceptionMessage == ex.ToString()); bool addItem = false; if (item != null) { TimeSpan ts = DateTime.Now - item.ErrorDate; if (ts.Hours > 12) { item.ErrorDate = DateTime.Now; addItem = true; } } else { addItem = true; } if (addItem) { ErrorItem newItem = new ErrorItem(); newItem.ErrorDate = DateTime.Now; newItem.ExceptionMessage = ex.ToString(); this._ErrorList.Add(newItem); AdaptableErrorHandler.AdaptableErrorHandlerInstance.HandleError("Application", "GRP.ReportGenerationController", ex); } } } // Wait for 5 seconds and then Abort all client threads, to allow "SAFE" stop of service process System.Threading.Thread.Sleep(5000); // Clean up all the locally created thread and confirm each have completed or is requested to aborted try { if (this._reportGeneratorEngineList != null) { for (int i = 0; i < this._reportGeneratorEngineList.Count; i++) { this._reportGeneratorEngineList[i] = null; System.Threading.Thread.Sleep(100); } } } catch (ApplicationException ex) { AdaptableErrorHandler.AdaptableErrorHandlerInstance.HandleError("Application", "GRP.ReportGenerationController", ex); } }
/// <summary> /// Handles the exception. /// </summary> /// <param name="ex">The ex.</param> private void HandleException(Exception ex) { // This is to stop the service from emailling the same message 1 million times // The error will only be logged if it does not exist yet or if the same error is older than 12 hour ErrorItem item = this._ErrorList.FirstOrDefault(entity => entity.ExceptionMessage == ex.ToString()); bool addItem = false; if (item != null) { TimeSpan ts = DateTime.Now - item.ErrorDate; if (ts.Hours > 12) { item.ErrorDate = DateTime.Now; addItem = true; } } else { addItem = true; } if (addItem) { ErrorItem newItem = new ErrorItem(); newItem.ErrorDate = DateTime.Now; newItem.ExceptionMessage = ex.ToString(); this._ErrorList.Add(newItem); AdaptableErrorHandler.AdaptableErrorHandlerInstance.HandleError("Application", "GRP.ReportGenerationController", ex); } }