using System; using System.Linq; using System.Threading; using LeafWeb.Core.DAL; using LeafWeb.Core.Entities; using LeafWeb.Core.Remote; using NLog; namespace LeafWeb.Web.Services { public class PiscalQueueManager : IDisposable { private readonly DataService _dataService; private readonly PiscalService _piscalService; public PiscalQueueManager(DataService dataService, PiscalService piscalService) { _dataService = dataService; _piscalService = piscalService; } public PiscalQueueManager() : this(new DataService(), new PiscalService()) {} private static readonly object ProcessQueueLock = new object(); public void ProcessQueue() { var logger = LogManager.GetCurrentClassLogger(); if (Monitor.TryEnter(ProcessQueueLock)) { logger.Trace("ProcessQueue entered"); try { ProcessRunning(logger); ProcessQueue(logger); } finally { logger.Trace("ProcessQueue exit"); Monitor.Exit(ProcessQueueLock); } } else { logger.Trace("ProcessQueue locked, queue already processing"); } } private void ProcessQueue(ILogger logger) { var runningLeafInputFiles = _dataService.GetLeafInputFiles(LeafInputStatusType.Running).ToList(); if (runningLeafInputFiles.Any()) return; var queuedFile = _dataService .GetLeafInputFiles(LeafInputStatusType.Queued) .OrderBy(l => l.StatusHistory.Min(sh => sh.DateTime)) .FirstOrDefault(); if (queuedFile == null) return; logger.Info("LeafInputFile: {0}, Start", queuedFile.Id); try { _piscalService.Run(queuedFile); } catch (PiscalClientException ex) { logger.Error("LeafInputFile: {0}, ProcessQueue Exception: {1}", queuedFile.Id, ex.Message); _dataService.SetLeafInputFileStatus(queuedFile, LeafInputStatusType.Error, "Error occurred submitting LeafInput"); // TODO: re-queue //_dataService.SetLeafInputFileStatus(queuedFile, LeafInputStatusType.Queued, "Re-queuing LeafInput"); } _dataService.SetLeafInputFileStatus(queuedFile, LeafInputStatusType.Running); } private void ProcessRunning(ILogger logger) { var runningLeafInputFiles = _dataService.GetLeafInputFiles(LeafInputStatusType.Running).ToList(); foreach (var file in runningLeafInputFiles) { var status = _piscalService.GetStatus(file); try { switch (status) { case PiscalStatus.Running: logger.Trace("LeafInputFile: {0}, Running", file.Id); // continue running break; case PiscalStatus.Success: logger.Info("LeafInputFile: {0}, Success", file.Id); // collect the leaf output var leafOutputFiles = _piscalService.RetrieveOutputFiles(file).ToList(); foreach (var outputFile in leafOutputFiles) _dataService.AddLeafOutputFile(outputFile); logger.Info("LeafInputFile: {0}, output files: {1}", file.Id, string.Join(", ", leafOutputFiles.Select(o => o.Filename))); // update db _dataService.SetLeafInputFileStatus(file, LeafInputStatusType.Complete); // remove working data from the server logger.Info("LeafInputFile: {0}, Cleanup", file.Id); _piscalService.Cleanup(file); break; case PiscalStatus.NotStarted: logger.Warn("LeafInputFile: {0}, Not Started, re-queueing", file.Id); // if it's not started, try to requeue the process - unusual state _dataService.SetLeafInputFileStatus(file, LeafInputStatusType.Queued); break; case PiscalStatus.Error: logger.Info("LeafInputFile: {0}, Error", file.Id); var errorMessage = _piscalService.GetErrorMessage(file); logger.Info("LeafInputFile: {0}, Error Message: {1}", file.Id, errorMessage); _dataService.SetLeafInputFileStatus(file, LeafInputStatusType.Error, errorMessage); break; } } catch (PiscalClientException ex) { logger.Error("LeafInputFile: {0}, ProcessRunning Exception: {1}", file.Id, ex.Message); _dataService.SetLeafInputFileStatus(file, LeafInputStatusType.Error, "Error occurred processing LeafInput"); // TODO: re-queue } } } public void Dispose() { _dataService.Dispose(); } } }