protected internal override async Task <JobContinuation> Execute() { // Give an extra 10 minutes to execute await Extend(TimeSpan.FromMinutes(10)); Start = DateTime.UtcNow; // Defaults: // SourceServerName = Sql.Legacy Server Name // SourceDatabaseName = Sql.Legacy DB Name // TargetServerName = SourceServerName SourceServerName = String.IsNullOrEmpty(SourceServerName) ? Utils.GetSqlServerName(Config.Sql.Legacy.DataSource) : SourceServerName; SourceDatabaseName = String.IsNullOrEmpty(SourceDatabaseName) ? Config.Sql.Legacy.InitialCatalog : SourceDatabaseName; TargetServerName = String.IsNullOrEmpty(TargetServerName) ? SourceServerName : TargetServerName; TargetDatabaseName = String.IsNullOrEmpty(TargetDatabaseNamePrefix) ? TargetDatabaseName : (TargetDatabaseNamePrefix + "_" + DateTime.UtcNow.ToString("yyyyMMMdd_HHmm") + "Z").ToLowerInvariant(); // Use our invocation ID to generate a unique name CopyName = "copytemp_" + Context.Invocation.Id.ToString("N"); Log.BeginningDatabaseCopyProcess(SourceServerName, SourceDatabaseName, TargetServerName, TargetDatabaseName, CopyName); using (var sql = CloudContext.Clients.CreateSqlManagementClient(Azure.GetCredentials(throwIfMissing: true))) { // 1. Start the copy to a unique-named database Log.StartingCopy(SourceServerName, SourceDatabaseName, TargetServerName, CopyName); var response = await sql.DatabaseCopies.CreateAsync( SourceServerName, SourceDatabaseName, new DatabaseCopyCreateParameters() { PartnerDatabase = CopyName, PartnerServer = TargetServerName }); // Would have thrown if it failed, so now start checking the status CopyOperationId = response.DatabaseCopy.Name; Log.StartedCopy(CopyOperationId); return(await Resume()); } }
protected internal override async Task <JobContinuation> Resume() { // Give us another 10 minutes to execute await Extend(TimeSpan.FromMinutes(10)); using (var sql = CloudContext.Clients.CreateSqlManagementClient(Azure.GetCredentials(throwIfMissing: true))) { try { // 2. Check the status of the copy Log.CheckingCopyStatus(CopyOperationId); var ops = await sql.DatabaseOperations.ListByDatabaseAsync(TargetServerName, CopyName); var op = ops.FirstOrDefault(); switch (op.StateId) { case 2: // COMPLETED (http://msdn.microsoft.com/en-us/library/azure/dn720371.aspx) Log.CopyCompleted(); await CompleteCopy(sql); Log.CompletedDatabaseCopyProcess(SourceServerName, SourceDatabaseName, TargetServerName, TargetDatabaseName); return(Complete()); case 3: // FAILED // Copy failed! Fail the whole job throw new JobFailureException(op.Error); default: // Copy is still in progress, check for timeout if (Timeout.HasValue && ((DateTime.UtcNow - Context.Invocation.QueuedAt.UtcDateTime) >= Timeout.Value)) { // Abort the copy await AbortCopy(sql); throw new JobFailureException("Copy operation exceeded timeout and was aborted."); } // Save state and wait for another five minutes Log.CopyInProgress(op.PercentComplete); return(Suspend(TimeSpan.FromMinutes(5), new { SourceServerName, SourceDatabaseName, TargetServerName, TargetDatabaseName, CopyName, CopyOperationId, Timeout, Start })); } } catch (Exception) { // Abort the copy AbortCopy(sql).Wait(); throw; } } }
protected internal override async Task <JobContinuation> Execute() { ServerName = String.IsNullOrEmpty(ServerName) ? Utils.GetSqlServerName(Config.Sql.Legacy.DataSource) : ServerName; // Capture the current time in case the date changes during invocation DateTimeOffset now = DateTimeOffset.UtcNow; // Resolve the connection if not specified explicitly Log.PreparingToClean(ServerName); // Connect to the master database using (var sql = CloudContext.Clients.CreateSqlManagementClient(Azure.GetCredentials(throwIfMissing: true))) { // Get online databases Log.GettingDatabaseList(ServerName); var dbs = (await sql.Databases.ListAsync(ServerName)).ToList(); Log.GotDatabases(dbs.Count, ServerName); // Determine which of these are backups var backups = dbs .Select(d => DatabaseBackup <Database> .Create(d)) .Where(b => b != null && String.Equals(NamePrefix, b.Prefix, StringComparison.OrdinalIgnoreCase)) .ToList(); // Start collecting a list of backups we're going to keep var keepers = new HashSet <DatabaseBackup <Database> >(); // Group backups by UTC Day var backupsByDate = backups .GroupBy(b => b.Timestamp.UtcDateTime.Date) .OrderByDescending(g => g.Key); // Keep the last backup from today and the max daily backups if any var dailyBackups = backupsByDate .Take(MaxDailyCopies ?? 1) .Select(g => g.OrderBy(db => db.Timestamp).Last()); foreach (var keeper in dailyBackups) { keepers.Add(keeper); } // Keep the most recent backups based on MaxRunningBackups foreach (var keeper in backups.OrderByDescending(b => b.Timestamp).Take(MaxRunningCopies ?? 1)) { keepers.Add(keeper); } // Report keepers foreach (var keeper in keepers) { Log.KeepingBackup(keeper.Db.Name); } // Delete the others! foreach (var db in backups.Select(b => b.Db.Name).Except(keepers.Select(b => b.Db.Name), StringComparer.OrdinalIgnoreCase)) { Log.DeletingBackup(db); if (!WhatIf) { await sql.Databases.DeleteAsync(ServerName, db); } Log.DeletedBackup(db); } // Clean out CopyTemp databases older than 3 hours var copytemps = dbs .Where(db => db.Name.StartsWith("copytemp", StringComparison.OrdinalIgnoreCase) && db.CreationDate < DateTime.UtcNow.AddHours(-3)); foreach (var copytemp in copytemps) { Log.DeletingBackup(copytemp.Name); if (!WhatIf) { await sql.Databases.DeleteAsync(ServerName, copytemp.Name); } Log.DeletedBackup(copytemp.Name); } } return(Complete()); }