Update con gestione task da DB in formato REST (es PROG)

This commit is contained in:
Samuele Locatelli
2024-10-25 19:03:13 +02:00
parent 12ec44d9ba
commit b897c7fa53
16 changed files with 408 additions and 50 deletions
+5
View File
@@ -21,6 +21,11 @@ namespace Maat.Core.CONF
/// </summary>
public MsSqlConf? MsSqlJobs { get; set; } = null;
/// <summary>
/// Area configurazione task RestApi (opzionale)
/// </summary>
public RestApiConf? RestApiJobs { get; set; } = null;
#endregion Public Properties
}
}
+70
View File
@@ -0,0 +1,70 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Maat.Core.Enums;
namespace Maat.Core.CONF
{
/// <summary>
/// Classe gestione configurazione parametri di base x gestione task da API REST
/// </summary>
public class RestApiConf
{
#region Public Properties
/// <summary>
/// Elenco dei server configurati x chiamate REST Api, ogni server ha la stessa base ApiUrl
/// </summary>
public List<SrvConf> ServerList { get; set; } = new List<SrvConf>();
#endregion Public Properties
#region Public Classes
public class SrvConf
{
#region Public Properties
/// <summary>
/// Dizionario dei metodi configurati da chiamare
/// </summary>
public List<CallConfig> CallList { get; set; } = new List<CallConfig>();
/// <summary>
/// Path di base ApiUrl del servizio
/// </summary>
public string ApiUrl { get; set; } = "";
#endregion Public Properties
}
/// <summary>
/// Configurazione singola chiamata
/// </summary>
public class CallConfig
{
/// <summary>
/// Modalità chiamata tra quelle disponibili
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public RestCallType CallMode { get; set; } = RestCallType.Get;
/// <summary>
/// Risorsa da chiamare
/// </summary>
public string Resource { get; set; } = "";
/// <summary>
/// Payload assocaito alla risorsa da chiamare
/// </summary>
public string Payload { get; set; } = "";
#endregion Public Classes
}
}
}
+40 -2
View File
@@ -26,7 +26,17 @@ namespace Maat.Core
/// <summary>
/// Chiamata a SQL Stored Procedure
/// </summary>
SqlStored
SqlStored,
/// <summary>
/// Chiamata REST tipo Get
/// </summary>
RestCallGet,
///// <summary>
///// Chiamata REST tipo Post
///// </summary>
//RestCallPost
}
//[JsonConverter(typeof(StringEnumConverter))]
@@ -74,7 +84,7 @@ namespace Maat.Core
}
/// <summary>
/// Tipologia di chiamata permessa
/// Tipologia di chiamata DB permessa
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum TaskCallType
@@ -89,5 +99,33 @@ namespace Maat.Core
/// </summary>
TaskList
}
/// <summary>
/// Tipologia di chiamata REST permessa
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum RestCallType
{
/// <summary>
/// Metodo Delete
/// </summary>
Delete,
/// <summary>
/// Metodo Get
/// </summary>
Get,
/// <summary>
/// Metodo Post
/// </summary>
Post,
/// <summary>
/// Metodo Put
/// </summary>
Put
}
}
}
+2 -2
View File
@@ -12,8 +12,8 @@
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NLog" Version="5.2.8" />
<PackageReference Include="StackExchange.Redis" Version="2.7.33" />
<PackageReference Include="NLog" Version="5.3.4" />
<PackageReference Include="StackExchange.Redis" Version="2.8.16" />
</ItemGroup>
</Project>
+61 -4
View File
@@ -91,8 +91,9 @@ namespace Maat.Data.Controllers
/// Chiamata esecuzione di un singolo task programmato
/// </summary>
/// <param name="TaskId"></param>
/// <param name="SchedNext">Se true rischedula successiva chiamata</param>
/// <returns></returns>
public TaskResultModel ExecuteTask(int TaskId)
public TaskResultModel ExecuteSqlTask(int TaskId, bool SchedNext)
{
TaskResultModel callRes = new TaskResultModel();
using (var dbCtx = new TaskRunContext(connString))
@@ -139,8 +140,12 @@ namespace Maat.Data.Controllers
currRec.LastResult = resRec.Result;
currRec.LastIsError = resRec.IsError;
currRec.LastDuration = dtEnd.Subtract(dtStart).TotalSeconds;
// calcolo prossima esecuzione...
currRec.DtNextExec = CalcNextExe(currRec);
// solo se richiesto rischedulazione ricalcola chiamata
if (SchedNext)
{
// calcolo prossima esecuzione...
currRec.DtNextExec = CalcNextExe(currRec);
}
// segno modificato
dbCtx.Entry(currRec).State = EntityState.Modified;
@@ -150,7 +155,59 @@ namespace Maat.Data.Controllers
}
catch (Exception exc)
{
Log.Error($"{tName} | Eccezione in ExecuteTask{Environment.NewLine}{exc}");
Log.Error($"{tName} | Eccezione in ExecuteSqlTask{Environment.NewLine}{exc}");
}
}
return callRes;
}
/// <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 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;
+4 -3
View File
@@ -20,10 +20,11 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.ILLink.Tasks" Version="8.0.3" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NLog" Version="5.2.8" />
<PackageReference Include="StackExchange.Redis" Version="2.7.33" />
<PackageReference Include="NLog" Version="5.3.4" />
<PackageReference Include="RestSharp" Version="112.1.0" />
<PackageReference Include="StackExchange.Redis" Version="2.8.16" />
</ItemGroup>
<ItemGroup>
+66 -11
View File
@@ -7,6 +7,7 @@ using static Maat.Core.Enums;
using System.Diagnostics;
using Newtonsoft.Json;
using System.Xml.Linq;
using Newtonsoft.Json.Linq;
namespace Maat.Data.Services
{
@@ -20,13 +21,16 @@ namespace Maat.Data.Services
#region Public Constructors
private RestCallService RCallService { get; set; } = null!;
/// <summary>
/// Servizio gestione Task su DB
/// </summary>
/// <param name="threadName"></param>
/// <param name="dbConnString"></param>
/// <param name="redisConnString"></param>
public MsSqlTaskService(string threadName, string dbConnString, string redisConnString)
/// <param name="apiUrl"></param>
public MsSqlTaskService(string threadName, string dbConnString, string redisConnString, string apiUrl)
{
Log.Info($"{tName} | Starting MsSqlTaskService");
tName = threadName;
@@ -46,6 +50,9 @@ namespace Maat.Data.Services
dbController = new MsSqlController(tName, dbConnString);
Log.Info($"{tName} | DbController OK");
}
// conf rest call service
RCallService = new RestCallService(apiUrl);
}
#endregion Public Constructors
@@ -64,16 +71,16 @@ namespace Maat.Data.Services
public List<TaskResultModel> CheckExecute()
{
List<TaskResultModel> answ = new List<TaskResultModel>();
List<TaskListModel> listTask = TaskListAll(Enums.Task2ExeType.ND, "");
List<TaskListModel> listTask = TaskListAll(tName, Enums.Task2ExeType.ND, "");
// verifico SE ci siano task in scadenza...
DateTime adesso = DateTime.Now;
var task2exe = listTask.Where(x => x.DtNextExec <= adesso).ToList();
List<TaskListModel> task2exe = listTask.Where(x => x.DtNextExec <= adesso).ToList();
if (task2exe != null && task2exe.Count > 0)
{
Log.Info($"{tName} | Found {task2exe.Count} task to execute");
foreach (var taskRec in task2exe)
{
TaskResultModel result = ExecuteTask(taskRec.TaskId);
TaskResultModel result = ExecuteTask(taskRec);
answ.Add(result);
}
}
@@ -93,16 +100,64 @@ namespace Maat.Data.Services
redisConn.Dispose();
}
public string CheckRestServer()
{
return RCallService.CheckServer();
}
/// <summary>
/// Chiamata esecuzione di un singolo task programmato
/// </summary>
/// <param name="tName">Nome del thread</param>
/// <param name="TaskId">TaskId</param>
/// <param name="TaskRec">Task richiesto</param>
/// <returns></returns>
public TaskResultModel ExecuteTask(int TaskId)
public TaskResultModel ExecuteTask(TaskListModel TaskRec)
{
TaskResultModel dbResult = dbController.ExecuteTask(TaskId);
Log.Info($"{tName} | Executed | TaskId: {TaskId}");
TaskResultModel dbResult = new TaskResultModel()
{
Task = $"TaskId: {TaskRec.TaskId} | {TaskRec.TType}",
ExecResult = -1,
TextResult = "Task Not recognized"
};
// verifico tipo di task ed eseguo di conseguenza...
switch (TaskRec.TType)
{
//case Task2ExeType.ND:
// break;
//case Task2ExeType.Exe:
// break;
//case Task2ExeType.SqlCommand:
// break;
case Task2ExeType.SqlStored:
dbResult = dbController.ExecuteSqlTask(TaskRec.TaskId, true);
Log.Info($"{tName} | Executed | TaskRec: {TaskRec}");
break;
case Task2ExeType.RestCallGet:
// in primis testo la chiamata al servizio Health
string rAnsw = RCallService.CheckServer();
DateTime dtStart = DateTime.Now;
// se ok effettuo vera chiamata...
if (rAnsw.ToUpper() == "OK")
{
var callResp = RCallService.CallRestGet(TaskRec.Command, TaskRec.Args);
DateTime dtEnd = DateTime.Now;
// da verificare...
string formattedJson = JValue.Parse(callResp.Content).ToString(Formatting.Indented);
TaskExecModel tExeMod = new TaskExecModel()
{
DtEnd = dtEnd,
DtStart = dtStart,
IsError = callResp.StatusCode != System.Net.HttpStatusCode.OK,
TaskId = TaskRec.TaskId,
// deserializzazione come json indentato?!?
Result = formattedJson// $"{callResp.Content}".Replace("\"", ""),
};
// salvo su DB
dbResult = dbController.TaskExecSaveExecuted(TaskRec.TaskId, true, tExeMod);
}
break;
default:
break;
}
// svuoto cache!
FlushCache("Task");
return dbResult;
@@ -150,7 +205,7 @@ namespace Maat.Data.Services
/// <param name="CurrFilter"></param>
/// <param name="searchVal"></param>
/// <returns></returns>
public List<TaskListModel> TaskListAll(Task2ExeType TType, string searchVal = "")
public List<TaskListModel> TaskListAll(string threadName, Task2ExeType TType, string searchVal = "")
{
// setup parametri costanti
string source = "DB";
@@ -159,7 +214,7 @@ namespace Maat.Data.Services
List<TaskListModel> result = new List<TaskListModel>();
// cerco in redis...
DateTime adesso = DateTime.Now;
string currKey = $"{Const.RedisBaseKey}:Task:List:{TType}";
string currKey = $"{Const.RedisBaseKey}:Task:{threadName}:List:{TType}";
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
+124
View File
@@ -0,0 +1,124 @@
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NLog;
using RestSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Maat.Data.Services
{
public class RestCallService
{
#region Public Constructors
/// <summary>
/// Init classe
/// </summary>
/// <param name="ApiUrl"></param>
public RestCallService(string ApiUrl)
{
apiUrl = ApiUrl;// _configuration.GetValue<string>("SrvConf:Prog.ApiUrl") ?? "http://office.egalware.com/MP7PROG";
// fix opzioni base del RestClient
restOptStd = new RestClientOptions
{
Timeout = TimeSpan.FromSeconds(60),
BaseUrl = new Uri(apiUrl),
ThrowOnAnyError = true,
ThrowOnDeserializationError = true
};
}
private string apiUrl = "";
#endregion Public Constructors
#region Public Methods
/// <summary>
/// Stato server da chiamare x verifiche preliminari stato API REST
/// </summary>
/// <param name="ApiUrl"></param>
/// <returns></returns>
public string CheckServer()
{
string answ = "ND";
// cerco online
using (RestClient client = new RestClient(restOptStd))
{
var request = new RestRequest($"api/health", Method.Get);
try
{
var response = client.ExecuteGet(request);
//var response = await client.GetAsync(request);
// controllo risposta
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
// verifico risposta
if (response.Content != null)
{
answ = response.Content.Replace("\"", "");
//answ= JValue.Parse(response.Content).ToString(Formatting.Indented);
}
}
}
catch (Exception exc)
{
Log.Error($"Eccezione in CheckServer{Environment.NewLine}{exc}");
}
}
return answ;
}
/// <summary>
/// Effettua una generica chiamata ApiRest
/// </summary>
/// <param name="ApiUrl">URL Api di base</param>
/// <param name="ApiRequest">Richiesta completa</param>
/// <returns></returns>
public RestResponse CallRestGet(string ApiUrl, string ApiRequest)
{
RestResponse response;
var currOpt = new RestClientOptions
{
Timeout = TimeSpan.FromSeconds(60),
BaseUrl = new Uri(ApiUrl),
ThrowOnAnyError = true,
ThrowOnDeserializationError = true
};
// cerco online
using (RestClient client = new RestClient(currOpt))
{
var request = new RestRequest(ApiRequest, Method.Get);
response = client.Get(request);
}
return response;
}
#endregion Public Methods
#region Private Fields
/// <summary>
/// Classe logger
/// </summary>
private static Logger Log = LogManager.GetCurrentClassLogger();
#endregion Private Fields
#region Private Properties
/// <summary>
/// Conf client RestSharp standard:
/// - base URI al sito
/// - timeout 1 min
/// </summary>
private RestClientOptions restOptStd { get; set; } = new RestClientOptions();
#endregion Private Properties
}
}
+10 -11
View File
@@ -5,7 +5,7 @@
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>1.0.2404.1009</Version>
<Version>1.1.2410.2517</Version>
</PropertyGroup>
<ItemGroup>
@@ -19,16 +19,15 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.ILLink.Tasks" Version="8.0.3" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NLog" Version="5.2.8" />
<PackageReference Include="StackExchange.Redis" Version="2.7.33" />
<PackageReference Include="NLog" Version="5.3.4" />
<PackageReference Include="StackExchange.Redis" Version="2.8.16" />
</ItemGroup>
<ItemGroup>
@@ -41,7 +40,7 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="conf\JobConfig.json">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="logs\stderr.log">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
+9 -2
View File
@@ -29,6 +29,12 @@ string redisConf = config.GetConnectionString("Redis") ?? "?????????????????????
string confPath = Path.Combine(Directory.GetCurrentDirectory(), "conf");
Logger Log = LogManager.GetCurrentClassLogger();
string apiUrlStd = config.GetValue<string>("SrvConf:Prog.ApiUrl") ?? "";
if (string.IsNullOrEmpty(apiUrlStd))
{
Log.Error($"Errore: ApiUrl vuota!");
}
// gestore della configurazione principale da cui derivare gestione...
JobConfigConf currConf = new JobConfigConf();
@@ -105,7 +111,7 @@ if (currConf != null)
{
// compongo connstring
string dbConnStr = $"Server={currSrv.ServerName}; Database={dbName}; User ID={currSrv.DbUser}; Password={currSrv.DbPasswd}; integrated security=False; MultipleActiveResultSets=True; App={appName}";
string threadName = $"ThdMsSql_{dbName}"; ;
string threadName = $"ThdMsSql_{dbName}";
Thread newThread = new Thread(() => doCronDB(threadName, dbConnStr));
newThread.Name = threadName;
jobsThreadList.Add(newThread);
@@ -242,10 +248,11 @@ void doCronDB(string threadName, string dbConnStr)
Log.Info($"{tName} | Starting dbCronDb task");
// periodo standard 1 minuto
int stepPeriod = 60000;
MsSqlTaskService tRun = new MsSqlTaskService(tName, dbConnStr, redisConf);
MsSqlTaskService tRun = new MsSqlTaskService(tName, dbConnStr, redisConf, apiUrlStd);
// ciclo infinito esegue task poi attende quanto manca a prox scadenza...
do
{
//var testServer = tRun.CheckRestServer();
// eseguo i miei task e recupero esito
var newStatus = tRun.CheckExecute();
+2 -1
View File
@@ -30,6 +30,7 @@
"AppName": "Maat.Runner",
"StepSec": 60,
"MinSaveIntSec": 15,
"JobConfigFile": "JobConfig.json"
"JobConfigFile": "JobConfig.json",
"Prog.ApiUrl": "https://office.egalware.com/MP/PROG"
}
}
+3 -2
View File
@@ -4,10 +4,11 @@
{
"CallMode": "TaskList",
"DbList": [
"MoonPro",
"MoonPro_STATS"
],
"DbPasswd": "utente",
"DbUser": "password",
"DbPasswd": "viadante16",
"DbUser": "steamware",
"ServerName": "SQL2016DEV"
}
]
+1 -1
View File
@@ -4,7 +4,7 @@
{
"CallMode": "TaskList",
"DbList": [
"MoonPro_STATS"
"MoonPro"
],
"DbPasswd": "viadante16",
"DbUser": "steamware",
+7 -7
View File
@@ -1,6 +1,6 @@
<body>
<i>MagMan - Wood Warehouse Management System</i>
<h4>Versione: 1.0.2404.0412</h4>
<i>Maat.Installer - Manager for Application & Applicative Task</i>
<h4>Versione: 1.1.2410.2517</h4>
<br /> Note di rilascio:
<ul>
<li>
@@ -10,18 +10,18 @@
<li>
<b>v.1.* &rarr;</b>
<ul>
<li>Prima release dotnet6</li>
<li>Integrazione EFCore</li>
<li>Integrazione EgtB&W</li>
<li>Prima release applicazione</li>
<li>Installer WIX</li>
<li>Integrazione processo gestione servizi</li>
</ul>
</li>
</ul>
<div>
<div style="float: left;">
<img src="logoSteamware.png" />
<img src="LogoEgw.png" />
</div>
<div style="float: right;">
<a href="https://www.steamware.net/IOT" target="_blank">&copy; Steamware 2006-2021</a>
<a href="https://www.egalware.net/support" target="_blank">&copy; EgalWare 2021-2024</a>
</div>
</div>
</body>
+1 -1
View File
@@ -1 +1 @@
1.0.2404.0412
1.1.2410.2517
+3 -3
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>1.0.2404.0412</version>
<url>http://nexus.steamware.net/repository/SWS/MagMan/stable/0/MagMan.UI.zip</url>
<changelog>http://nexus.steamware.net/repository/SWS/MagMan/stable/0/ChangeLog.html</changelog>
<version>1.1.2410.2517</version>
<url>http://nexus.steamware.net/repository/SWS/Maat.Installer/stable/LAST/Maat.Installer.msi</url>
<changelog>http://nexus.steamware.net/repository/SWS/Maat.Installer/stable/LAST/ChangeLog.html</changelog>
<mandatory>false</mandatory>
</item>