|
@@ -26,6 +26,9 @@ namespace Quadarax.Foundation.Core.Business.Processor.Queue
|
|
|
private readonly ProcessQueueConfiguration _configuration;
|
|
private readonly ProcessQueueConfiguration _configuration;
|
|
|
private readonly IProcessorStorageProvider _storageProvider;
|
|
private readonly IProcessorStorageProvider _storageProvider;
|
|
|
private bool _isTransient;
|
|
private bool _isTransient;
|
|
|
|
|
+
|
|
|
|
|
+ private Timer _timerWatchDog;
|
|
|
|
|
+ private bool _isFirstCycle;
|
|
|
#endregion
|
|
#endregion
|
|
|
|
|
|
|
|
#region *** Constructors ***
|
|
#region *** Constructors ***
|
|
@@ -58,12 +61,17 @@ namespace Quadarax.Foundation.Core.Business.Processor.Queue
|
|
|
Log(LogSeverityEnum.Debug, $"ProcessQueue [{QueueIdentifier}] starting...");
|
|
Log(LogSeverityEnum.Debug, $"ProcessQueue [{QueueIdentifier}] starting...");
|
|
|
|
|
|
|
|
//TODO: start mechanism here
|
|
//TODO: start mechanism here
|
|
|
|
|
+ _isFirstCycle = true;
|
|
|
|
|
+ _timerWatchDog = new
|
|
|
|
|
+ Timer(OnWatchdog, this, (int) _configuration.WatchdogInterval.TotalMilliseconds, (int) _configuration.WatchdogInterval.TotalMilliseconds);
|
|
|
|
|
+
|
|
|
|
|
|
|
|
Log(LogSeverityEnum.Info, $"ProcessQueue [{QueueIdentifier}] started @{DateTime.Now.Subtract(now).ToReadableString()}");
|
|
Log(LogSeverityEnum.Info, $"ProcessQueue [{QueueIdentifier}] started @{DateTime.Now.Subtract(now).ToReadableString()}");
|
|
|
_isTransient = false;
|
|
_isTransient = false;
|
|
|
IsRunning = true;
|
|
IsRunning = true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
public void Stop()
|
|
public void Stop()
|
|
|
{
|
|
{
|
|
|
if (!IsRunning || _isTransient)
|
|
if (!IsRunning || _isTransient)
|
|
@@ -117,7 +125,7 @@ namespace Quadarax.Foundation.Core.Business.Processor.Queue
|
|
|
return (ITaskItem[])result;
|
|
return (ITaskItem[])result;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- public ITaskIdentifier[] QueryTasks(ProcessStatusEnum[] states,int maxItems, bool onlyTimeValid = true, bool includeDeleted = false)
|
|
|
|
|
|
|
+ public ITaskIdentifier[] QueryTasks(ProcessStatusEnum[] states,int maxItems, bool affinityQueue = true, bool onlyTimeValid = true, bool includeDeleted = false)
|
|
|
{
|
|
{
|
|
|
if (states == null || !states.Any()) throw new ArgumentNullException(nameof(states));
|
|
if (states == null || !states.Any()) throw new ArgumentNullException(nameof(states));
|
|
|
|
|
|
|
@@ -128,6 +136,10 @@ namespace Quadarax.Foundation.Core.Business.Processor.Queue
|
|
|
var items = _storageProvider.Query(states);
|
|
var items = _storageProvider.Query(states);
|
|
|
if (onlyTimeValid)
|
|
if (onlyTimeValid)
|
|
|
items = items.Where(x=> x.ProcessingValidFrom <= now && x.ProcessingValidTo.GetValueOrDefault(DateTime.MaxValue) >= now);
|
|
items = items.Where(x=> x.ProcessingValidFrom <= now && x.ProcessingValidTo.GetValueOrDefault(DateTime.MaxValue) >= now);
|
|
|
|
|
+
|
|
|
|
|
+ items = affinityQueue ? items.Where(x => x.AffinityToken != null && x.AffinityToken.QueueIdentifier == QueueIdentifier)
|
|
|
|
|
+ : items.Where(x => x.AffinityToken == null);
|
|
|
|
|
+
|
|
|
var result = items.OrderBy(x => x.ProcessingValidFrom)
|
|
var result = items.OrderBy(x => x.ProcessingValidFrom)
|
|
|
.ThenBy(x => x.Priority)
|
|
.ThenBy(x => x.Priority)
|
|
|
.Take(maxItems)
|
|
.Take(maxItems)
|
|
@@ -143,6 +155,40 @@ namespace Quadarax.Foundation.Core.Business.Processor.Queue
|
|
|
|
|
|
|
|
#region *** Private Operations ***
|
|
#region *** Private Operations ***
|
|
|
|
|
|
|
|
|
|
+ private void OnWatchdog(object? state)
|
|
|
|
|
+ {
|
|
|
|
|
+ try
|
|
|
|
|
+ {
|
|
|
|
|
+ if (_isFirstCycle)
|
|
|
|
|
+ {
|
|
|
|
|
+ // first cycle scenario
|
|
|
|
|
+ // reset previous left tasks
|
|
|
|
|
+ var forceLeftTasks = QueryTasks(new[] { ProcessStatusEnum.Started}, _configuration.WorkersCount, true,true, false);
|
|
|
|
|
+
|
|
|
|
|
+ Log(LogSeverityEnum.Debug, $"ProcessQueue [{QueueIdentifier}] Watchdog first cycle. Force reset on {forceLeftTasks.Count()} tasks.");
|
|
|
|
|
+ foreach (var task in forceLeftTasks)
|
|
|
|
|
+ {
|
|
|
|
|
+ ((ITaskItem)task).Stop("(System) Force stop of interrupted task.", true, false);
|
|
|
|
|
+ ((ITaskItem)task).Reset("(System) Reset after force stop.", TimeSpan.FromSeconds(10));
|
|
|
|
|
+ }
|
|
|
|
|
+ _isFirstCycle = false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // gets processing tasks to know thread assigned slots
|
|
|
|
|
+
|
|
|
|
|
+ // calculate free slots and assigned slots
|
|
|
|
|
+
|
|
|
|
|
+ // start assigned slots
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (Exception e)
|
|
|
|
|
+ {
|
|
|
|
|
+ Log(LogSeverityEnum.Error, e.Message, e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
protected void Log(LogSeverityEnum type, string message, Exception? e = null)
|
|
protected void Log(LogSeverityEnum type, string message, Exception? e = null)
|
|
|
{
|
|
{
|
|
|
if (type == LogSeverityEnum.Error || type == LogSeverityEnum.Fatal)
|
|
if (type == LogSeverityEnum.Error || type == LogSeverityEnum.Fatal)
|