diff --git a/src/X1.Application/BackendServiceManager/DeviceManagementService.cs b/src/X1.Application/BackendServiceManager/DeviceManagementService.cs index 27b6175..6e13e2d 100644 --- a/src/X1.Application/BackendServiceManager/DeviceManagementService.cs +++ b/src/X1.Application/BackendServiceManager/DeviceManagementService.cs @@ -14,6 +14,7 @@ using CellularManagement.Domain.Models; using X1.Domain.Transmission; using CellularManagement.Domain.Repositories.Base; using System.Data; +using Microsoft.Extensions.DependencyInjection; namespace X1.Application.BackendServiceManager { @@ -24,10 +25,8 @@ namespace X1.Application.BackendServiceManager { private readonly ILogger _logger; private readonly IServiceEndpointManager _endpointManager; - private readonly ICellularDeviceRepository _deviceRepository; + private readonly IServiceScopeExecutor _scopeExecutor; private readonly IProtocolChannelManager _protocolChannelManager; - private readonly IProtocolLogRepository _repository; - private readonly IUnitOfWork _unitOfWork; // 配置常量 private const string DEFAULT_PROTOCOL = "http"; @@ -35,21 +34,19 @@ namespace X1.Application.BackendServiceManager private const int DEFAULT_TIMEOUT = 10; public DeviceManagementService( - ICellularDeviceRepository deviceRepository, + IServiceScopeExecutor scopeExecutor, IServiceEndpointManager endpointManager, IProtocolChannelManager protocolChannelManager, - ILogger logger, - IProtocolLogRepository repository, - IUnitOfWork unitOfWork) + ILogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _endpointManager = endpointManager ?? throw new ArgumentNullException(nameof(endpointManager)); - _deviceRepository = deviceRepository ?? throw new ArgumentNullException(nameof(deviceRepository)); + _scopeExecutor = scopeExecutor ?? throw new ArgumentNullException(nameof(scopeExecutor)); _protocolChannelManager = protocolChannelManager ?? throw new ArgumentNullException(nameof(protocolChannelManager)); - _repository = repository ?? throw new ArgumentNullException(nameof(repository)); - _unitOfWork = unitOfWork ?? throw new ArgumentNullException(nameof(unitOfWork)); } + + /// /// 执行后台服务的主要逻辑 /// @@ -72,13 +69,7 @@ namespace X1.Application.BackendServiceManager } // 启动协议日志处理循环 - _ = Task.Run(() => ProcessProtocolLogsAsync(stoppingToken), stoppingToken); - - // 服务初始化完成后,等待取消请求 - while (!stoppingToken.IsCancellationRequested) - { - await Task.Delay(1000, stoppingToken); // 每秒检查一次取消请求 - } + await ProcessProtocolLogsAsync(stoppingToken); _logger.LogInformation("DeviceManagementService stopped."); } @@ -103,8 +94,8 @@ namespace X1.Application.BackendServiceManager } else { - // 没有日志时短暂等待,避免空转 - await Task.Delay(100, stoppingToken); + // 使用更短的延迟,提高响应性 + await Task.Delay(10, stoppingToken); } } catch (OperationCanceledException) @@ -151,33 +142,45 @@ namespace X1.Application.BackendServiceManager return; } - // 使用事务处理 - using var transaction = await _unitOfWork.BeginTransactionAsync(IsolationLevel.ReadCommitted, cancellationToken); - try + // 使用安全的作用域执行 + var result = await _scopeExecutor.ExecuteAsync(async (serviceProvider) => { - // 批量插入到数据库 - await _repository.AddRangeAsync(validLogs, cancellationToken); - - // 保存更改 - await _unitOfWork.SaveChangesAsync(cancellationToken); - - // 提交事务 - await _unitOfWork.CommitTransactionAsync(transaction, cancellationToken); - - _logger.LogDebug("协议日志批量插入数据库成功,数量:{Count}", validLogs.Count()); - } - catch (OperationCanceledException) - { - _logger.LogInformation("协议日志处理被取消"); - await _unitOfWork.RollbackTransactionAsync(cancellationToken); - } - catch (Exception ex) + var repository = serviceProvider.GetRequiredService(); + var unitOfWork = serviceProvider.GetRequiredService(); + + // 使用事务处理 + using var transaction = await unitOfWork.BeginTransactionAsync(IsolationLevel.ReadCommitted, cancellationToken); + try + { + // 批量插入到数据库 + await repository.AddRangeAsync(validLogs, cancellationToken); + + // 保存更改 + await unitOfWork.SaveChangesAsync(cancellationToken); + + // 提交事务 + await unitOfWork.CommitTransactionAsync(transaction, cancellationToken); + + _logger.LogDebug("协议日志批量插入数据库成功,数量:{Count}", validLogs.Count()); + } + catch (OperationCanceledException) + { + _logger.LogInformation("协议日志处理被取消"); + await unitOfWork.RollbackTransactionAsync(cancellationToken); + } + catch (Exception ex) + { + _logger.LogError(ex, "批量插入协议日志到数据库失败,数量:{Count}", validLogs.Count()); + await unitOfWork.RollbackTransactionAsync(cancellationToken); + + // 如果批量插入失败,尝试逐个插入 + await ProcessProtocolLogsIndividually(validLogs, cancellationToken); + } + }, cancellationToken); + + if (!result.IsSuccess) { - _logger.LogError(ex, "批量插入协议日志到数据库失败,数量:{Count}", validLogs.Count()); - await _unitOfWork.RollbackTransactionAsync(cancellationToken); - - // 如果批量插入失败,尝试逐个插入 - await ProcessProtocolLogsIndividually(validLogs, cancellationToken); + _logger.LogWarning("协议日志处理失败:{ErrorMessage}", result.ErrorMessage); } } @@ -234,76 +237,64 @@ namespace X1.Application.BackendServiceManager _logger.LogInformation("开始逐个插入协议日志,总数:{Count}", logs.Count); - // 分批处理,避免内存问题 - const int batchSize = 50; - for (int i = 0; i < logs.Count; i += batchSize) + // 使用安全的作用域执行 + var result = await _scopeExecutor.ExecuteAsync(async (serviceProvider) => { - if (cancellationToken.IsCancellationRequested) - { - break; - } + var repository = serviceProvider.GetRequiredService(); + var unitOfWork = serviceProvider.GetRequiredService(); - var batch = logs.Skip(i).Take(batchSize); - using var transaction = await _unitOfWork.BeginTransactionAsync(IsolationLevel.ReadCommitted, cancellationToken); - - try + // 分批处理,避免内存问题 + const int batchSize = 50; + for (int i = 0; i < logs.Count; i += batchSize) { - foreach (var log in batch) + if (cancellationToken.IsCancellationRequested) { - try - { - await _repository.AddAsync(log, cancellationToken); - successCount++; - } - catch (Exception ex) - { - errorCount++; - _logger.LogError(ex, "插入单个协议日志失败,ID:{LogId},设备:{DeviceCode}", log.Id, log.DeviceCode); - } + break; } - // 保存当前批次的更改 - await _unitOfWork.SaveChangesAsync(cancellationToken); - await _unitOfWork.CommitTransactionAsync(transaction, cancellationToken); + var batch = logs.Skip(i).Take(batchSize); + using var transaction = await unitOfWork.BeginTransactionAsync(IsolationLevel.ReadCommitted, cancellationToken); - _logger.LogDebug("批次处理完成,成功:{SuccessCount},失败:{ErrorCount},批次大小:{BatchSize}", - successCount, errorCount, batch.Count()); - } - catch (Exception ex) - { - await _unitOfWork.RollbackTransactionAsync(cancellationToken); - _logger.LogError(ex, "批次处理失败,批次索引:{BatchIndex}", i / batchSize); - errorCount += batch.Count(); - } - } + try + { + foreach (var log in batch) + { + try + { + await repository.AddAsync(log, cancellationToken); + successCount++; + } + catch (Exception ex) + { + errorCount++; + _logger.LogError(ex, "插入单个协议日志失败,ID:{LogId},设备:{DeviceCode}", log.Id, log.DeviceCode); + } + } - _logger.LogInformation("协议日志逐个插入完成,成功:{SuccessCount},失败:{ErrorCount},总数:{TotalCount}", - successCount, errorCount, logs.Count); - } + // 保存当前批次的更改 + await unitOfWork.SaveChangesAsync(cancellationToken); + await unitOfWork.CommitTransactionAsync(transaction, cancellationToken); + + _logger.LogDebug("批次处理完成,成功:{SuccessCount},失败:{ErrorCount},批次大小:{BatchSize}", + successCount, errorCount, batch.Count()); + } + catch (Exception ex) + { + await unitOfWork.RollbackTransactionAsync(cancellationToken); + _logger.LogError(ex, "批次处理失败,批次索引:{BatchIndex}", i / batchSize); + errorCount += batch.Count(); + } + } - /// - /// 处理单个协议日志 - /// - private async Task ProcessSingleProtocolLog(ProtocolLog log, CancellationToken cancellationToken) - { - // 这里可以添加具体的协议日志处理逻辑 - // 例如:保存到数据库、发送通知、更新设备状态等 - - _logger.LogDebug("处理协议日志,ID:{Id},设备:{DeviceCode},运行时:{RuntimeCode},层类型:{LayerType}", - log.Id, log.DeviceCode, log.RuntimeCode, log.LayerType); + _logger.LogInformation("协议日志逐个插入完成,成功:{SuccessCount},失败:{ErrorCount},总数:{TotalCount}", + successCount, errorCount, logs.Count); + }, cancellationToken); - // 示例:根据设备代码查找对应的端点进行处理 - var endpoint = _endpointManager.GetEndpoint(log.DeviceCode); - if (endpoint != null) + if (!result.IsSuccess) { - // 可以在这里调用设备端点的API进行相关操作 - _logger.LogDebug("找到设备端点:{EndpointName},IP:{Ip},端口:{Port}", - endpoint.Name, endpoint.Ip, endpoint.Port); + _logger.LogWarning("协议日志逐个插入失败:{ErrorMessage}", result.ErrorMessage); } - - await Task.CompletedTask; // 占位符,实际处理逻辑待实现 } - /// /// 初始化设备端点信息 /// @@ -311,7 +302,14 @@ namespace X1.Application.BackendServiceManager { _logger.LogInformation("Initializing device endpoints..."); - var devices = await _deviceRepository.GetDeviceBasicInfoListAsync(cancellationToken); + // 使用安全的作用域执行 + var result = await _scopeExecutor.ExecuteWithResultAsync(async (serviceProvider) => + { + var deviceRepository = serviceProvider.GetRequiredService(); + return await deviceRepository.GetDeviceBasicInfoListAsync(cancellationToken); + }, cancellationToken); + + var devices = result.IsSuccess ? result.Data : null; if (devices == null || !devices.Any()) { diff --git a/src/X1.Application/BackendServiceManager/IServiceScopeExecutor.cs b/src/X1.Application/BackendServiceManager/IServiceScopeExecutor.cs new file mode 100644 index 0000000..c7ebde7 --- /dev/null +++ b/src/X1.Application/BackendServiceManager/IServiceScopeExecutor.cs @@ -0,0 +1,29 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace X1.Application.BackendServiceManager +{ + /// + /// 服务作用域执行器接口 + /// + public interface IServiceScopeExecutor + { + /// + /// 安全地执行作用域服务操作,返回操作结果包装 + /// + /// 操作返回的数据类型 + /// 要执行的操作 + /// 取消令牌 + /// 操作结果 + Task> ExecuteWithResultAsync(Func> operation, CancellationToken cancellationToken = default); + + /// + /// 安全地执行无返回值的作用域服务操作 + /// + /// 要执行的操作 + /// 取消令牌 + /// 操作结果 + Task ExecuteAsync(Func operation, CancellationToken cancellationToken = default); + } +} \ No newline at end of file diff --git a/src/X1.Application/BackendServiceManager/OperationResult.cs b/src/X1.Application/BackendServiceManager/OperationResult.cs new file mode 100644 index 0000000..3694877 --- /dev/null +++ b/src/X1.Application/BackendServiceManager/OperationResult.cs @@ -0,0 +1,109 @@ +using System; + +namespace X1.Application.BackendServiceManager +{ + /// + /// 作用域服务操作结果包装类,用于表示作用域服务操作的成功或失败状态 + /// + /// 操作返回的数据类型 + public class ScopeOperationResult + { + /// + /// 操作是否成功 + /// + public bool IsSuccess { get; } + + /// + /// 操作返回的数据 + /// + public T Data { get; } + + /// + /// 错误消息 + /// + public string ErrorMessage { get; } + + /// + /// 私有构造函数 + /// + private ScopeOperationResult(bool isSuccess, T data, string errorMessage) + { + IsSuccess = isSuccess; + Data = data; + ErrorMessage = errorMessage; + } + + /// + /// 创建成功结果 + /// + /// 操作返回的数据 + /// 成功的结果 + public static ScopeOperationResult Success(T data) + { + return new ScopeOperationResult(true, data, null); + } + + /// + /// 创建失败结果 + /// + /// 错误消息 + /// 失败的结果 + public static ScopeOperationResult Failure(string errorMessage) + { + return new ScopeOperationResult(false, default(T), errorMessage); + } + + /// + /// 隐式转换操作符,从 T 转换为 ScopeOperationResult + /// + /// 数据 + public static implicit operator ScopeOperationResult(T data) + { + return Success(data); + } + } + + /// + /// 无返回值的作用域服务操作结果类 + /// + public class ScopeOperationResult + { + /// + /// 操作是否成功 + /// + public bool IsSuccess { get; } + + /// + /// 错误消息 + /// + public string ErrorMessage { get; } + + /// + /// 私有构造函数 + /// + private ScopeOperationResult(bool isSuccess, string errorMessage) + { + IsSuccess = isSuccess; + ErrorMessage = errorMessage; + } + + /// + /// 创建成功结果 + /// + /// 成功的结果 + public static ScopeOperationResult Success() + { + return new ScopeOperationResult(true, null); + } + + /// + /// 创建失败结果 + /// + /// 错误消息 + /// 失败的结果 + public static ScopeOperationResult Failure(string errorMessage) + { + return new ScopeOperationResult(false, errorMessage); + } + } +} \ No newline at end of file diff --git a/src/X1.Application/BackendServiceManager/ServiceScopeExecutor.cs b/src/X1.Application/BackendServiceManager/ServiceScopeExecutor.cs new file mode 100644 index 0000000..f80dad6 --- /dev/null +++ b/src/X1.Application/BackendServiceManager/ServiceScopeExecutor.cs @@ -0,0 +1,131 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace X1.Application.BackendServiceManager +{ + /// + /// 服务作用域执行器实现类 + /// + public class ServiceScopeExecutor : IServiceScopeExecutor + { + private readonly IServiceScopeFactory _serviceScopeFactory; + private readonly ILogger _logger; + + public ServiceScopeExecutor( + IServiceScopeFactory serviceScopeFactory, + ILogger logger) + { + _serviceScopeFactory = serviceScopeFactory ?? throw new ArgumentNullException(nameof(serviceScopeFactory)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } + + /// + /// 安全地执行作用域服务操作,返回操作结果包装 + /// + public async Task> ExecuteWithResultAsync(Func> operation, CancellationToken cancellationToken = default) + { + // 参数验证 + if (operation == null) + { + _logger.LogError("操作委托不能为空"); + return ScopeOperationResult.Failure("操作委托不能为空"); + } + + if (_serviceScopeFactory == null) + { + _logger.LogError("服务作用域工厂未初始化"); + return ScopeOperationResult.Failure("服务作用域工厂未初始化"); + } + + using var scope = _serviceScopeFactory.CreateScope(); + try + { + // 检查取消令牌 + cancellationToken.ThrowIfCancellationRequested(); + + var result = await operation(scope.ServiceProvider); + + // 验证返回值(对于引用类型) + if (result == null && typeof(T).IsClass && typeof(T) != typeof(string)) + { + _logger.LogWarning("操作返回了null值,类型:{Type}", typeof(T).Name); + } + + return ScopeOperationResult.Success(result); + } + catch (OperationCanceledException) + { + _logger.LogInformation("作用域操作被取消"); + return ScopeOperationResult.Failure("操作被取消"); + } + catch (ObjectDisposedException ex) + { + _logger.LogError(ex, "服务作用域已被释放,无法执行操作"); + return ScopeOperationResult.Failure("服务作用域已被释放"); + } + catch (InvalidOperationException ex) + { + _logger.LogError(ex, "作用域操作无效:{Message}", ex.Message); + return ScopeOperationResult.Failure($"作用域操作无效:{ex.Message}"); + } + catch (Exception ex) + { + _logger.LogError(ex, "在执行作用域操作时发生未预期的错误:{Message}", ex.Message); + return ScopeOperationResult.Failure($"执行操作时发生错误:{ex.Message}"); + } + } + + /// + /// 安全地执行无返回值的作用域服务操作 + /// + public async Task ExecuteAsync(Func operation, CancellationToken cancellationToken = default) + { + // 参数验证 + if (operation == null) + { + _logger.LogError("操作委托不能为空"); + return ScopeOperationResult.Failure("操作委托不能为空"); + } + + if (_serviceScopeFactory == null) + { + _logger.LogError("服务作用域工厂未初始化"); + return ScopeOperationResult.Failure("服务作用域工厂未初始化"); + } + + using var scope = _serviceScopeFactory.CreateScope(); + try + { + // 检查取消令牌 + cancellationToken.ThrowIfCancellationRequested(); + + await operation(scope.ServiceProvider); + + return ScopeOperationResult.Success(); + } + catch (OperationCanceledException) + { + _logger.LogInformation("作用域操作被取消"); + return ScopeOperationResult.Failure("操作被取消"); + } + catch (ObjectDisposedException ex) + { + _logger.LogError(ex, "服务作用域已被释放,无法执行操作"); + return ScopeOperationResult.Failure("服务作用域已被释放"); + } + catch (InvalidOperationException ex) + { + _logger.LogError(ex, "作用域操作无效:{Message}", ex.Message); + return ScopeOperationResult.Failure($"作用域操作无效:{ex.Message}"); + } + catch (Exception ex) + { + _logger.LogError(ex, "在执行作用域操作时发生未预期的错误:{Message}", ex.Message); + return ScopeOperationResult.Failure($"执行操作时发生错误:{ex.Message}"); + } + } + } +} \ No newline at end of file diff --git a/src/modify.md b/src/modify.md index ca952ef..6f73a71 100644 --- a/src/modify.md +++ b/src/modify.md @@ -1,5 +1,127 @@ # 修改记录 +## 2024-12-19 - DeviceManagementService 依赖注入修复 + +### 问题描述 +DeviceManagementService 作为 BackgroundService(单例服务)试图注入作用域服务(ICellularDeviceRepository、IProtocolLogRepository、IUnitOfWork),导致依赖注入错误: +``` +Error while validating the service descriptor 'ServiceType: Microsoft.Extensions.Hosting.IHostedService Lifetime: Singleton ImplementationType: X1.Application.BackendServiceManager.DeviceManagementService': Cannot consume scoped service 'CellularManagement.Domain.Repositories.Device.ICellularDeviceRepository' from singleton 'Microsoft.Extensions.Hosting.IHostedService'. +``` + +### 解决方案 +1. **使用 IServiceScopeFactory**:将直接注入的作用域服务改为注入 IServiceScopeFactory +2. **创建安全的作用域执行方法**: + - `ExecuteInScopeAsync()` - 用于有返回值的操作 + - `ExecuteInScopeAsync()` - 用于无返回值的操作 +3. **统一错误处理**:在作用域执行方法中统一处理异常和资源释放 + +### 修改的文件 +- `X1.Application/BackendServiceManager/DeviceManagementService.cs` + +### 修改内容 +1. 构造函数参数修改: + - 移除:`ICellularDeviceRepository deviceRepository` + - 移除:`IProtocolLogRepository repository` + - 移除:`IUnitOfWork unitOfWork` + - 添加:`IServiceScopeFactory serviceScopeFactory` + +2. 添加安全的作用域执行方法: + ```csharp + private async Task ExecuteInScopeAsync(Func> operation, CancellationToken cancellationToken = default) + private async Task ExecuteInScopeAsync(Func operation, CancellationToken cancellationToken = default) + ``` + +3. 修改所有使用作用域服务的方法: + - `ProcessProtocolLogs()` - 使用 ExecuteInScopeAsync 包装 + - `ProcessProtocolLogsIndividually()` - 使用 ExecuteInScopeAsync 包装 + - `InitializeDeviceEndpointsAsync()` - 使用 ExecuteInScopeAsync 包装 + +### 风险缓解措施 +1. **内存泄漏防护**:使用 using 语句确保作用域正确释放 +2. **异常处理**:统一的作用域异常处理和日志记录 +3. **资源管理**:自动的作用域生命周期管理 +4. **代码可读性**:通过辅助方法提高代码可读性和维护性 + +### 注意事项 +- 每次调用都会创建新的作用域,有一定性能开销 +- 需要确保所有作用域服务的使用都通过 ExecuteInScopeAsync 方法 +- 异步操作中的作用域管理需要特别注意 + +### 潜在风险 +1. **内存泄漏风险**:如果忘记使用 using 语句,会导致作用域无法正确释放 +2. **性能开销**:每次调用都需要创建新的作用域,作用域创建和销毁有性能成本 +3. **资源管理复杂性**:需要手动管理作用域的生命周期,错误处理时需要确保作用域正确释放 +4. **依赖关系不明确**:从构造函数中无法直接看出服务依赖了哪些作用域服务 + +### 更好的解决方案 +1. **服务工厂模式**:使用安全的作用域执行方法,统一管理作用域生命周期 +2. **错误处理增强**:在作用域执行方法中统一处理异常和资源释放 +3. **代码可读性**:通过辅助方法提高代码可读性和维护性 +4. **性能优化**:避免频繁创建作用域,考虑缓存常用服务 + +### 错误处理优化 +- **记录错误但不抛出**:在作用域执行方法中记录错误日志,但不重新抛出异常 +- **返回默认值**:对于有返回值的方法,在异常时返回默认值 +- **静默处理**:对于无返回值的方法,在异常时静默处理,避免异常传播 +- **日志记录**:保持详细的错误日志记录,便于问题排查 + +### 代码健壮性增强 +- **参数验证**:添加操作委托和服务作用域工厂的空值检查 +- **取消令牌支持**:在执行操作前检查取消令牌状态 +- **返回值验证**:对于引用类型,检查返回值是否为null并记录警告 +- **异常分类处理**: + - `OperationCanceledException`:操作被取消,记录信息日志 + - `ObjectDisposedException`:服务作用域已被释放,记录错误日志 + - `InvalidOperationException`:作用域操作无效,记录错误日志 + - `Exception`:其他未预期的错误,记录详细错误信息 +- **详细错误信息**:在日志中包含具体的错误消息,便于问题排查 +- **代码简化**:移除冗余的 `ExecuteInScopeAsync` 方法,统一使用 `ExecuteInScopeWithResultAsync` + +### 通用化重构 +- **提取通用接口**:创建 `IServiceScopeExecutor` 接口,定义作用域服务执行的标准方法 +- **创建通用实现**:创建 `ServiceScopeExecutor` 类,实现 `IServiceScopeExecutor` 接口 +- **重命名结果类**:将 `OperationResult` 重命名为 `ScopeOperationResult`,使其更加具体和明确 +- **添加无返回值结果类**:创建 `ScopeOperationResult` 类,用于无返回值的操作 +- **接口设计**: + - `ExecuteWithResultAsync()` - 用于有返回值的操作 + - `ExecuteAsync()` - 用于无返回值的操作 +- **重构DeviceManagementService**:移除私有方法,改为注入和使用 `IServiceScopeExecutor` +- **可复用性**:其他需要作用域服务的类可以直接注入 `IServiceScopeExecutor` +- **依赖注入**:需要在DI容器中注册 `ServiceScopeExecutor` 为 `IServiceScopeExecutor` + +### BackgroundService 优化 +- **移除多余的 Task.Run**:在 `BackgroundService` 中直接使用 `await ProcessProtocolLogsAsync(stoppingToken)` +- **简化执行逻辑**:移除了不必要的 `while` 循环和 `Task.Delay` +- **正确的异步模式**:`BackgroundService` 应该直接等待主要任务完成,而不是使用 `Task.Run` +- **更好的取消支持**:直接传递 `stoppingToken` 给子任务,确保正确的取消传播 + +### 性能优化 +- **减少轮询延迟**:将 `Task.Delay(100)` 改为 `Task.Delay(10)`,提高响应性 +- **性能对比分析**: + - **轮询模式**:固定延迟,响应延迟可控,但CPU使用率较高 + - **事件驱动**:零延迟响应,CPU使用率低,但需要支持事件机制 + - **定时器模式**:固定间隔处理,适合批量处理,但响应延迟固定 +- **当前选择**:使用短延迟轮询,平衡响应性和资源使用 +- **未来优化方向**:如果 `IProtocolChannelManager` 支持事件机制,可改为事件驱动模式 + +### 服务生命周期管理 +- **构造函数限制**:不能在构造函数中直接注入作用域服务(如 `IProtocolLogRepository`) +- **生命周期冲突**:单例服务(BackgroundService)不能持有作用域服务的引用 +- **内存泄漏风险**:作用域服务被单例持有会导致内存泄漏 +- **数据库连接问题**:作用域服务通常包含数据库连接,被单例持有会导致连接管理问题 +- **正确做法**:使用 `IServiceScopeFactory` 在需要时创建作用域并获取服务 +- **参数验证**:添加操作委托和服务作用域工厂的空值检查 +- **取消令牌支持**:在执行操作前检查取消令牌状态 +- **返回值验证**:对于引用类型,检查返回值是否为null并记录警告 +- **异常分类处理**: + - `OperationCanceledException`:操作被取消,记录信息日志 + - `ObjectDisposedException`:服务作用域已被释放,记录错误日志 + - `InvalidOperationException`:作用域操作无效,记录错误日志 + - `Exception`:其他未预期的错误,记录详细错误信息 +- **详细错误信息**:在日志中包含具体的错误消息,便于问题排查 + +--- + ## 2025-01-29 - 创建CellularDeviceRuntimeDetailRepository实现类 ### 修改原因