Make long running tasks cancellable

This commit is contained in:
Jackson Schuster 2024-02-28 10:06:38 -08:00
parent b6fba7eb7c
commit 9ffe5c200d
3 changed files with 26 additions and 9 deletions

View file

@ -11,10 +11,10 @@ using System.Threading.Tasks;
public abstract class Archive : IDisposable public abstract class Archive : IDisposable
{ {
public static async Task<Archive> Create(string path) public static async Task<Archive> Create(string path, CancellationToken cancellationToken = default)
{ {
if (path.EndsWith(".tar.gz")) if (path.EndsWith(".tar.gz"))
return await TarArchive.Create(path); return await TarArchive.Create(path, cancellationToken);
else if (path.EndsWith(".zip")) else if (path.EndsWith(".zip"))
return ZipFileArchive.Create(path); return ZipFileArchive.Create(path);
else else
@ -40,7 +40,7 @@ public abstract class Archive : IDisposable
_extractedFolder = extractedFolder; _extractedFolder = extractedFolder;
} }
public static async Task<TarArchive> Create(string path, CancellationToken cancellationToken = default) public static new async Task<TarArchive> Create(string path, CancellationToken cancellationToken = default)
{ {
var tmpFolder = Directory.CreateTempSubdirectory(nameof(FindArchiveDiffs)); var tmpFolder = Directory.CreateTempSubdirectory(nameof(FindArchiveDiffs));
using (var gzStream = File.OpenRead (path)) using (var gzStream = File.OpenRead (path))
@ -90,7 +90,7 @@ public abstract class Archive : IDisposable
_archive = archive; _archive = archive;
} }
public static new ZipFileArchive Create(string path) public static ZipFileArchive Create(string path)
{ {
return new ZipFileArchive(new ZipArchive(File.OpenRead(path))); return new ZipFileArchive(new ZipArchive(File.OpenRead(path)));
} }

View file

@ -5,12 +5,13 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Build.Framework; using Microsoft.Build.Framework;
using Microsoft.Build.Utilities; using Microsoft.Build.Utilities;
using Task = System.Threading.Tasks.Task; using Task = System.Threading.Tasks.Task;
public class FindArchiveDiffs : Microsoft.Build.Utilities.Task public class FindArchiveDiffs : Microsoft.Build.Utilities.Task, ICancelableTask
{ {
public class ArchiveItem public class ArchiveItem
{ {
@ -26,6 +27,13 @@ public class FindArchiveDiffs : Microsoft.Build.Utilities.Task
[Output] [Output]
public ITaskItem[] ContentDifferences { get; set; } = []; public ITaskItem[] ContentDifferences { get; set; } = [];
private CancellationTokenSource _cancellationTokenSource = new();
private CancellationToken cancellationToken => _cancellationTokenSource.Token;
public void Cancel()
{
_cancellationTokenSource.Cancel();
}
public override bool Execute() public override bool Execute()
{ {
return Task.Run(ExecuteAsync).Result; return Task.Run(ExecuteAsync).Result;

View file

@ -4,10 +4,11 @@
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Build.Framework; using Microsoft.Build.Framework;
public class GetClosestOfficialSdk : Microsoft.Build.Utilities.Task public class GetClosestOfficialSdk : Microsoft.Build.Utilities.Task, ICancelableTask
{ {
[Required] [Required]
public required string BuiltSdkPath { get; init; } public required string BuiltSdkPath { get; init; }
@ -20,8 +21,16 @@ public class GetClosestOfficialSdk : Microsoft.Build.Utilities.Task
return Task.Run(ExecuteAsync).Result; return Task.Run(ExecuteAsync).Result;
} }
private CancellationTokenSource _cancellationTokenSource = new();
private CancellationToken cancellationToken => _cancellationTokenSource.Token;
public void Cancel()
{
_cancellationTokenSource.Cancel();
}
public async Task<bool> ExecuteAsync() public async Task<bool> ExecuteAsync()
{ {
cancellationToken.ThrowIfCancellationRequested();
var (versionString, rid, extension) = Archive.GetInfoFromArchivePath(BuiltSdkPath); var (versionString, rid, extension) = Archive.GetInfoFromArchivePath(BuiltSdkPath);
string downloadUrl = GetLatestOfficialSdkUrl(versionString, rid, extension); string downloadUrl = GetLatestOfficialSdkUrl(versionString, rid, extension);
@ -32,14 +41,14 @@ public class GetClosestOfficialSdk : Microsoft.Build.Utilities.Task
AllowAutoRedirect = false AllowAutoRedirect = false
}; };
var client = new HttpClient(handler); var client = new HttpClient(handler);
var redirectResponse = await client.GetAsync(downloadUrl); var redirectResponse = await client.GetAsync(downloadUrl, cancellationToken);
// aka.ms returns a 301 for valid redirects and a 302 to Bing for invalid URLs // aka.ms returns a 301 for valid redirects and a 302 to Bing for invalid URLs
if (redirectResponse.StatusCode != HttpStatusCode.Moved) if (redirectResponse.StatusCode != HttpStatusCode.Moved)
{ {
Log.LogMessage(MessageImportance.High, $"Failed to download '{downloadUrl}': invalid aka.ms URL"); Log.LogMessage(MessageImportance.High, $"Failed to download '{downloadUrl}': invalid aka.ms URL");
return true; return true;
} }
var packageResponse = await client.GetAsync(redirectResponse.Headers.Location!); var packageResponse = await client.GetAsync(redirectResponse.Headers.Location!, cancellationToken);
var packageUriPath = packageResponse.RequestMessage!.RequestUri!.LocalPath; var packageUriPath = packageResponse.RequestMessage!.RequestUri!.LocalPath;
string downloadedVersion = PathWithVersions.GetVersionInPath(packageUriPath).ToString(); string downloadedVersion = PathWithVersions.GetVersionInPath(packageUriPath).ToString();
@ -48,7 +57,7 @@ public class GetClosestOfficialSdk : Microsoft.Build.Utilities.Task
Log.LogMessage($"Copying {packageUriPath} to {ClosestOfficialSdkPath}"); Log.LogMessage($"Copying {packageUriPath} to {ClosestOfficialSdkPath}");
using (var file = File.Create(ClosestOfficialSdkPath)) using (var file = File.Create(ClosestOfficialSdkPath))
{ {
await packageResponse.Content.CopyToAsync(file); await packageResponse.Content.CopyToAsync(file, cancellationToken);
} }
return true; return true;