public async Task <MigrationResult> RunMigrationsAsync(CancellationToken cancellationToken = default) { if (Migrations.Count == 0) { AddMigrationsFromLoadedAssemblies(); } var migrationsLock = await _lockProvider.AcquireAsync("migration-manager", TimeSpan.FromMinutes(30), TimeSpan.Zero); if (migrationsLock == null) { return(MigrationResult.UnableToAcquireLock); } try { var migrationStatus = await GetMigrationStatus(); if (!migrationStatus.NeedsMigration) { return(MigrationResult.Success); } foreach (var migrationInfo in migrationStatus.PendingMigrations) { if (cancellationToken.IsCancellationRequested) { return(MigrationResult.Cancelled); } // stuck on non-resumable versioned migration, must be manually fixed if (migrationInfo.Migration.MigrationType == MigrationType.Versioned && migrationInfo.State != null && migrationInfo.State.StartedUtc > DateTime.MinValue) { return(MigrationResult.Failed); } await MarkMigrationStartedAsync(migrationInfo).AnyContext(); try { var context = new MigrationContext(migrationsLock, _loggerFactory.CreateLogger(migrationInfo.Migration.GetType()), cancellationToken); if (migrationInfo.Migration.MigrationType != MigrationType.Versioned) { await Run.WithRetriesAsync <object>(async() => { await migrationsLock.RenewAsync(TimeSpan.FromMinutes(30)); if (cancellationToken.IsCancellationRequested) { return(MigrationResult.Cancelled); } await migrationInfo.Migration.RunAsync(context).AnyContext(); return(null); }, 3, retryInterval : TimeSpan.Zero, cancellationToken : CancellationToken.None, _logger).AnyContext(); } else { await migrationInfo.Migration.RunAsync(context).AnyContext(); } } catch (Exception ex) { _logger.LogError(ex, "Failed running migration {Id}", migrationInfo.Migration.GetId()); migrationInfo.State.ErrorMessage = ex.Message; await _migrationStatusRepository.SaveAsync(migrationInfo.State).AnyContext(); return(MigrationResult.Failed); } await MarkMigrationCompleteAsync(migrationInfo).AnyContext(); // renew migration lock await migrationsLock.RenewAsync(TimeSpan.FromMinutes(30)); } } finally { await migrationsLock.ReleaseAsync(); } return(MigrationResult.Success); }
public virtual Task RunAsync(MigrationContext context) { return(RunAsync()); }