Feat: Edición y Manejo de Titulares, entre otros.
This commit is contained in:
		| @@ -9,17 +9,27 @@ using Titulares.Api.Models; | ||||
|  | ||||
| namespace Titulares.Api.Workers; | ||||
|  | ||||
| public class ProcesoScrapingWorker : BackgroundService | ||||
| public class ProcesoScrapingWorker : BackgroundService, IDisposable | ||||
| { | ||||
|   private readonly ILogger<ProcesoScrapingWorker> _logger; | ||||
|   private readonly IServiceProvider _serviceProvider; | ||||
|   private readonly IOptionsMonitor<ConfiguracionApp> _configuracion; | ||||
|   private readonly IDisposable? _optionsReloadToken; | ||||
|  | ||||
|   private CancellationTokenSource? _delayCts; | ||||
|  | ||||
|   public ProcesoScrapingWorker(ILogger<ProcesoScrapingWorker> logger, IServiceProvider serviceProvider, IOptionsMonitor<ConfiguracionApp> configuracion) | ||||
|   { | ||||
|     _logger = logger; | ||||
|     _serviceProvider = serviceProvider; | ||||
|     _configuracion = configuracion; | ||||
|     _optionsReloadToken = _configuracion.OnChange(OnConfigurationChanged); | ||||
|   } | ||||
|  | ||||
|   private void OnConfigurationChanged(ConfiguracionApp newConfig) | ||||
|   { | ||||
|     _logger.LogInformation("La configuración ha cambiado. Interrumpiendo la espera actual para aplicar los nuevos ajustes."); | ||||
|     _delayCts?.Cancel(); | ||||
|   } | ||||
|  | ||||
|   protected override async Task ExecuteAsync(CancellationToken stoppingToken) | ||||
| @@ -27,42 +37,26 @@ public class ProcesoScrapingWorker : BackgroundService | ||||
|     while (!stoppingToken.IsCancellationRequested) | ||||
|     { | ||||
|       var configActual = _configuracion.CurrentValue; | ||||
|  | ||||
|       _logger.LogInformation("Iniciando ciclo de scraping con cantidad: {cantidad}", configActual.CantidadTitularesAScrapear); | ||||
|  | ||||
|       try | ||||
|       { | ||||
|         // Creamos un 'scope' para obtener instancias 'scoped' de nuestros servicios. | ||||
|         // Es la práctica correcta en servicios de larga duración. | ||||
|         using (var scope = _serviceProvider.CreateScope()) | ||||
|         { | ||||
|           var repositorio = scope.ServiceProvider.GetRequiredService<TitularRepositorio>(); | ||||
|           var scrapingService = scope.ServiceProvider.GetRequiredService<ScrapingService>(); | ||||
|           var hubContext = scope.ServiceProvider.GetRequiredService<IHubContext<TitularesHub>>(); | ||||
|           var csvService = scope.ServiceProvider.GetRequiredService<CsvService>(); | ||||
|           int cantidadTitulares = configActual.CantidadTitularesAScrapear; | ||||
|           var articulosScrapeados = await scrapingService.ObtenerUltimosTitulares(cantidadTitulares); | ||||
|  | ||||
|           // Obtener estos valores desde la configuración | ||||
|           int cantidadAObtener = configActual.CantidadTitularesAScrapear; | ||||
|           int limiteTotalEnDb = configActual.LimiteTotalEnDb; | ||||
|           await repositorio.SincronizarDesdeScraping(articulosScrapeados, cantidadTitulares); | ||||
|           _logger.LogInformation("Sincronización con la base de datos completada."); | ||||
|  | ||||
|           // 1. Obtener los últimos titulares de la web | ||||
|           var articulosScrapeados = await scrapingService.ObtenerUltimosTitulares(cantidadAObtener); | ||||
|  | ||||
|           if (articulosScrapeados.Any()) | ||||
|           { | ||||
|             await repositorio.SincronizarDesdeScraping(articulosScrapeados, limiteTotalEnDb); | ||||
|             _logger.LogInformation("Sincronización con la base de datos completada."); | ||||
|  | ||||
|             var titularesActualizados = await repositorio.ObtenerTodosAsync(); | ||||
|             await hubContext.Clients.All.SendAsync("TitularesActualizados", titularesActualizados, stoppingToken); | ||||
|             _logger.LogInformation("Notificación enviada a los clientes."); | ||||
|  | ||||
|             await csvService.GenerarCsvAsync(titularesActualizados); | ||||
|           } | ||||
|           else | ||||
|           { | ||||
|             _logger.LogWarning("No se encontraron artículos en el scraping."); | ||||
|           } | ||||
|           var titularesActualizados = await repositorio.ObtenerTodosAsync(); | ||||
|           await hubContext.Clients.All.SendAsync("TitularesActualizados", titularesActualizados, stoppingToken); | ||||
|           _logger.LogInformation("Notificación enviada a los clientes."); | ||||
|           await csvService.GenerarCsvAsync(titularesActualizados); | ||||
|         } | ||||
|       } | ||||
|       catch (Exception ex) | ||||
| @@ -72,7 +66,29 @@ public class ProcesoScrapingWorker : BackgroundService | ||||
|  | ||||
|       var intervaloEnMinutos = configActual.IntervaloMinutos; | ||||
|       _logger.LogInformation("Proceso en espera por {minutos} minutos.", intervaloEnMinutos); | ||||
|       await Task.Delay(TimeSpan.FromMinutes(intervaloEnMinutos), stoppingToken); | ||||
|  | ||||
|       try | ||||
|       { | ||||
|         _delayCts = new CancellationTokenSource(); | ||||
|         using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken, _delayCts.Token); | ||||
|         await Task.Delay(TimeSpan.FromMinutes(intervaloEnMinutos), linkedCts.Token); | ||||
|       } | ||||
|       catch (TaskCanceledException) | ||||
|       { | ||||
|         _logger.LogInformation("La espera fue interrumpida. Reiniciando el ciclo."); | ||||
|       } | ||||
|       finally | ||||
|       { | ||||
|         _delayCts?.Dispose(); | ||||
|         _delayCts = null; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   public override void Dispose() | ||||
|   { | ||||
|     _optionsReloadToken?.Dispose(); | ||||
|     _delayCts?.Dispose(); | ||||
|     base.Dispose(); | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user