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);
        }
Ejemplo n.º 2
0
 public virtual Task RunAsync(MigrationContext context)
 {
     return(RunAsync());
 }