499 lines
19 KiB
C#
499 lines
19 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Configuration;
|
|
using MP.TaskMan.Models;
|
|
using NLog;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using static MP.TaskMan.Objects.Enums;
|
|
|
|
namespace MP.TaskMan.Controllers
|
|
{
|
|
public class MpTaskController : IDisposable
|
|
{
|
|
#region Public Constructors
|
|
|
|
public MpTaskController(IConfiguration configuration)
|
|
{
|
|
_configuration = configuration;
|
|
Log.Info("Avviato MpTaskController");
|
|
}
|
|
|
|
#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()
|
|
{
|
|
_configuration = null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Chiamata esecuzione di un singolo task programmato, SE in stato abilitato
|
|
/// </summary>
|
|
/// <param name="TaskId"></param>
|
|
/// <param name="SchedNext">Se true rischedula successiva chiamata</param>
|
|
/// <returns></returns>
|
|
public TaskResultModel ExecuteSqlTask(int TaskId, bool SchedNext)
|
|
{
|
|
TaskResultModel callRes = new TaskResultModel();
|
|
using (var dbCtx = new TaskContext(_configuration))
|
|
{
|
|
// imposto timeout a 5 min
|
|
//var currTimeout = dbCtx.Database.GetCommandTimeout();
|
|
dbCtx.Database.SetCommandTimeout(TimeSpan.FromMinutes(5));
|
|
string sqlCall = "";
|
|
try
|
|
{
|
|
DateTime dtStart = DateTime.Now;
|
|
// recupero i dati da richiamare...
|
|
var currRec = dbCtx
|
|
.DbSetTaskList
|
|
.Where(x => x.TaskId == TaskId && x.Enabled)
|
|
.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)
|
|
{
|
|
Log.Error($"Eccezione in ExecuteSqlCommand{Environment.NewLine}Call eseguita:{Environment.NewLine}{sqlCall}{Environment.NewLine}------- Stack Eccezione -------{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
return callRes;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Annulla modifiche su una specifica entity (cancel update)
|
|
/// </summary>
|
|
/// <param name="item"></param>
|
|
/// <returns></returns>
|
|
public bool RollBackEntity(object item)
|
|
{
|
|
bool answ = false;
|
|
using (var dbCtx = new TaskContext(_configuration))
|
|
{
|
|
try
|
|
{
|
|
if (dbCtx.Entry(item).State == EntityState.Deleted || dbCtx.Entry(item).State == EntityState.Modified)
|
|
{
|
|
dbCtx.Entry(item).Reload();
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Eccezione in rollBackEntity{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ricerca task dato tipo + num max (desc)
|
|
/// </summary>
|
|
/// <param name="TaskId">TaskId da cui deriva</param>
|
|
/// <returns></returns>
|
|
public List<TaskExecModel> TaskExecGetFilt(int TaskId, int maxRec)
|
|
{
|
|
List<TaskExecModel> dbResult = new List<TaskExecModel>();
|
|
using (var dbCtx = new TaskContext(_configuration))
|
|
{
|
|
dbResult = dbCtx
|
|
.DbSetTaskExe
|
|
.Include(x => x.TaskListNav)
|
|
.Where(x => (x.TaskId == TaskId))
|
|
.OrderByDescending(x => x.DtStart)
|
|
.Take(maxRec)
|
|
.ToList();
|
|
}
|
|
return dbResult;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Esegue registrazione di un Task generico (NON SQL)
|
|
/// </summary>
|
|
/// <param name="TaskId"></param>
|
|
/// <param name="SchedNext">Se true rischedula successiva chiamata</param>
|
|
/// <param name="ResRec">Record esecuzione task esterno</param>
|
|
/// <returns></returns>
|
|
public TaskResultModel TaskExecSaveExecuted(int TaskId, bool SchedNext, TaskExecModel ResRec)
|
|
{
|
|
TaskResultModel callRes = new TaskResultModel();
|
|
using (var dbCtx = new TaskContext(_configuration))
|
|
{
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Upsert record TaskExec
|
|
/// </summary>
|
|
/// <param name="rec2upd">Record da aggiornare/inserire</param>
|
|
/// <returns></returns>
|
|
public bool TaskExecUpsert(TaskExecModel rec2upd)
|
|
{
|
|
bool done = false;
|
|
using (var dbCtx = new TaskContext(_configuration))
|
|
{
|
|
try
|
|
{
|
|
var currData = dbCtx
|
|
.DbSetTaskExe
|
|
.Where(x => x.TaskExecId == rec2upd.TaskExecId)
|
|
.FirstOrDefault();
|
|
if (currData != null)
|
|
{
|
|
currData.TaskId = rec2upd.TaskId;
|
|
currData.DtStart = rec2upd.DtStart;
|
|
currData.DtEnd = rec2upd.DtEnd;
|
|
currData.IsError = rec2upd.IsError;
|
|
currData.Result = rec2upd.Result;
|
|
dbCtx.Entry(currData).State = EntityState.Modified;
|
|
}
|
|
else
|
|
{
|
|
dbCtx
|
|
.DbSetTaskExe
|
|
.Add(rec2upd);
|
|
}
|
|
dbCtx.SaveChanges();
|
|
done = true;
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Eccezione in TaskExecUpsert{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
return done;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ricerca task dato tipo e
|
|
/// </summary>
|
|
/// <param name="TType"></param>
|
|
/// <returns></returns>
|
|
public List<TaskListModel> TaskListGetAll(Task2ExeType TType)
|
|
{
|
|
List<TaskListModel> dbResult = new List<TaskListModel>();
|
|
using (var dbCtx = new TaskContext(_configuration))
|
|
{
|
|
dbResult = dbCtx
|
|
.DbSetTaskList
|
|
.Where(x => (TType == Task2ExeType.ALL || x.TType == TType))
|
|
.OrderBy(x => x.Ordinal)
|
|
.ToList();
|
|
}
|
|
return dbResult;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update ordinamento task
|
|
/// </summary>
|
|
/// <param name="rec2upd">Record da spostare x priorità</param>
|
|
/// <returns></returns>
|
|
public bool TaskListMove(TaskListModel rec2upd, bool moveUp)
|
|
{
|
|
bool done = false;
|
|
using (var dbCtx = new TaskContext(_configuration))
|
|
{
|
|
try
|
|
{
|
|
var currData = dbCtx
|
|
.DbSetTaskList
|
|
.Where(x => x.TaskId == rec2upd.TaskId)
|
|
.FirstOrDefault();
|
|
if (currData != null)
|
|
{
|
|
int actOrdinal = currData.Ordinal;
|
|
TaskListModel? otherRec = null;
|
|
// cerco, secondo richiesta, precedente o successivo
|
|
if (moveUp)
|
|
{
|
|
otherRec = dbCtx
|
|
.DbSetTaskList
|
|
.Where(x => x.Ordinal < currData.Ordinal && x.Group==currData.Group)
|
|
.OrderByDescending(x => x.Ordinal)
|
|
.FirstOrDefault();
|
|
}
|
|
else
|
|
{
|
|
otherRec = dbCtx
|
|
.DbSetTaskList
|
|
.Where(x => x.Ordinal > currData.Ordinal && x.Group == currData.Group)
|
|
.OrderBy(x => x.Ordinal)
|
|
.FirstOrDefault();
|
|
}
|
|
// inverto ordinale SE ho record
|
|
if (otherRec != null)
|
|
{
|
|
currData.Ordinal = otherRec.Ordinal;
|
|
otherRec.Ordinal = actOrdinal;
|
|
dbCtx.Entry(currData).State = EntityState.Modified;
|
|
dbCtx.Entry(otherRec).State = EntityState.Modified;
|
|
}
|
|
}
|
|
//salvo
|
|
dbCtx.SaveChanges();
|
|
done = true;
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Eccezione in TaskListUpsert{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
return done;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Riordino record di un dato gruppo (da richiamare post cambio gruppo...)
|
|
/// </summary>
|
|
/// <param name="codGroup"></param>
|
|
/// <returns></returns>
|
|
public bool TaskListReorder(int codGroup)
|
|
{
|
|
bool done = false;
|
|
using (var dbCtx = new TaskContext(_configuration))
|
|
{
|
|
// in primis recupero i record del gruppo ordinati
|
|
var currList = dbCtx
|
|
.DbSetTaskList
|
|
.Where(x => x.Group == codGroup)
|
|
.OrderBy(x => x.Ordinal)
|
|
.ThenBy(x => x.TaskId)
|
|
.ToList();
|
|
int newIdx = 0;
|
|
int numRec = currList.Count;
|
|
// li verifico in base al loro id attuale...
|
|
foreach (var item in currList)
|
|
{
|
|
newIdx++;
|
|
// se va cambiato lo riassegno
|
|
if (item.Ordinal != newIdx)
|
|
{
|
|
item.Ordinal = newIdx;
|
|
dbCtx.Entry(item).State = EntityState.Modified;
|
|
}
|
|
}
|
|
// salvo!
|
|
try
|
|
{
|
|
dbCtx.SaveChanges();
|
|
done = true;
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Eccezione in TaskListReorder{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
return done;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Upsert record TaskList
|
|
/// </summary>
|
|
/// <param name="rec2upd">Record da aggiornare/inserire</param>
|
|
/// <returns></returns>
|
|
public bool TaskListUpsert(TaskListModel rec2upd)
|
|
{
|
|
bool done = false;
|
|
using (var dbCtx = new TaskContext(_configuration))
|
|
{
|
|
try
|
|
{
|
|
var currData = dbCtx
|
|
.DbSetTaskList
|
|
.Where(x => x.TaskId == rec2upd.TaskId && rec2upd.TaskId > 0)
|
|
.FirstOrDefault();
|
|
if (currData != null)
|
|
{
|
|
currData.Ordinal = rec2upd.Ordinal;
|
|
currData.Group = rec2upd.Group;
|
|
currData.Enabled = rec2upd.Enabled;
|
|
currData.Name = rec2upd.Name;
|
|
currData.Descript = rec2upd.Descript;
|
|
currData.Command = rec2upd.Command;
|
|
currData.Args = rec2upd.Args;
|
|
currData.Freq = rec2upd.Freq;
|
|
currData.Cad = rec2upd.Cad;
|
|
currData.DtLastExec = rec2upd.DtLastExec;
|
|
currData.DtNextExec = rec2upd.DtNextExec;
|
|
currData.LastDuration = rec2upd.LastDuration;
|
|
currData.LastResult = rec2upd.LastResult;
|
|
dbCtx.Entry(currData).State = EntityState.Modified;
|
|
}
|
|
else
|
|
{
|
|
dbCtx
|
|
.DbSetTaskList
|
|
.Add(rec2upd);
|
|
}
|
|
dbCtx.SaveChanges();
|
|
done = true;
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Eccezione in TaskListUpsert{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
return done;
|
|
}
|
|
|
|
#endregion Public Methods
|
|
|
|
#region Private Fields
|
|
|
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
|
|
|
#endregion Private Fields
|
|
|
|
#region Private Properties
|
|
|
|
private static IConfiguration _configuration { get; set; } = null!;
|
|
|
|
#endregion Private Properties
|
|
}
|
|
} |