- {"Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.\r\nObject name: 'UnifiedDbContext'."}
- Steps to reproduce the issue:
- using FireBytes.Unified.SysTem.CustomizeLogging; using FireBytes.Unified.SysTem.Lock; using FireBytes.Unified.Wave.Devices; using FireBytes.Unified.Wave.DeviceTypes; using FireBytes.Unified.Wave.DeviceTypeSystems; using FireBytes.Unified.Wave.MqSynchronizeRecords; using FireBytes.Unified.Wave.Pacs.PacsMqHelper; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using System; using System.Linq; using System.Threading.Tasks; using Volo.Abp.BackgroundWorkers; using Volo.Abp.DistributedLocking; using Volo.Abp.Domain.Repositories; using Volo.Abp.MultiTenancy; using Volo.Abp.Threading; using Volo.Saas.Tenants;
namespace FireBytes.Unified.BackgroundWorker { public class MqCardHolderBackgroundWorker : AsyncPeriodicBackgroundWorkerBase { private readonly IMqBackgroundAppService _mqBackgroundApp; private readonly ICurrentTenant _currentTenant; private readonly IDistributedLockManager _lockManager; private readonly IHelperLogging _helperLogging;
private static readonly string lockKey = "Wave_Async_MqCardHolderBackgroundWorker";
private static readonly string logKey = "BackgroundLog";
public MqCardHolderBackgroundWorker(
AbpAsyncTimer timer,
IServiceScopeFactory serviceScopeFactory,
IMqBackgroundAppService mqBackgroundApp,
ICurrentTenant currentTenant,
IDistributedLockManager lockManager,
IHelperLogging helperLogging)
: base(timer, serviceScopeFactory)
{
Timer.Period = 3 * 1000; // 每 3 秒执行一次
_mqBackgroundApp = mqBackgroundApp;
_currentTenant = currentTenant;
_lockManager = lockManager;
_helperLogging = helperLogging;
}
protected override async Task DoWorkAsync(PeriodicBackgroundWorkerContext workerContext)
{
try
{
_helperLogging.LogInformation(logKey, "MqCardHolderBackgroundWorker is running");
var tenantRepository = workerContext.ServiceProvider.GetRequiredService<ITenantRepository>();
var tenants = await tenantRepository.GetListAsync();
foreach (var tenant in tenants)
{
try
{
using (_currentTenant.Change(tenant.Id))
using (var scope = workerContext.ServiceProvider.CreateScope())
{
var deviceRepository = scope.ServiceProvider.GetRequiredService<IRepository<Device>>();
var deviceTypeRepository = scope.ServiceProvider.GetRequiredService<IRepository<DeviceType>>();
var deviceTypeSystemRepository = scope.ServiceProvider.GetRequiredService<IRepository<DeviceTypeSystem>>();
var deviceQuery = await deviceRepository.GetQueryableAsync();
var deviceTypeQuery = await deviceTypeRepository.GetQueryableAsync();
var deviceTypeSystemQuery = await deviceTypeSystemRepository.GetQueryableAsync();
var deviceInner = from device in deviceQuery
join deviceType in deviceTypeQuery on device.DeviceTypeId equals deviceType.Id
join deviceTypeSystem in deviceTypeSystemQuery on deviceType.DeviceSystemTypeId equals deviceTypeSystem.Id
where deviceTypeSystem.Name == "PACS"
select device.DeviceVendorSystemId;
var deviceListQuery = await deviceInner.AsNoTracking().ToListAsync();
var deviceList = deviceListQuery.Distinct().ToList();
foreach (var device in deviceList)
{
await _lockManager.ExecuteWithLockAsync($"{lockKey}_{tenant.Id}_{device}", async () =>
{
await _mqBackgroundApp.AsyncSendCardHolderMQ(device);
}, TimeSpan.FromSeconds(10));
}
_helperLogging.LogInformation(logKey, $"租户 {tenant.Name} 任务执行完成");
}
}
catch (Exception innerEx)
{
_helperLogging.LogError(logKey, innerEx, $"租户 {tenant.Name} 执行失败: {innerEx.Message}");
}
}
_helperLogging.LogInformation(logKey, "MqCardHolderBackgroundWorker is end");
}
catch (Exception ex)
{
_helperLogging.LogError(logKey, ex, $"MqCardHolderBackgroundWorker 异常: {ex.Message}\nStackTrace: {ex.StackTrace}");
}
}
}
}
7 Answer(s)
-
0
hi
Try to add
UnitOfWork
attribute toDoWorkAsync
method or begin a new UOW[UnitOfWork] protected override async Task DoWorkAsync(PeriodicBackgroundWorkerContext workerContext) { }
protected override async Task DoWorkAsync(PeriodicBackgroundWorkerContext workerContext) { try { using (var uow = _unitOfWorkManager.Begin(requiresNew: true)) { await uow.CompleteAsync(); } } }
-
0
如果我使用多线程执行,怎么保证每个线程里面的dbcontex都是一个新的,现在并发执行时一直在var lists = await query.Where报错:{"A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913."}
public async Task AsyncSendCardHolderMQ(string deviceVendorSystemId) { try { // 在新的作用域中处理查询和更新 using (var scope = _serviceProvider.CreateScope()) { // 对更新操作使用独立 UoW,确保不会被全局 UoW 影响 using (var uow = _unitOfWorkManager.Begin(isTransactional: true)) {
var mqRecordRepository = scope.ServiceProvider.GetRequiredService<IRepository<MqSynchronizeRecord>>(); var query = await mqRecordRepository.GetQueryableAsync(); var lists = await query.Where(item => item.sendTime == null && item.QueueNameSycn != null && item.QueueName == MqQueueNameEnum.card_holder.ToString() && item.DeviceVendorSystemId == deviceVendorSystemId) .OrderBy(item => item.SubmissionDateTime) .Take(100) .ToListAsync(); if (lists.Any()) { var priority = Convert.ToByte(10); foreach (var item in lists) { item.sendTime = _clock.Now; } // 这里重新解析仓储,确保是独立的上下文实例 await mqRecordRepository.UpdateManyAsync(lists); await uow.CompleteAsync(); // 提交数据库事务 await uow.SaveChangesAsync(); // 发送消息 foreach (var item in lists) { var entity = _jsonSerializer.Deserialize<PacsCardHolderQueueDto>(item.SendMessage); if (!string.IsNullOrWhiteSpace(item.Channel)) { entity.Channel = item.Channel; } _rabbitManager.PublishPro(entity, item.QueueNameSycn, priority); } } } } } catch (Exception innerEx) { Console.WriteLine($"执行失败: {innerEx.Message}{innerEx.StackTrace}"); }
}
-
0
使用
requiresNew: true
确保创建一个新的工作单元.注意: 一个
DbContext
是不支持多线程的 -
0
好的 谢谢
-
0
不客气
-
0
当我使用后台任务时:AsyncPeriodicBackgroundWorkerBase 设置 Timer.Period = 3 * 1000; // 每 3秒执行一次,当我第一次执行的时间超过了3秒,这个后台任务会同时执行好几个吗?
-
0
你好, 请打开一个新问题,谢谢