| File: Tasks\ZipDeploy\ZipDeploymentStatus.cs | Web Access |
| Project: src\sdk\src\WebSdk\Publish\Tasks\Microsoft.NET.Sdk.Publish.Tasks.csproj (Microsoft.NET.Sdk.Publish.Tasks) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Net; using System.Net.Http; using System.Text.Json; using Microsoft.Build.Utilities; using Microsoft.NET.Sdk.Publish.Tasks.Properties; namespace Microsoft.NET.Sdk.Publish.Tasks.ZipDeploy { public class ZipDeploymentStatus { private const int MaxMinutesToWait = 3; private const int StatusRefreshDelaySeconds = 3; private const int RetryCount = 3; private const int RetryDelaySeconds = 1; private readonly IHttpClient _client; private readonly string _userAgent; private readonly TaskLoggingHelper _log; private readonly bool _logMessages; public ZipDeploymentStatus(IHttpClient client, string userAgent, TaskLoggingHelper log, bool logMessages) { _client = client; _userAgent = userAgent; _log = log; _logMessages = logMessages; } public async Task<DeploymentResponse?> PollDeploymentStatusAsync(string deploymentUrl, string? userName, string? password) { var tokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(MaxMinutesToWait)); if (_logMessages) { _log.LogMessage(Resources.ZIPDEPLOY_DeploymentStatusPolling); } DeploymentResponse? deploymentResponse = null; DeployStatus? deployStatus = DeployStatus.Pending; while (!tokenSource.IsCancellationRequested && deployStatus != DeployStatus.Success && deployStatus != DeployStatus.Failed && deployStatus != DeployStatus.Unknown) { try { deploymentResponse = await InvokeGetRequestWithRetryAsync<DeploymentResponse>( deploymentUrl, userName, password, RetryCount, TimeSpan.FromSeconds(RetryDelaySeconds), tokenSource); deployStatus = deploymentResponse?.Status is not null ? deploymentResponse.Status : DeployStatus.Unknown; if (_logMessages) { _log.LogMessage(string.Format(Resources.ZIPDEPLOY_DeploymentStatus, Enum.GetName(typeof(DeployStatus), deployStatus))); } } catch (HttpRequestException) { return deploymentResponse; } await System.Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(StatusRefreshDelaySeconds)); } return deploymentResponse ?? new() { Status = DeployStatus.Unknown }; } private async Task<T?> InvokeGetRequestWithRetryAsync<T>(string url, string? userName, string? password, int retryCount, TimeSpan retryDelay, CancellationTokenSource cts) { IHttpResponse? response = null; await RetryAsync(async () => { response = await _client.GetRequestAsync(new Uri(url, UriKind.RelativeOrAbsolute), userName, password, _userAgent, cts.Token); }, retryCount, retryDelay); if (response?.StatusCode != HttpStatusCode.OK && response?.StatusCode != HttpStatusCode.Accepted) { return default; } using var stream = await response.GetResponseBodyAsync(); if (stream is null) { return default; } var reader = new StreamReader(stream, Encoding.UTF8); return FromJson<T>(reader.ReadToEnd()); } private async System.Threading.Tasks.Task RetryAsync(Func<System.Threading.Tasks.Task> func, int retryCount, TimeSpan retryDelay) { while (true) { try { await func(); return; } catch (Exception) { if (retryCount <= 0) { throw; } retryCount--; } await System.Threading.Tasks.Task.Delay(retryDelay); } } private static T? FromJson<T>(string jsonString) { return JsonSerializer.Deserialize<T>(jsonString, new JsonSerializerOptions { AllowTrailingCommas = true, ReadCommentHandling = JsonCommentHandling.Skip }); } } }