You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

384 lines
13 KiB
C#

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<BackgroundTaskService> _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<BackgroundTaskService> 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<IEnumerable<ScheduledTask>> GetScheduledTasksAsync();
}
public class BackgroundTaskManager : ISchedulerService
{
private readonly ILogger<BackgroundTaskManager> _logger;
private readonly IDeviceCollectionService _collectionService;
private readonly IProductionService _productionService;
private readonly IAlarmService _alarmService;
private readonly Dictionary<string, Timer> _scheduledTasks = new Dictionary<string, Timer>();
private readonly object _lock = new object();
public BackgroundTaskManager(
ILogger<BackgroundTaskManager> 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<IEnumerable<ScheduledTask>> GetScheduledTasksAsync()
{
var tasks = _scheduledTasks.Keys.Select(key => new ScheduledTask
{
TaskId = key,
ScheduledTime = DateTime.Now,
Status = "Active"
}).ToList();
return Task.FromResult<IEnumerable<ScheduledTask>>(tasks);
}
}
public class ScheduledTask
{
public string TaskId { get; set; }
public DateTime ScheduledTime { get; set; }
public string Status { get; set; }
}
}