Files
2025-11-11 11:12:05 +01:00

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;
}
}
}