public static async Task RestoreAsync(RestoreCommand restoreCommand, ILogger logger, CancellationToken cancellationToken) { await using var connection = restoreCommand.CreateConnectionMars(); var state = new RestoreState(logger, restoreCommand, connection); state.LogStarting(); await state.EnsuredIndexsExistsAsync(); await Task.WhenAll( state.LoadServerInfosAsync(), state.LoadDatabasesAsync(), state.LoadRestoreHistoryAsync(), state.PrepareRestoreJobAsync()); logger.Information($"{state.Directories.Count} directories found"); logger.Information("Starting..."); var po = new ParallelizeOption { FailMode = Fail.Smart, MaxDegreeOfParallelism = restoreCommand.Threads }; IRestoreMethod method = restoreCommand.Brentozar ? (IRestoreMethod) new BrentozarRestoreMethod(state, connection) : new NativeRestoreMethod(state); await state.Directories .ParallelizeAsync((item, cancel) => RestoreBackupAsync(method, item, state), po, cancellationToken) .ForEachAsync((value, token) => { state.Accumulated = state.Accumulated.Add(value.Item.Elapsed); return(Task.CompletedTask); }); var report = await state.GetReportStateAsync(); state.LogFinished(report); var slack = new SlackSender(new SlackClient(logger)); await slack.ReportAsync(report, state.RestoreCommand.SlackChannel, state.RestoreCommand.SlackSecret, state.RestoreCommand.SlackOnlyOnError, state.RestoreCommand.SlackTitle); await report.SendMailAsync(state.RestoreCommand.Email, state.RestoreCommand.Smtp, cancellationToken); if (report.Status.HasFlag(ReportStatus.Error)) { Environment.ExitCode = 1; } }
private static async Task <RestoreItem> RestoreBackupAsync(IRestoreMethod restoreMethod, RestoreItem item, RestoreState state) { RestoreCommand restoreCommand = state.RestoreCommand; state.Loggger.Debug($"Starting restore for {item.Name}"); item.SetStart(); await using var sqlConnection = restoreCommand.CreateConnectionMars(); Exception exception; if (restoreCommand.FullOnly) { exception = await restoreMethod.RestoreFullAsync(item); } else { bool startFromFull = StartFromFull(state, item); exception = await restoreMethod.RestoreFullDiffLogAsync(item, startFromFull); } var incremented = state.Increment(); state.Loggger.Information($"[{incremented}/{state.Directories.Count}] OK : {item.Name} {item.Stats()}"); if (exception != null) { state.ExceptionBackupFull.Add((exception, item)); item.SetError(exception); state.Loggger.Error(exception, $"Error restoring {item.Name}"); return(item); } try { Exception scriptException = null; if (restoreCommand.RunRecovery) { var recoveryException = await restoreMethod.RunRecoveryAsync(item); if (recoveryException != null) { state.ExceptionBackupFull.Add((recoveryException, item)); item.SetError(recoveryException); throw recoveryException; } scriptException = await PostScriptExecuteAsync(state, item); await RunDbccCheckDb(state, item); } if (scriptException != null) { state.ExceptionBackupFull.Add((scriptException, item)); item.SetError(scriptException); } if (restoreCommand.IsUncheckedModeEnable) { try { // overwrite destination if exists var target = Path.Combine(restoreCommand.Checked.FullName, item.Name); if (Directory.Exists(target)) { Directory.Delete(target, true); } item.BaseDirectoryInfo.MoveTo(target); } catch (Exception e) { state.Loggger.Error(e, $"Error moving {item.Name}"); return(item); } } if (scriptException != null) { return(item); } } catch (Exception e) { item.SetError(e); return(item); } item.SetSuccess(); state.OkBackupFull.Add(item); state.Loggger.Debug($"Finished restore for {item.Name}"); return(item); }