-
Notifications
You must be signed in to change notification settings - Fork 61
/
ZipDeploymentStatus.cs
124 lines (112 loc) · 4.52 KB
/
ZipDeploymentStatus.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Build.Utilities;
using Microsoft.NET.Sdk.Functions.Http;
using Microsoft.NET.Sdk.Functions.MSBuild.Properties;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Task = System.Threading.Tasks.Task;
namespace Microsoft.NET.Sdk.Functions.MSBuild.Tasks
{
internal 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<DeployStatus> PollDeploymentStatusAsync(string deploymentUrl, string userName, string password)
{
DeployStatus deployStatus = DeployStatus.Pending;
var tokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(MaxMinutesToWait));
if (_logMessages)
{
_log.LogMessage(Resources.DeploymentStatusPolling);
}
while (!tokenSource.IsCancellationRequested && deployStatus != DeployStatus.Success && deployStatus != DeployStatus.Failed && deployStatus != DeployStatus.Unknown)
{
try
{
deployStatus = await GetDeploymentStatusAsync(deploymentUrl, userName, password, RetryCount, TimeSpan.FromSeconds(RetryDelaySeconds), tokenSource);
if (_logMessages)
{
_log.LogMessage(String.Format(Resources.DeploymentStatus, Enum.GetName(typeof(DeployStatus), deployStatus)));
}
}
catch (HttpRequestException)
{
return DeployStatus.Unknown;
}
await Task.Delay(TimeSpan.FromSeconds(StatusRefreshDelaySeconds));
}
return deployStatus;
}
private async Task<DeployStatus> GetDeploymentStatusAsync(string deploymentUrl, string userName, string password, int retryCount, TimeSpan retryDelay, CancellationTokenSource cts)
{
var json = await InvokeGetRequestWithRetryAsync<JObject>(deploymentUrl, userName, password, retryCount, retryDelay, cts);
if (json != null
&& json.TryGetValue("status", out JToken statusString)
&& Enum.TryParse(statusString.Value<string>(), out DeployStatus result))
{
return result;
}
return 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.GetWithBasicAuthAsync(new Uri(url, UriKind.RelativeOrAbsolute), userName, password, _userAgent, cts.Token);
}, retryCount, retryDelay);
if (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.Accepted)
{
return default(T);
}
else
{
using (var stream = await response.GetResponseBodyAsync())
{
var reader = new StreamReader(stream, Encoding.UTF8);
return JsonConvert.DeserializeObject<T>(reader.ReadToEnd());
}
}
}
private async Task RetryAsync(Func<Task> func, int retryCount, TimeSpan retryDelay)
{
while (true)
{
try
{
await func();
return;
}
catch (Exception e)
{
if (retryCount <= 0)
{
throw e;
}
retryCount--;
}
await Task.Delay(retryDelay);
}
}
}
}