232 lines
8.1 KiB
C#
232 lines
8.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Web;
|
|
using System.Threading.Tasks;
|
|
|
|
using C4IT.FASD.Base;
|
|
using C4IT.Logging;
|
|
|
|
using static C4IT.Logging.cLogManager;
|
|
using static C4IT.FASD.Base.cF4SDHealthCardRawData;
|
|
using System.Threading;
|
|
|
|
namespace C4IT.DataHistoryProvider
|
|
{
|
|
public class cSuccessorJob
|
|
{
|
|
public List<string> Tables = new List<string>();
|
|
public cF4SDHealthCardRawData data = null;
|
|
public Task<bool> task = null;
|
|
public CancellationToken Token = CancellationToken.None;
|
|
public bool Finished = false;
|
|
public DateTime FinishedTime;
|
|
public List<Int64> Usage = null;
|
|
}
|
|
|
|
public class SuccessorEntry : List<cSuccessorJob>
|
|
{
|
|
public List<Int64> UsageInfo = null;
|
|
}
|
|
|
|
public static class SuccessorCache
|
|
{
|
|
private static Timer _timerCache = new Timer(callbackTimerCache, null, 1000, 10000);
|
|
|
|
private static void callbackTimerCache(object state)
|
|
{
|
|
var myNow = DateTime.UtcNow;
|
|
lock (Cache)
|
|
{
|
|
var lstIds = new List<Guid>();
|
|
|
|
foreach (var Entry in Cache)
|
|
{
|
|
var lstJobs = new List<cSuccessorJob>();
|
|
foreach (var Job in Entry.Value)
|
|
{
|
|
if (Job.Finished && (myNow - Job.FinishedTime) > TimeSpan.FromSeconds(60))
|
|
lstJobs.Add(Job);
|
|
}
|
|
|
|
foreach (var Job in lstJobs)
|
|
Entry.Value.Remove(Job);
|
|
|
|
if (Entry.Value.Count == 0)
|
|
lstIds.Add(Entry.Key);
|
|
}
|
|
|
|
foreach (var id in lstIds)
|
|
Cache.Remove(id);
|
|
}
|
|
}
|
|
|
|
private static Dictionary<Guid, SuccessorEntry> Cache = new Dictionary<Guid, SuccessorEntry>();
|
|
|
|
|
|
public static bool AddTask(Guid Id, List<string> Tables, Task<List<cF4SDHealthCardRawData.cHealthCardTable>> task, List<Int64> UsageInfo, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
try
|
|
{
|
|
var Job = new cSuccessorJob();
|
|
lock (Cache)
|
|
{
|
|
if (!Cache.TryGetValue(Id, out var lst))
|
|
{
|
|
lst = new SuccessorEntry() { Job };
|
|
Cache.Add(Id, lst);
|
|
}
|
|
else
|
|
lst.Add(Job);
|
|
|
|
if (UsageInfo != null)
|
|
lst.UsageInfo = UsageInfo;
|
|
}
|
|
|
|
Job.Tables = Tables;
|
|
Job.task = Task.Run<bool>(async () =>
|
|
{
|
|
try
|
|
{
|
|
var res = await task;
|
|
Dictionary<string, cHealthCardTable> tbls = null;
|
|
if (res != null)
|
|
tbls = res.ToDictionary(x => x.Name, x => x);
|
|
lock (Cache)
|
|
{
|
|
Job.task = null;
|
|
Job.data = new cF4SDHealthCardRawData()
|
|
{
|
|
Id = Id,
|
|
Tables = tbls
|
|
};
|
|
Job.Finished = true;
|
|
Job.FinishedTime = DateTime.UtcNow;
|
|
}
|
|
return true;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
return false;
|
|
}, Token);
|
|
|
|
|
|
return true;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static async Task<cF4SDHealthCardRawData> GetNextResult(cDataHistoryCollector Collector, Guid Id, bool noAwait, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var lstResults = new SuccessorEntry();
|
|
var lstTasks = new SuccessorEntry();
|
|
var lstWaitingTables = new List<string>();
|
|
lock (Cache)
|
|
{
|
|
if (!Cache.TryGetValue(Id, out var lstObj))
|
|
return null;
|
|
|
|
foreach (var Entry in lstObj)
|
|
{
|
|
if (Entry.Finished)
|
|
lstResults.Add(Entry);
|
|
else
|
|
{
|
|
lstTasks.Add(Entry);
|
|
lstWaitingTables.AddRange(Entry.Tables);
|
|
}
|
|
}
|
|
foreach (var Entry in lstResults)
|
|
lstObj.Remove(Entry);
|
|
}
|
|
|
|
if (lstTasks.Count == 0)
|
|
Cache.Remove(Id);
|
|
|
|
if (lstResults.Count > 0)
|
|
{
|
|
var RetVal = lstResults[0];
|
|
for (int i = 1; i < lstResults.Count; i++)
|
|
{
|
|
var res = lstResults[i];
|
|
if (res?.data?.Tables != null)
|
|
{
|
|
foreach (var Entry in res.data.Tables)
|
|
{
|
|
if (RetVal?.data?.Tables != null)
|
|
RetVal.data.Tables[Entry.Key] = Entry.Value;
|
|
else
|
|
{
|
|
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
}
|
|
}
|
|
foreach (var Table in lstWaitingTables)
|
|
{
|
|
var tbl = new cF4SDHealthCardRawData.cHealthCardTable()
|
|
{
|
|
Name = Table,
|
|
IsIncomplete = true,
|
|
};
|
|
if (RetVal?.data?.Tables != null)
|
|
RetVal.data.Tables[Table] = tbl;
|
|
}
|
|
|
|
// correct the result due to usage information
|
|
if (RetVal.data != null && lstTasks.UsageInfo != null)
|
|
cDataHistoryCollector.CorrectUsage(Collector, RetVal.data, lstTasks.UsageInfo);
|
|
|
|
return RetVal.data;
|
|
}
|
|
|
|
if (noAwait)
|
|
return null;
|
|
|
|
var arrTask = new Task<bool>[lstTasks.Count];
|
|
for (int i = 0; i < lstTasks.Count; i++)
|
|
arrTask[i] = lstTasks[i].task;
|
|
|
|
var tskFinished = await Task.WhenAny(arrTask);
|
|
|
|
return await GetNextResult(Collector, Id, true, requestInfo, LogDeep+1);
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
}
|
|
} |