| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- using SWRIS.Core;
- using SWRIS.Models;
- using SWRIS.Repository;
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Threading;
- using System.Threading.Tasks;
- using System.Windows;
- namespace SWRIS.Services
- {
- public class HistoryCleanupService : IDisposable
- {
- private Timer _cleanupTimer;
- private readonly IRecordRepository _recordRepository;
- private bool _isRunning = false;
- private bool _disposed = false;
- private int _consecutiveFailures = 0;
- public event EventHandler<DeleteResultModel> OnCleanupCompleted;
- public event EventHandler<Exception> OnCleanupFailed;
- public bool IsRunning => _isRunning;
- public DateTime? NextScheduledTime { get; private set; }
- public DateTime? LastCleanupTime { get; private set; }
- public DeleteResultModel LastCleanupResult { get; private set; }
- public HistoryCleanupService()
- {
- _recordRepository = new RecordRepository();
- ValidateConfiguration();
- }
- public void StartScheduledCleanup()
- {
- if (_isRunning)
- {
- LogHelper.Warn("清理服务已在运行中");
- return;
- }
- try
- {
- ValidateConfiguration();
- var now = DateTime.Now;
- var scheduledTime = CalculateNextScheduledTime(now);
- var initialDelay = scheduledTime - now;
- _cleanupTimer = new Timer(
- callback: _ => ExecuteCleanupAsync().ConfigureAwait(false),
- state: null,
- dueTime: initialDelay,
- period: TimeSpan.FromHours(24)
- );
- _isRunning = true;
- NextScheduledTime = scheduledTime;
- _consecutiveFailures = 0;
- LogHelper.Info($"计划清理已启动。下次执行: {scheduledTime:yyyy-MM-dd HH:mm:ss}");
- }
- catch (Exception ex)
- {
- LogHelper.Error($"启动计划任务失败: {ex.Message}");
- _isRunning = false;
- OnCleanupFailed?.Invoke(this, ex);
- // 延迟重试
- Task.Delay(TimeSpan.FromMinutes(5)).ContinueWith(_ => RetryStartup());
- }
- }
- private DateTime CalculateNextScheduledTime(DateTime now)
- {
- var timeSpan = App.Config.CleanScheduledTime;
- var scheduledTime = new DateTime(now.Year, now.Month, now.Day,
- timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds);
- if (now > scheduledTime)
- {
- scheduledTime = scheduledTime.AddDays(1);
- }
- return scheduledTime;
- }
- private void RetryStartup(int retryCount = 0)
- {
- if (retryCount >= 3)
- {
- LogHelper.Error("启动重试次数超过限制,请检查系统配置");
- return;
- }
- LogHelper.Info($"尝试重新启动清理服务 (重试 {retryCount + 1}/3)");
- StartScheduledCleanup();
- }
- private async Task ExecuteCleanupAsync()
- {
- try
- {
- LastCleanupTime = DateTime.Now;
- LogHelper.Info($"开始执行计划清理任务 ({LastCleanupTime:yyyy-MM-dd HH:mm:ss})");
- var result = await Task.Run(() =>
- CleanupHistoryOlderThanDays(App.Config.DataSaveDays));
- // 更新下一次执行时间
- NextScheduledTime = CalculateNextScheduledTime(DateTime.Now);
- // 重置连续失败计数
- _consecutiveFailures = 0;
- // 在UI线程更新结果
- await Application.Current.Dispatcher.InvokeAsync(() =>
- {
- LastCleanupResult = result;
- if (result.IsSuccess)
- {
- LogHelper.Info($"{result.Message} (执行时间: {result.OperationTime:HH:mm:ss})");
- LogHelper.Info($"删除记录: {result.DeletedRecords} 条, 删除文件: {result.DeletedFiles} 个");
- }
- else
- {
- LogHelper.Warn($"清理任务完成但有警告: {result.Message}");
- }
- OnCleanupCompleted?.Invoke(this, result);
- });
- }
- catch (Exception ex)
- {
- _consecutiveFailures++;
- LogHelper.Error($"清理执行失败 (失败次数: {_consecutiveFailures}): {ex.Message}", ex);
- // 连续失败告警
- if (_consecutiveFailures >= 3)
- {
- LogHelper.Warn("连续清理失败次数过多,请检查系统状态");
- }
- OnCleanupFailed?.Invoke(this, ex);
- }
- }
- public DeleteResultModel CleanupHistoryOlderThanDays(int days)
- {
- var result = new DeleteResultModel
- {
- OperationTime = DateTime.Now,
- DataSaveDays = days
- };
- try
- {
- if (days <= 0)
- {
- throw new ArgumentException("数据保存天数必须大于0", nameof(days));
- }
- var endTime = DateTime.Today.AddDays(-days);
- LogHelper.Info($"开始清理 {endTime:yyyy-MM-dd} 之前的历史数据");
- var (effect, filePaths) = _recordRepository.DeleteRecords(endTime);
- result.DeletedRecords = effect;
- result.DeletedFiles = DeleteAssociatedFiles(filePaths);
- result.IsSuccess = true;
- result.Message = $"清理完成,删除了 {result.DeletedRecords} 条记录和 {result.DeletedFiles} 个文件。";
- LogHelper.Info($"数据库记录清理: {result.DeletedRecords} 条");
- LogHelper.Info($"关联文件清理: {result.DeletedFiles} 个");
- }
- catch (Exception ex)
- {
- result.IsSuccess = false;
- result.Message = $"清理过程中发生错误: {ex.Message}";
- LogHelper.Error($"Cleanup Error: {ex}", ex);
- }
- return result;
- }
- private int DeleteAssociatedFiles(List<string> filePaths)
- {
- int deletedCount = 0;
- int errorCount = 0;
- if (filePaths == null || filePaths.Count == 0)
- {
- return 0;
- }
- LogHelper.Info($"开始清理 {filePaths.Count} 个关联文件");
- foreach (var filePath in filePaths)
- {
- try
- {
- if (File.Exists(filePath))
- {
- File.Delete(filePath);
- deletedCount++;
- }
- else
- {
- LogHelper.Warn($"文件不存在: {filePath}");
- }
- }
- catch (Exception ex)
- {
- errorCount++;
- LogHelper.Error($"删除文件失败 {filePath}: {ex.Message}");
- }
- }
- if (errorCount > 0)
- {
- LogHelper.Warn($"{errorCount} 个文件删除失败");
- }
- return deletedCount;
- }
- public void StopScheduledCleanup()
- {
- _cleanupTimer?.Change(Timeout.Infinite, Timeout.Infinite);
- _isRunning = false;
- NextScheduledTime = null;
- LogHelper.Info("计划清理已停止");
- }
- public void TriggerManualCleanup()
- {
- LogHelper.Info("手动触发清理任务");
- ExecuteCleanupAsync().ConfigureAwait(false);
- }
- private void ValidateConfiguration()
- {
- if (App.Config?.CleanScheduledTime == null)
- {
- throw new InvalidOperationException("清理计划时间未配置");
- }
- if (App.Config.DataSaveDays <= 0)
- {
- throw new InvalidOperationException("数据保存天数必须大于0");
- }
- }
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
- protected virtual void Dispose(bool disposing)
- {
- if (!_disposed)
- {
- if (disposing)
- {
- StopScheduledCleanup();
- _cleanupTimer?.Dispose();
- _cleanupTimer = null;
- }
- _disposed = true;
- }
- }
- ~HistoryCleanupService()
- {
- Dispose(false);
- }
- }
- }
|