Browse Source

Merge pull request #19506 from abpframework/bug/multiple-instance-migration

Database migration event handler multiple instance bug fixed
pull/19511/head
Halil İbrahim Kalkan 2 years ago
committed by GitHub
parent
commit
f85b3dd5d6
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 34
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Migrations/EfCoreDatabaseMigrationEventHandlerBase.cs

34
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Migrations/EfCoreDatabaseMigrationEventHandlerBase.cs

@ -7,6 +7,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.DistributedLocking;
using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.EventBus.Distributed; using Volo.Abp.EventBus.Distributed;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
@ -37,10 +38,16 @@ public abstract class EfCoreDatabaseMigrationEventHandlerBase<TDbContext> :
/// </summary> /// </summary>
protected int MaxValueToWaitOnFailure { get; set; } = 15000; protected int MaxValueToWaitOnFailure { get; set; } = 15000;
/// <summary>
/// As minutes.
/// </summary>
protected TimeSpan DistributedLockAcquireTimeout { get; set; } = TimeSpan.FromMinutes(15);
protected ICurrentTenant CurrentTenant { get; } protected ICurrentTenant CurrentTenant { get; }
protected IUnitOfWorkManager UnitOfWorkManager { get; } protected IUnitOfWorkManager UnitOfWorkManager { get; }
protected ITenantStore TenantStore { get; } protected ITenantStore TenantStore { get; }
protected IDistributedEventBus DistributedEventBus { get; } protected IDistributedEventBus DistributedEventBus { get; }
protected IAbpDistributedLock DistributedLock { get; }
protected ILogger<EfCoreDatabaseMigrationEventHandlerBase<TDbContext>> Logger { get; } protected ILogger<EfCoreDatabaseMigrationEventHandlerBase<TDbContext>> Logger { get; }
protected EfCoreDatabaseMigrationEventHandlerBase( protected EfCoreDatabaseMigrationEventHandlerBase(
@ -48,6 +55,7 @@ public abstract class EfCoreDatabaseMigrationEventHandlerBase<TDbContext> :
ICurrentTenant currentTenant, ICurrentTenant currentTenant,
IUnitOfWorkManager unitOfWorkManager, IUnitOfWorkManager unitOfWorkManager,
ITenantStore tenantStore, ITenantStore tenantStore,
IAbpDistributedLock abpDistributedLock,
IDistributedEventBus distributedEventBus, IDistributedEventBus distributedEventBus,
ILoggerFactory loggerFactory) ILoggerFactory loggerFactory)
{ {
@ -55,6 +63,7 @@ public abstract class EfCoreDatabaseMigrationEventHandlerBase<TDbContext> :
UnitOfWorkManager = unitOfWorkManager; UnitOfWorkManager = unitOfWorkManager;
TenantStore = tenantStore; TenantStore = tenantStore;
DatabaseName = databaseName; DatabaseName = databaseName;
DistributedLock = abpDistributedLock;
DistributedEventBus = distributedEventBus; DistributedEventBus = distributedEventBus;
Logger = loggerFactory.CreateLogger<EfCoreDatabaseMigrationEventHandlerBase<TDbContext>>(); Logger = loggerFactory.CreateLogger<EfCoreDatabaseMigrationEventHandlerBase<TDbContext>>();
@ -186,16 +195,35 @@ public abstract class EfCoreDatabaseMigrationEventHandlerBase<TDbContext> :
{ {
using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: false)) using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: false))
{ {
async Task<IAsyncDisposable> WaitForDistributedLockAsync(TDbContext dbContext)
{
var distributedLockHandle = await DistributedLock.TryAcquireAsync(
"DatabaseMigrationEventHandler_" +
dbContext.Database.GetConnectionString()!.ToUpperInvariant().ToMd5(),
DistributedLockAcquireTimeout
);
if(distributedLockHandle == null)
{
throw new AbpException($"Distributed lock could not be acquired for database migration event handler: {DatabaseName}.");
}
return distributedLockHandle;
}
async Task<bool> MigrateDatabaseSchemaWithDbContextAsync() async Task<bool> MigrateDatabaseSchemaWithDbContextAsync()
{ {
var dbContext = await uow.ServiceProvider var dbContext = await uow.ServiceProvider
.GetRequiredService<IDbContextProvider<TDbContext>>() .GetRequiredService<IDbContextProvider<TDbContext>>()
.GetDbContextAsync(); .GetDbContextAsync();
if ((await dbContext.Database.GetPendingMigrationsAsync()).Any()) await using (await WaitForDistributedLockAsync(dbContext))
{ {
await dbContext.Database.MigrateAsync(); if ((await dbContext.Database.GetPendingMigrationsAsync()).Any())
return true; {
await dbContext.Database.MigrateAsync();
return true;
}
} }
return false; return false;

Loading…
Cancel
Save