|
5 | 5 | using System.Net;
|
6 | 6 | using System.Linq;
|
7 | 7 | using System.Text;
|
| 8 | +using System.Net.Http; |
8 | 9 | using System.Threading;
|
9 | 10 | using System.Diagnostics;
|
10 | 11 | using System.Net.Sockets;
|
|
21 | 22 | using MFDLabs.Threading.Extensions;
|
22 | 23 | using MFDLabs.Reflection.Extensions;
|
23 | 24 | using MFDLabs.Diagnostics.Extensions;
|
| 25 | +using MFDLabs.ErrorHandling.Extensions; |
24 | 26 |
|
25 | 27 | // ReSharper disable InconsistentNaming
|
26 | 28 | // ReSharper disable EmptyGeneralCatchClause
|
|
29 | 31 | /** TODO: Report to Infrastructure that node deployed this App **/
|
30 | 32 | /** TODO: Expose some API to force Rollbacks and Force Deployments? **/
|
31 | 33 | /** TODO: Rate limit detection for not just the REST API but also the GraphQL API **/
|
| 34 | +/** TODO: Store some stuff in the registry like skipped version. **/ |
32 | 35 |
|
33 | 36 | namespace MFDLabs.Grid.AutoDeployer.Service
|
34 | 37 | {
|
@@ -145,6 +148,12 @@ private static bool CachedVersionExistsRemotely(out bool wasRatelimited, out Tim
|
145 | 148 | return false;
|
146 | 149 |
|
147 | 150 | }
|
| 151 | + /* Last cases for this, we assume it is either timeout or 500. */ |
| 152 | + catch (Exception ex) when (ex is HttpRequestException or ApiException) |
| 153 | + { |
| 154 | + EventLogLogger.Singleton.Warning(ex.ToDetailedString()); |
| 155 | + return true; |
| 156 | + } |
148 | 157 | catch (Exception ex)
|
149 | 158 | {
|
150 | 159 | Logger.Singleton.Error(ex);
|
@@ -238,7 +247,7 @@ private static void Work()
|
238 | 247 | {
|
239 | 248 | var uri = new Uri(gheUrl);
|
240 | 249 |
|
241 |
| - _gitHubClient = new(ghApiPhv, new Uri(gheUrl)); |
| 250 | + _gitHubClient = new(ghApiPhv, uri); |
242 | 251 | _gitHubQLClient = new(ghQlPhv, new($"{uri.Scheme}://{uri.Host}/graphql"), _githubToken);
|
243 | 252 | }
|
244 | 253 |
|
@@ -275,87 +284,95 @@ private static void SkippedVersionInvalidationWork()
|
275 | 284 |
|
276 | 285 | private static void Run()
|
277 | 286 | {
|
278 |
| - SetupRegistry(); |
279 |
| - SetupDeploymentPath(); |
280 |
| - _markerLock = new FileLock(Path.Combine(_deploymentPath, DeploymentMarkerFilename)); |
281 |
| - _markerLock.Lock(); |
282 |
| - PurgeCachedVersionIfNoLongerExists(out _, out _); |
283 |
| - DetermineLatestVersion(); |
284 |
| - LaunchIfNotRunning(); |
285 |
| - |
286 |
| - while (_isRunning) |
| 287 | + try |
287 | 288 | {
|
288 |
| - if (DetermineIfNewReleaseAvailable(out var r)) |
| 289 | + SetupRegistry(); |
| 290 | + SetupDeploymentPath(); |
| 291 | + _markerLock = new FileLock(Path.Combine(_deploymentPath, DeploymentMarkerFilename)); |
| 292 | + _markerLock.Lock(); |
| 293 | + PurgeCachedVersionIfNoLongerExists(out _, out _); |
| 294 | + DetermineLatestVersion(); |
| 295 | + LaunchIfNotRunning(); |
| 296 | + |
| 297 | + while (_isRunning) |
289 | 298 | {
|
290 |
| - // We have the release, it should have the following files: |
291 |
| - // A .mfdlabs-config-archive file -> This file contains .config files |
292 |
| - // A .Unpacker.ps1 file -> This file runs a 7Zip command that unpacks the contents to the archives into the directory it's in. |
293 |
| - // A .Unpacker.bat file -> This file is a wrapper to the .ps1 file. |
294 |
| - // A .mfdlabs-archive file -> Contains everything else other than the .config files. |
295 |
| - // There should only be 4 assets in the release, and each of these should match the deployment id regex and have any of those extensions at the end. |
296 |
| - if (r.Assets.Count != 4) |
| 299 | + if (DetermineIfNewReleaseAvailable(out var r)) |
297 | 300 | {
|
298 |
| - SkipVersion(r.TagName); |
299 |
| - EventLogLogger.Singleton.Warning("Skipping '{0}' because it had more or less than 4 assets.", r.TagName); |
300 |
| - goto SLEEP; |
301 |
| - } |
302 |
| - |
303 |
| - var regex = $@"{r.TagName}_?(((?i)(net(?i)(standard|coreapp)?)(([0-9]{{1,3}}\.?){{1,2}}))-(?i)(release|debug)(?i)(config(?i)(uration)?)?)?(?i)(\.mfdlabs-(config-)?archive|Unpacker\.(ps1|bat))?"; |
304 |
| - |
305 |
| - foreach (var a in r.Assets) |
306 |
| - { |
307 |
| - if (!a.Name.IsMatch(regex)) |
| 301 | + // We have the release, it should have the following files: |
| 302 | + // A .mfdlabs-config-archive file -> This file contains .config files |
| 303 | + // A .Unpacker.ps1 file -> This file runs a 7Zip command that unpacks the contents to the archives into the directory it's in. |
| 304 | + // A .Unpacker.bat file -> This file is a wrapper to the .ps1 file. |
| 305 | + // A .mfdlabs-archive file -> Contains everything else other than the .config files. |
| 306 | + // There should only be 4 assets in the release, and each of these should match the deployment id regex and have any of those extensions at the end. |
| 307 | + if (r.Assets.Count != 4) |
308 | 308 | {
|
309 | 309 | SkipVersion(r.TagName);
|
310 |
| - EventLogLogger.Singleton.Warning("Skipping '{0}' because the asset '{1}' didn't match '{2}'.", r.TagName, a.Name, regex); |
| 310 | + EventLogLogger.Singleton.Warning("Skipping '{0}' because it had more or less than 4 assets.", r.TagName); |
311 | 311 | goto SLEEP;
|
312 | 312 | }
|
313 |
| - } |
| 313 | + |
| 314 | + var regex = $@"{r.TagName}_?(((?i)(net(?i)(standard|coreapp)?)(([0-9]{{1,3}}\.?){{1,2}}))-(?i)(release|debug)(?i)(config(?i)(uration)?)?)?(?i)(\.mfdlabs-(config-)?archive|Unpacker\.(ps1|bat))?"; |
| 315 | + |
| 316 | + foreach (var a in r.Assets) |
| 317 | + { |
| 318 | + if (!a.Name.IsMatch(regex)) |
| 319 | + { |
| 320 | + SkipVersion(r.TagName); |
| 321 | + EventLogLogger.Singleton.Warning("Skipping '{0}' because the asset '{1}' didn't match '{2}'.", r.TagName, a.Name, regex); |
| 322 | + goto SLEEP; |
| 323 | + } |
| 324 | + } |
314 | 325 |
|
315 | 326 | #if GRID_BOT
|
316 |
| - if (ProcessHelper.GetProcessByName(_primaryDeploymentExecutable.ToLower().Replace(".exe", ""), out _)) |
317 |
| - { |
318 |
| - InvokeMaintenanceCommandOnPreviousExe(r.TagName); |
319 |
| - EventLogLogger.Singleton.Warning("Invoked upgrade message onto bot, sleep for 15 seconds to ensure it receives it."); |
320 |
| - Thread.Sleep(TimeSpan.FromSeconds(15)); |
321 |
| - } |
| 327 | + if (ProcessHelper.GetProcessByName(_primaryDeploymentExecutable.ToLower().Replace(".exe", ""), out _)) |
| 328 | + { |
| 329 | + InvokeMaintenanceCommandOnPreviousExe(r.TagName); |
| 330 | + EventLogLogger.Singleton.Warning("Invoked upgrade message onto bot, sleep for 15 seconds to ensure it receives it."); |
| 331 | + Thread.Sleep(TimeSpan.FromSeconds(15)); |
| 332 | + } |
322 | 333 | #endif
|
323 | 334 |
|
324 |
| - foreach (var a in r.Assets) |
325 |
| - { |
326 |
| - var fqp = Path.Combine(_deploymentPath, a.Name); |
327 |
| - DownloadArtifact(a.Name, a.Url, fqp); |
328 |
| - } |
| 335 | + foreach (var a in r.Assets) |
| 336 | + { |
| 337 | + var fqp = Path.Combine(_deploymentPath, a.Name); |
| 338 | + DownloadArtifact(a.Name, a.Url, fqp); |
| 339 | + } |
329 | 340 |
|
330 |
| - if (!RunUnpacker(r, out var versionDeploymentPath)) |
331 |
| - { |
| 341 | + if (!RunUnpacker(r, out var versionDeploymentPath)) |
| 342 | + { |
| 343 | + CleanupArtifacts(r.Assets.ToArray()); |
| 344 | + try { Directory.Delete(versionDeploymentPath, true); } catch { } |
| 345 | + try { Directory.Delete(Path.Combine(_deploymentPath, r.TagName), true); } catch { } |
| 346 | + SkipVersion(r.TagName); |
| 347 | + goto SLEEP; |
| 348 | + } |
332 | 349 | CleanupArtifacts(r.Assets.ToArray());
|
333 |
| - try { Directory.Delete(versionDeploymentPath, true); } catch { } |
334 |
| - try { Directory.Delete(Path.Combine(_deploymentPath, r.TagName), true); } catch { } |
335 |
| - SkipVersion(r.TagName); |
336 |
| - goto SLEEP; |
337 |
| - } |
338 |
| - CleanupArtifacts(r.Assets.ToArray()); |
339 | 350 |
|
340 |
| - var primaryExe = Path.Combine(versionDeploymentPath, _primaryDeploymentExecutable); |
| 351 | + var primaryExe = Path.Combine(versionDeploymentPath, _primaryDeploymentExecutable); |
341 | 352 |
|
342 |
| - if (!File.Exists(primaryExe)) |
343 |
| - { |
344 |
| - SkipVersion(r.TagName); |
345 |
| - versionDeploymentPath.PollDeletionBlocking(); |
346 |
| - EventLogLogger.Singleton.Error("Unable to deploy version '{0}': The file '{1}' was not found.", r.TagName, primaryExe); |
347 |
| - goto SLEEP; |
348 |
| - } |
| 353 | + if (!File.Exists(primaryExe)) |
| 354 | + { |
| 355 | + SkipVersion(r.TagName); |
| 356 | + versionDeploymentPath.PollDeletionBlocking(); |
| 357 | + EventLogLogger.Singleton.Error("Unable to deploy version '{0}': The file '{1}' was not found.", r.TagName, primaryExe); |
| 358 | + goto SLEEP; |
| 359 | + } |
349 | 360 |
|
350 |
| - KillAllProcessByNameSafe(_primaryDeploymentExecutable); |
351 |
| - StartNewProcess(primaryExe, versionDeploymentPath); |
| 361 | + KillAllProcessByNameSafe(_primaryDeploymentExecutable); |
| 362 | + StartNewProcess(primaryExe, versionDeploymentPath); |
| 363 | + |
| 364 | + _cachedVersion = r.TagName; |
| 365 | + WriteVersionToRegistry(); |
| 366 | + } |
352 | 367 |
|
353 |
| - _cachedVersion = r.TagName; |
354 |
| - WriteVersionToRegistry(); |
| 368 | +SLEEP: |
| 369 | + Thread.Sleep(_pollingInterval); |
355 | 370 | }
|
356 |
| - |
357 |
| - SLEEP: |
358 |
| - Thread.Sleep(_pollingInterval); |
| 371 | + } |
| 372 | + catch (Exception ex) |
| 373 | + { |
| 374 | + EventLogLogger.Singleton.Error(ex); |
| 375 | + Stop(null, null); |
359 | 376 | }
|
360 | 377 | }
|
361 | 378 |
|
@@ -561,8 +578,10 @@ private static void SkipVersion(string version)
|
561 | 578 | _skippedVersions.Add(version);
|
562 | 579 | }
|
563 | 580 |
|
564 |
| - private static bool DetermineIfNewReleaseAvailable(out MinimalRelease latestRelease, string nextPageCursor = null) |
| 581 | + private static bool DetermineIfNewReleaseAvailable(out MinimalRelease latestRelease) |
565 | 582 | {
|
| 583 | + string nextPageCursor = null; |
| 584 | + |
566 | 585 | while (true)
|
567 | 586 | {
|
568 | 587 | latestRelease = null;
|
|
0 commit comments