private static void AutoRenewLeaseOnBlob(AzureBlobLease instance, string accountName, string accountKey, string containerName, string blob, string leaseId, string leaseUrl, Microsoft.Build.Utilities.TaskLoggingHelper log) { TimeSpan maxWait = TimeSpan.FromSeconds(s_MaxWaitDefault); TimeSpan delay = TimeSpan.FromMilliseconds(s_DelayDefault); TimeSpan waitFor = maxWait; CancellationToken token = instance._cancellationTokenSource.Token; while (true) { token.ThrowIfCancellationRequested(); try { log.LogMessage(MessageImportance.Low, $"Requesting lease for container/blob '{containerName}/{blob}'."); using (HttpClient client = new HttpClient()) { Tuple <string, string> leaseAction = new Tuple <string, string>("x-ms-lease-action", "renew"); Tuple <string, string> headerLeaseId = new Tuple <string, string>("x-ms-lease-id", leaseId); List <Tuple <string, string> > additionalHeaders = new List <Tuple <string, string> >() { leaseAction, headerLeaseId }; var request = Utility.AzureHelper.RequestMessage("PUT", leaseUrl, accountName, accountKey, additionalHeaders); using (HttpResponseMessage response = Utility.AzureHelper.RequestWithRetry(log, client, request).GetAwaiter().GetResult()) { if (!response.IsSuccessStatusCode) { throw new Exception("Unable to acquire lease."); } } } waitFor = maxWait; } catch (Exception e) { Console.WriteLine($"Rerying lease renewal on {containerName}, {e.Message}"); waitFor = delay; } token.ThrowIfCancellationRequested(); Thread.Sleep(waitFor); } }
public override bool Execute() { ParseConnectionString(); if (Log.HasLoggedErrors) { return(false); } if (!FinalizeContainer.EndsWith("/")) { FinalizeContainer = $"{FinalizeContainer}/"; } string targetVersionFile = $"{FinalizeContainer}{Version}"; CreateBlobIfNotExists(SemaphoreBlob); AzureBlobLease blobLease = new AzureBlobLease(AccountName, AccountKey, ConnectionString, ContainerName, SemaphoreBlob, Log); Log.LogMessage($"Acquiring lease on semaphore blob '{SemaphoreBlob}'"); blobLease.Acquire(); // Prevent race conditions by dropping a version hint of what version this is. If we see this file // and it is the same as our version then we know that a race happened where two+ builds finished // at the same time and someone already took care of publishing and we have no work to do. if (IsLatestSpecifiedVersion(targetVersionFile) && !ForcePublish) { Log.LogMessage(MessageImportance.Low, $"version hint file for publishing finalization is {targetVersionFile}"); Log.LogMessage(MessageImportance.High, $"Version '{Version}' is already published, skipping finalization."); Log.LogMessage($"Releasing lease on semaphore blob '{SemaphoreBlob}'"); blobLease.Release(); return(true); } else { // Delete old version files GetBlobList(FinalizeContainer) .Select(s => s.Replace("/dotnet/", "")) .Where(w => _versionRegex.Replace(Path.GetFileName(w), "") == "") .ToList() .ForEach(f => TryDeleteBlob(f)); // Drop the version file signaling such for any race-condition builds (see above comment). CreateBlobIfNotExists(targetVersionFile); try { CopyBlobs( $"{ProductBlobStorageName}/{ProductVersion}/", $"{ProductBlobStorageName}/{Channel}/"); // Generate the latest version text file string sfxVersion = GetSharedFrameworkVersionFileContent(); PublishStringToBlob( ContainerName, $"{ProductBlobStorageName}/{Channel}/latest.version", sfxVersion, "text/plain"); } finally { blobLease.Release(); } } return(!Log.HasLoggedErrors); }