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