using Maat.Data.DbModels;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Maat.Core.Enums;
namespace Maat.Data.Controllers
{
public class MsSqlController : IDisposable
{
#region Public Constructors
///
/// Avvio Controller ThreadRun x DB
///
/// nome del thread di esecuzione
/// stringa di connessione da impiegare
/// timeout esecuzione comandi (minuti)
public MsSqlController(string threadName, string cString, int cmdExecTOut)
{
tName = threadName;
connString = cString;
cmdTimeout = cmdExecTOut;
Log.Info($"{tName} | Avviata classe MsSqlController");
}
#endregion Public Constructors
#region Public Methods
public DateTime CalcNextExe(TaskListModel taskRec)
{
DateTime dtNext = DateTime.Today;
DateTime adesso = DateTime.Now;
int maxIter = 1000;
try
{
// prendo come partenza la DATA di fine a cui aggiungo l'ora/minuti schedulata precedentemente
TimeSpan oraSched = taskRec.DtNextExec.Subtract(taskRec.DtNextExec.Date);
DateTime baseDT = taskRec.DtLastExec.Date.Add(oraSched);
// calcolo next exec da tipo... con ciclo fino a quando supero dataora attuale...
while (dtNext < adesso && maxIter > 0)
{
switch (taskRec.Freq)
{
case TaskFreqType.ND:
dtNext = baseDT.AddDays(taskRec.Cad);
break;
case TaskFreqType.Sec:
dtNext = baseDT.AddSeconds(taskRec.Cad);
break;
case TaskFreqType.Min:
dtNext = baseDT.AddMinutes(taskRec.Cad);
break;
case TaskFreqType.Hour:
dtNext = baseDT.AddHours(taskRec.Cad);
break;
case TaskFreqType.Day:
dtNext = baseDT.AddDays(taskRec.Cad);
break;
case TaskFreqType.Week:
dtNext = baseDT.AddDays(7 * taskRec.Cad);
break;
case TaskFreqType.Month:
dtNext = baseDT.AddMonths(taskRec.Cad);
break;
case TaskFreqType.Year:
dtNext = baseDT.AddYears(taskRec.Cad);
break;
default:
dtNext = baseDT.AddDays(taskRec.Cad);
break;
}
baseDT = dtNext;
maxIter--;
}
}
catch (Exception exc)
{
Log.Error($"Eccezione in CalcNextExe{Environment.NewLine}{exc}");
}
return dtNext;
}
public void Dispose()
{
}
///
/// Chiamata esecuzione di un singolo task programmato
///
///
/// Se true rischedula successiva chiamata
///
public TaskResultModel ExecuteSqlTask(int TaskId, bool SchedNext)
{
TaskResultModel callRes = new TaskResultModel();
using (var dbCtx = new TaskRunContext(connString))
{
// imposto timeout a 5 min
dbCtx.Database.SetCommandTimeout(TimeSpan.FromMinutes(cmdTimeout));
string sqlCall = "";
try
{
DateTime dtStart = DateTime.Now;
// recupero i dati da richiamare...
var currRec = dbCtx
.DbSetTaskList
.Where(x => x.TaskId == TaskId)
.FirstOrDefault();
if (currRec != null)
{
// recupero comando
string sqlCommand = currRec.Command;
string rawParams = currRec.Args;
// salvo la call x eventuale log errore
sqlCall = $"EXEC {sqlCommand} {rawParams}";
var rawData = dbCtx
.DbSetTaskResult
.FromSqlRaw($"EXEC {sqlCommand} {rawParams}")
.ToList();
callRes = rawData.FirstOrDefault() ?? new TaskResultModel();
DateTime dtEnd = DateTime.Now;
// preparo record esecuzione...
TaskExecModel resRec = new TaskExecModel()
{
TaskId = TaskId,
DtStart = dtStart,
DtEnd = dtEnd,
IsError = callRes.ExecResult < 0,
Result = callRes.TextResult
};
dbCtx
.DbSetTaskExe
.Add(resRec);
// aggiorno record chiamata...
currRec.DtLastExec = dtStart;
currRec.LastResult = resRec.Result;
currRec.LastIsError = resRec.IsError;
currRec.LastDuration = dtEnd.Subtract(dtStart).TotalSeconds;
// solo se richiesto rischedulazione ricalcola chiamata
if (SchedNext)
{
// calcolo prossima esecuzione...
currRec.DtNextExec = CalcNextExe(currRec);
}
// segno modificato
dbCtx.Entry(currRec).State = EntityState.Modified;
// salvo modifiche!
dbCtx.SaveChanges();
}
}
catch (Exception exc)
{
string excMsg = $"{tName} | Eccezione in ExecuteSqlTask{Environment.NewLine}Call eseguita:{Environment.NewLine}{sqlCall}{Environment.NewLine}------- Stack Eccezione -------{Environment.NewLine}{exc}";
callRes.ExecResult = -1;
callRes.TextResult = excMsg;
Log.Error(excMsg);
}
}
return callRes;
}
///
/// Esegue registrazione di un Task generico (NON SQL)
///
///
/// Se true rischedula successiva chiamata
/// Record esecuzione task esterno
///
public TaskResultModel TaskExecSaveExecuted(int TaskId, bool SchedNext, TaskExecModel ResRec)
{
TaskResultModel callRes = new TaskResultModel();
using (var dbCtx = new TaskRunContext(connString))
{
try
{
// recupero i dati da richiamare...
var currRec = dbCtx
.DbSetTaskList
.Where(x => x.TaskId == TaskId)
.FirstOrDefault();
if (currRec != null)
{
// registro task ricevuto
dbCtx
.DbSetTaskExe
.Add(ResRec);
// aggiorno record chiamata...
currRec.DtLastExec = ResRec.DtStart;
currRec.LastResult = ResRec.Result;
currRec.LastIsError = ResRec.IsError;
currRec.LastDuration = ResRec.DtEnd.Subtract(ResRec.DtStart).TotalSeconds;
// solo se richiesto rischedulazione ricalcola chiamata
if (SchedNext)
{
// calcolo prossima esecuzione...
currRec.DtNextExec = CalcNextExe(currRec);
}
// segno modificato
dbCtx.Entry(currRec).State = EntityState.Modified;
// salvo modifiche!
dbCtx.SaveChanges();
}
}
catch (Exception exc)
{
Log.Error($"Eccezione in TaskExecSaveExecuted{Environment.NewLine}{exc}");
}
}
return callRes;
}
///
/// Ricerca task dato tipo e
///
///
///
public List TaskListGetAll(Task2ExeType TType)
{
List dbResult = new List();
using (var dbCtx = new TaskRunContext(connString))
{
dbResult = dbCtx
.DbSetTaskList
.Where(x => (TType == Task2ExeType.ND || x.TType == TType))
.OrderBy(x => x.Ordinal)
.ToList();
}
return dbResult;
}
#endregion Public Methods
#region Private Fields
private static Logger Log = LogManager.GetCurrentClassLogger();
private string connString = "";
private string tName = "";
private int cmdTimeout = 0;
#endregion Private Fields
}
}