using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Haoliang.Core.Services; using Haoliang.Data.Repositories; namespace Haoliang.Core.Services { public interface IBackgroundTaskService { Task StartAsync(CancellationToken cancellationToken); Task StopAsync(CancellationToken cancellationToken); } public class BackgroundTaskService : BackgroundService, IBackgroundTaskService { private readonly ILogger _logger; private readonly IDeviceCollectionService _collectionService; private readonly IProductionService _productionService; private readonly IAlarmService _alarmService; private readonly IRealTimeService _realTimeService; private readonly ISchedulerService _schedulerService; private readonly Timer _collectionTimer; private Timer _productionTimer; private Timer _alarmTimer; private Timer _realTimeTimer; private bool _isRunning; public BackgroundTaskService( ILogger logger, IDeviceCollectionService collectionService, IProductionService productionService, IAlarmService alarmService, IRealTimeService realTimeService, ISchedulerService schedulerService) { _logger = logger; _collectionService = collectionService; _productionService = productionService; _alarmService = alarmService; _realTimeService = realTimeService; _schedulerService = schedulerService; _isRunning = false; _collectionTimer = new Timer(ExecuteCollectionTasks, null, TimeSpan.Zero, TimeSpan.FromMinutes(1)); } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _logger.LogInformation("Background Task Service is starting."); _isRunning = true; try { await StartTimers(stoppingToken); while (!stoppingToken.IsCancellationRequested) { await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken); // Log service health await LogServiceHealthAsync(); } } catch (Exception ex) { _logger.LogError(ex, "Background Task Service encountered an error."); } finally { await StopTimersAsync(); _logger.LogInformation("Background Task Service is stopping."); } } public async Task StartAsync(CancellationToken cancellationToken) { if (_isRunning) return; _logger.LogInformation("Starting background task service..."); try { // Start device collection await _collectionService.CollectAllDevicesAsync(); _logger.LogInformation("Device collection started."); // Start production calculation await _productionService.CalculateAllProductionAsync(); _logger.LogInformation("Production calculation started."); // Start alarm monitoring var activeAlarms = await _alarmService.GetActiveAlarmsAsync(); if (activeAlarms.Any()) { _logger.LogInformation($"Found {activeAlarms.Count()} active alarms."); } _isRunning = true; _logger.LogInformation("Background task service started successfully."); } catch (Exception ex) { _logger.LogError(ex, "Failed to start background task service."); throw; } } public async Task StopAsync(CancellationToken cancellationToken) { if (!_isRunning) return; _logger.LogInformation("Stopping background task service..."); try { await StopTimersAsync(); _isRunning = false; _logger.LogInformation("Background task service stopped successfully."); } catch (Exception ex) { _logger.LogError(ex, "Error while stopping background task service."); throw; } } private async void ExecuteCollectionTasks(object state) { if (!_isRunning) return; try { await _collectionService.CollectAllDevicesAsync(); } catch (Exception ex) { _logger.LogError(ex, "Error executing collection tasks."); } } private async Task StartTimers(CancellationToken cancellationToken) { // Start production calculation timer (every 5 minutes) _productionTimer = new Timer(async _ => { if (!_isRunning) return; try { await _productionService.CalculateAllProductionAsync(); } catch (Exception ex) { _logger.LogError(ex, "Error in production calculation timer."); } }, null, TimeSpan.Zero, TimeSpan.FromMinutes(5)); // Start alarm monitoring timer (every 1 minute) _alarmTimer = new Timer(async _ => { if (!_isRunning) return; try { var activeAlarms = await _alarmService.GetActiveAlarmsAsync(); _logger.LogInformation($"Monitoring {activeAlarms.Count()} active alarms."); } catch (Exception ex) { _logger.LogError(ex, "Error in alarm monitoring timer."); } }, null, TimeSpan.Zero, TimeSpan.FromMinutes(1)); // Start real-time data push timer (every 30 seconds) _realTimeTimer = new Timer(async _ => { if (!_isRunning) return; try { await _realTimeService.BroadcastDeviceStatusAsync(); } catch (Exception ex) { _logger.LogError(ex, "Error in real-time data push timer."); } }, null, TimeSpan.Zero, TimeSpan.FromSeconds(30)); _logger.LogInformation("Background timers started."); } private async Task StopTimersAsync() { _collectionTimer?.Dispose(); _productionTimer?.Dispose(); _alarmTimer?.Dispose(); _realTimeTimer?.Dispose(); _logger.LogInformation("Background timers stopped."); } private async Task LogServiceHealthAsync() { try { var collectionHealth = await _collectionService.GetCollectionHealthAsync(); var deviceCount = await _collectionService.GetCollectionStatisticsAsync(DateTime.Today); _logger.LogInformation($"Service Health - Devices: {collectionHealth.TotalDevices}, " + $"Online: {collectionHealth.OnlineDevices}, " + $"Success Rate: {collectionHealth.SuccessRate:F1}%, " + $"Active Tasks: {collectionHealth.ActiveCollectionTasks}"); } catch (Exception ex) { _logger.LogError(ex, "Error logging service health."); } } } public interface ISchedulerService { Task ScheduleDeviceCollectionAsync(int deviceId); Task ScheduleProductionCalculationAsync(int deviceId); Task ScheduleAlarmCheckAsync(); Task CancelScheduledTaskAsync(string taskId); Task> GetScheduledTasksAsync(); } public class BackgroundTaskManager : ISchedulerService { private readonly ILogger _logger; private readonly IDeviceCollectionService _collectionService; private readonly IProductionService _productionService; private readonly IAlarmService _alarmService; private readonly Dictionary _scheduledTasks = new Dictionary(); private readonly object _lock = new object(); public BackgroundTaskManager( ILogger logger, IDeviceCollectionService collectionService, IProductionService productionService, IAlarmService alarmService) { _logger = logger; _collectionService = collectionService; _productionService = productionService; _alarmService = alarmService; } public async Task ScheduleDeviceCollectionAsync(int deviceId) { var taskId = $"collection_{deviceId}_{DateTime.Now:yyyyMMddHHmmss}"; lock (_lock) { if (_scheduledTasks.ContainsKey(taskId)) { _scheduledTasks[taskId].Dispose(); } var timer = new Timer(async _ => { try { await _collectionService.CollectDeviceAsync(deviceId); } catch (Exception ex) { _logger.LogError(ex, $"Failed to execute scheduled collection for device {deviceId}"); } }, null, TimeSpan.Zero, TimeSpan.FromMinutes(5)); _scheduledTasks[taskId] = timer; } _logger.LogInformation($"Scheduled device collection for device {deviceId} with task ID {taskId}"); } public async Task ScheduleProductionCalculationAsync(int deviceId) { var taskId = $"production_{deviceId}_{DateTime.Now:yyyyMMddHHmmss}"; lock (_lock) { if (_scheduledTasks.ContainsKey(taskId)) { _scheduledTasks[taskId].Dispose(); } var timer = new Timer(async _ => { try { await _productionService.CalculateProductionAsync(deviceId); } catch (Exception ex) { _logger.LogError(ex, $"Failed to execute scheduled production calculation for device {deviceId}"); } }, null, TimeSpan.Zero, TimeSpan.FromMinutes(10)); _scheduledTasks[taskId] = timer; } _logger.LogInformation($"Scheduled production calculation for device {deviceId} with task ID {taskId}"); } public async Task ScheduleAlarmCheckAsync() { var taskId = $"alarm_check_{DateTime.Now:yyyyMMddHHmmss}"; lock (_lock) { if (_scheduledTasks.ContainsKey(taskId)) { _scheduledTasks[taskId].Dispose(); } var timer = new Timer(async _ => { try { var activeAlarms = await _alarmService.GetActiveAlarmsAsync(); _logger.LogInformation($"Alarm check completed: {activeAlarms.Count()} active alarms"); } catch (Exception ex) { _logger.LogError(ex, "Failed to execute alarm check"); } }, null, TimeSpan.Zero, TimeSpan.FromMinutes(2)); _scheduledTasks[taskId] = timer; } _logger.LogInformation($"Scheduled alarm check with task ID {taskId}"); } public Task CancelScheduledTaskAsync(string taskId) { lock (_lock) { if (_scheduledTasks.TryGetValue(taskId, out var timer)) { timer.Dispose(); _scheduledTasks.Remove(taskId); _logger.LogInformation($"Cancelled scheduled task {taskId}"); return Task.CompletedTask; } } _logger.LogWarning($"Attempted to cancel non-existent task {taskId}"); return Task.CompletedTask; } public Task> GetScheduledTasksAsync() { var tasks = _scheduledTasks.Keys.Select(key => new ScheduledTask { TaskId = key, ScheduledTime = DateTime.Now, Status = "Active" }).ToList(); return Task.FromResult>(tasks); } } public class ScheduledTask { public string TaskId { get; set; } public DateTime ScheduledTime { get; set; } public string Status { get; set; } } }