108 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			108 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Linq;
 | |
| using System.Threading.Tasks;
 | |
| using Microsoft.EntityFrameworkCore;
 | |
| using Microsoft.Extensions.DependencyInjection;
 | |
| using Serilog;
 | |
| using Volo.Abp;
 | |
| using Volo.Abp.Data;
 | |
| using Volo.Abp.DependencyInjection;
 | |
| using Volo.Abp.DistributedLocking;
 | |
| using Volo.Abp.EventBus.Distributed;
 | |
| using Volo.Abp.MultiTenancy;
 | |
| using Volo.Abp.Uow;
 | |
| 
 | |
| namespace KonSoft.Shared.Hosting.Microservices.DbMigrations.EfCore;
 | |
| 
 | |
| public abstract class PendingEfCoreMigrationsChecker<TDbContext> : ITransientDependency
 | |
|     where TDbContext : DbContext
 | |
| {
 | |
|     protected PendingEfCoreMigrationsChecker(
 | |
|         IUnitOfWorkManager unitOfWorkManager,
 | |
|         IServiceProvider serviceProvider,
 | |
|         ICurrentTenant currentTenant,
 | |
|         IDistributedEventBus distributedEventBus,
 | |
|         IAbpDistributedLock abpDistributedLock,
 | |
|         string databaseName)
 | |
|     {
 | |
|         UnitOfWorkManager = unitOfWorkManager;
 | |
|         ServiceProvider = serviceProvider;
 | |
|         CurrentTenant = currentTenant;
 | |
|         DistributedEventBus = distributedEventBus;
 | |
|         DistributedLockProvider = abpDistributedLock;
 | |
|         DatabaseName = databaseName;
 | |
|     }
 | |
| 
 | |
|     protected IUnitOfWorkManager UnitOfWorkManager { get; }
 | |
|     protected IServiceProvider ServiceProvider { get; }
 | |
|     protected ICurrentTenant CurrentTenant { get; }
 | |
|     protected IDistributedEventBus DistributedEventBus { get; }
 | |
|     protected IAbpDistributedLock DistributedLockProvider { get; }
 | |
|     protected string DatabaseName { get; }
 | |
| 
 | |
|     public virtual async Task CheckAndApplyDatabaseMigrationsAsync()
 | |
|     {
 | |
|         await TryAsync(LockAndApplyDatabaseMigrationsAsync);
 | |
|     }
 | |
| 
 | |
|     protected async Task TryAsync(Func<Task> task, int retryCount = 3)
 | |
|     {
 | |
|         try
 | |
|         {
 | |
|             await task();
 | |
|         }
 | |
|         catch (Exception ex)
 | |
|         {
 | |
|             retryCount--;
 | |
| 
 | |
|             if (retryCount <= 0)
 | |
|             {
 | |
|                 throw;
 | |
|             }
 | |
| 
 | |
|             Log.Warning(
 | |
|                 $"{ex.GetType().Name} has been thrown. The operation will be tried {retryCount} times more. Exception:\n{ex.Message}");
 | |
| 
 | |
|             await Task.Delay(RandomHelper.GetRandom(5000, 15000));
 | |
| 
 | |
|             await TryAsync(task, retryCount);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     protected virtual async Task LockAndApplyDatabaseMigrationsAsync()
 | |
|     {
 | |
|         await using var handle = await DistributedLockProvider.TryAcquireAsync("Migration_" + DatabaseName);
 | |
|         Log.Information($"Lock is acquired for db migration and seeding on database named: {DatabaseName}...");
 | |
| 
 | |
|         if (handle is null)
 | |
|         {
 | |
|             Log.Information($"Handle is null because of the locking for : {DatabaseName}");
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         using (CurrentTenant.Change(null))
 | |
|         {
 | |
|             // Create database tables if needed
 | |
|             using (var uow = UnitOfWorkManager.Begin(true, false))
 | |
|             {
 | |
|                 var dbContext = ServiceProvider.GetRequiredService<TDbContext>();
 | |
| 
 | |
|                 var pendingMigrations = await dbContext
 | |
|                     .Database
 | |
|                     .GetPendingMigrationsAsync();
 | |
| 
 | |
|                 if (pendingMigrations.Any())
 | |
|                 {
 | |
|                     await dbContext.Database.MigrateAsync();
 | |
|                 }
 | |
| 
 | |
|                 await uow.CompleteAsync();
 | |
|             }
 | |
| 
 | |
|             await ServiceProvider.GetRequiredService<IDataSeeder>()
 | |
|                 .SeedAsync();
 | |
|         }
 | |
| 
 | |
|         Log.Information($"Lock is released for db migration and seeding on database named: {DatabaseName}...");
 | |
|     }
 | |
| } |