using System; using System.Linq; using System.Threading; using Hangfire; using LeafWeb.Core.Entities; using LeafWeb.Core.Remote; namespace LeafWeb.Web.Services { public class PiscalQueueManager : PiscalQueueBase { private static readonly object ProcessQueueLock = new object(); public void ProcessQueue() { // prevent multiple entry into processing the queue if (Monitor.TryEnter(ProcessQueueLock)) { Logger.Trace("ProcessQueue entered"); try { UpdateRunning(); StartNextPending(); } finally { Logger.Trace("ProcessQueue exit"); Monitor.Exit(ProcessQueueLock); } } else { Logger.Trace("ProcessQueue locked, queue already processing"); } } private void StartNextPending() { var runningLeafInputs = DataService.GetRunningLeafInputs().ToList(); if (runningLeafInputs.Any()) { Logger.Trace("Leaf input currently running , don't enqueue any new"); return; } var pendingInput = DataService .GetLeafInputs(LeafInputStatusType.Pending) .OrderBy(l => l.StatusHistory.Min(sh => sh.DateTime)) .FirstOrDefault(); if (pendingInput == null) { Logger.Trace("No pending leaf input"); return; } var pendingInputId = pendingInput.Id; Logger.Info("LeafInput: {0}, Starting", pendingInputId); DataService.SetLeafInputStatus(pendingInput, LeafInputStatusType.Starting); BackgroundJob.Enqueue(c => c.DoWork(pendingInputId)); } private void UpdateRunning() { var running = DataService.GetLeafInputs(LeafInputStatusType.Running).ToList(); foreach (var leafInput in running) { try { var status = PiscalService.GetStatus(leafInput); var leafInputId = leafInput.Id; switch (status) { case PiscalStatus.NotStarted: // if it's not started - this is unusual state Logger.Warn("LeafInput: {0}, Piscal Not Started", leafInput.Id); break; case PiscalStatus.Running: Logger.Trace("LeafInput: {0}, Piscal Running", leafInput.Id); // continue running break; case PiscalStatus.Complete: // TODO: change to "retrieving output"? DataService.SetLeafInputStatus(leafInput, LeafInputStatusType.Finishing); var retrieveFilesId = BackgroundJob.Enqueue(s => s.DoWork(leafInputId)); BackgroundJob.ContinueWith(retrieveFilesId, s => s.DoWork(leafInputId)); BackgroundJob.ContinueWith(retrieveFilesId, email => email.SendLeafWebComplete(leafInputId)); BackgroundJob.ContinueWith(retrieveFilesId, s => s.DoWork(leafInputId)); break; } } catch (PiscalClientException ex) { PiscalExceptionNotify(ex, leafInput); } catch (Exception ex) { var errorMessage = FormatException(ex, leafInput.Id); Logger.Error(errorMessage); } } } } }