using EgwCoreLib.Lux.Core.RestPayload; using EgwCoreLib.Lux.Data.Services; using EgwMultiEngineManager.Data; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using NLog; using StackExchange.Redis; using System.Diagnostics; namespace Lux.API.Controllers { [Route("api/[controller]")] [ApiController] public class ProdController : ControllerBase { #region Public Constructors public ProdController(ProdService prodService) { PService = prodService; } #endregion Public Constructors #region Public Methods /// /// Chiamata GET: test status alive /// GET: api/Prod/alive /// /// id oggetto /// [HttpGet("alive")] public async Task Alive() { Stopwatch sw = new Stopwatch(); sw.Start(); await Task.Delay(1); sw.Stop(); Log.Info($"Alive | {sw.Elapsed.TotalMilliseconds:N3} ms"); return Ok("OK"); } /// /// Chiamata GET: /// - fornisce il job da eseguire dalla coda (SE presente) /// GET: api/Prod/getjob/ABC012345 /// /// [HttpGet("getjob/{id}")] public async Task> GetJob(string id) { var result = await PService.GetJob(id); return Ok(result); } /// /// Chiamata GET: /// - fornisce il primo job da eseguire dalla coda (SE presente) /// - viene registrato come "in corso" e spostato dalla coda richiesta /// GET: api/Prod/getnext /// /// [HttpGet("getnext")] public async Task> GetNext() { var result = await PService.GetNext(); return Ok(result); #if false Stopwatch sw = new Stopwatch(); sw.Start(); string result = ""; // prendo dalla coda primo job (rimuovendolo...) var rawReq = await _redisService.QueuePopAsync(queueKey); if (rawReq.HasValue) { string reqUid = $"{rawReq}"; // metto UID in coda running _redisService.QueuePush(queueKey, (RedisValue)reqUid); // FixMe ToDo !!!: salvataggio data-ora per indicare avvio calcolo... // recupero richiesta serializzata string currKey = $"{redisOrderReqKey}:{reqUid.Replace("/", ":")}"; var rawRes = await _redisService.GetAsync(currKey); if (!string.IsNullOrEmpty(rawRes)) { result = rawRes; } } sw.Stop(); Log.Info($"GetNext | {sw.Elapsed.TotalMilliseconds:N3} ms"); return Ok(result); #endif } /// /// Chiamata GET: num richieste in coda (tot) /// GET: api/Prod/alive /// /// id oggetto /// [HttpGet("queue")] public async Task QueueLen() { var result = await PService.QueueLen(); return Ok(result); #if false Stopwatch sw = new Stopwatch(); sw.Start(); long numWaiting = await _redisService.QueueCountAsync(queueKey); sw.Stop(); Log.Info($"QueueLen | {sw.Elapsed.TotalMilliseconds:N3} ms"); return Ok(numWaiting); #endif } #endregion Public Methods #region Private Fields private static Logger Log = LogManager.GetCurrentClassLogger(); private ProdService PService; #endregion Private Fields #if false [HttpPost("enqueue")] /// /// Accodamento richiesta di calcolo prod /// /// Tipo richiesta /// UID (riga ordine) /// Contenuto della richiesta come QuestionDTO /// public async Task EnqueueRequest(string reqType, string reqUid, CalcRequestDTO currRequest) { bool done = false; int nId = 1; // salvo su cache x successivo reinvio da currRequest QuestionDTO calcRequest = new QuestionDTO(nId, currRequest.EnvType, currRequest.DictExec); // salvo in cache contenuto della richiesta x UID string currKey = $"{redisOrderReqKey}:{reqUid.Replace("/", ":")}"; done = await _redisService.SetAsync(currKey, calcRequest.sProcessArgs); // accodo la nuova richiesta //RedisKey queueKey = (RedisKey)$"{redisBaseKey}:OrderQueue:{reqType}"; _redisService.QueuePush(queueKey, (RedisValue)reqUid); // dizionario richieste: è il serializzato dell'elenco degli UID da calcolare... var currList = await _redisService.QueueListAllAsync(queueKey); Dictionary calcDict = new Dictionary(); calcDict.Add("ReqLen", $"{calcDict.Count}"); string listReq = JsonConvert.SerializeObject(currList); calcDict.Add("ReqList", listReq); // preparo richiesta di calcolo x UID da inviare QuestionDTO chRequest = new QuestionDTO(nId, currRequest.EnvType, calcDict); // invio sul channel redis della richiesta di processing await _redisService.PublishAsync(chPub, chRequest.sProcessArgs); // ritorno return done; } /// /// Chiamata GET: dizionario stato richieste /// GET: api/Prod/alive /// /// id oggetto /// [HttpGet("queue-status")] public async Task QueueStatus() { Stopwatch sw = new Stopwatch(); sw.Start(); List? listEstim = new List(); List? listOptim = new List(); Dictionary queueStatus = new Dictionary(); // cerco in redis... RedisValue rawEstim = await _redisDb.StringGetAsync($"{redisBaseKey}:EstimReq"); if (rawEstim.HasValue) { listEstim = JsonConvert.DeserializeObject>($"{rawEstim}"); } RedisValue rawOptim = await _redisDb.StringGetAsync($"{redisBaseKey}:OptimReq"); if (rawOptim.HasValue) { listOptim = JsonConvert.DeserializeObject>($"{rawOptim}"); } // simulo status... queueStatus.Add("estimation", listEstim?.Count ?? 0); queueStatus.Add("optimization", listOptim?.Count ?? 0); sw.Stop(); Log.Info($"QueueStatus | {sw.Elapsed.TotalMilliseconds:N3} ms"); return Ok(queueStatus); } /// /// Chiamata GET: /// - elenco delle richieste di stima da eseguire /// - vengono registrate come "passate" al calcolo alla data-ora della richiesta /// GET: api/Prod/estimation /// /// [HttpGet("estimation")] public async Task>> EstimationRequestQueue() { Stopwatch sw = new Stopwatch(); sw.Start(); var listReq = new List(); // vado a recuperare da REDIS elenco degli ordini NON ancora associati ad 1/+ prod // opzione 1: restituisco TUTTI ordini NON ancora eseguiti // opzione 2: restituisco dall'inizio solo max(n) non ancora eseguiti? (es primi 5 ordini) // genero elenco degli ordini e per ogni ordine aggiungo il Dict await Task.Delay(100); // opzione 1: per tutti gli ordini ritornato registro data-ora invio e tolgo dalla coda... // opzione 2: aspetto conferma dal sistema che li ha presi in carico e registro data-ora... sw.Stop(); Log.Info($"EstimationRequestQueue | {sw.Elapsed.TotalMilliseconds:N3} ms"); return Ok(listReq); } /// /// Chiamata GET: /// - elenco delle richieste di ottimizzazione/nesting da eseguire /// - vengono registrate come "passate" al calcolo alla data-ora della richiesta /// GET: api/Prod/estimation /// /// [HttpGet("optmization")] public async Task>> OptimitionRequestQueue() { Stopwatch sw = new Stopwatch(); sw.Start(); var listReq = new List(); // vado a recuperare da REDIS elenco degli ordini NON ancora associati ad 1/+ prod // opzione 1: restituisco TUTTI ordini NON ancora eseguiti // opzione 2: restituisco dall'inizio solo max(n) non ancora eseguiti? (es primi 5 ordini) // genero elenco degli ordini e per ogni ordine aggiungo il Dict await Task.Delay(100); // opzione 1: per tutti gli ordini ritornato registro data-ora invio e tolgo dalla coda... // opzione 2: aspetto conferma dal sistema che li ha presi in carico e registro data-ora... sw.Stop(); Log.Info($"EstimationRequestQueue | {sw.Elapsed.TotalMilliseconds:N3} ms"); return Ok(listReq); } #endif } }