Почему моя задача не отменяется?

Я запускаю процесс, который периодически скручивается в список URL-адресов, чтобы проверить производительность этих сайтов. Моя основная программа - это цикл do ... sleep ... while, который вызывает функцию runTest () каждые N секунд, с прерыванием клавиатуры, чтобы убить его. По сравнению с основами мой код выглядит следующим образом:

public void runTest()
{
   if(isRunning)
   {
      return; //Plus some logging that one or more of the tests hasn't completed
   }
   try {
       isRunning = true;
       Curl.GlobalInit((int)CURLinitFlag.CURL_GLOBAL_ALL);
       CancellationTokenSource cts = new CancellationTokenSource(httpTimeoutValueMs * 2);
       foreach (var url in urls)
            taskList.Add(doAsyncCurls(url, cts))
       List<CurlResults> listOfResults = Task.WhenAll(taskList.Select(x => x)).Result.ToList();
       taskList.Clear();
  }
  catch {/*Some exception handling code*/}
  finally { 
    isRunning = false; 
    Curl.GlobalCleanup();
  }
}
private static async Task<CurlResults> doAsyncCurls(string url, CancellationTokenSource cts)
{
    try
    {
      /*Initiate a Curl using libCurl*/
      Easy easy = new Easy();
      easy.SetOpt(CURLoption.CURLOPT_URL, url);
      easy.SetOpt(CURLoption.CURLOPT_DNS_CACHE_TIMEOUT, 0); //Disables DNS cache
      easy.SetOpt(CURLoption.CURLOPT_CONNECTTIMEOUT, httpTimeoutValueMs / 1000); //20sec timeout

      Task t = new Task(() => easy.Perform(), cts.Token);
      t.Start();
      await t;
      return new CurlResults(/*valid results parameters*/);
    } 
    catch (TaskCanceledException)
    { /*Cancellation token invoked*/
        return new CurlResults(/*Invalid results parameters*/);
    }
    catch (Exception e)
    { /*Other exception handling*/ 
        return new CurlResults(/*Invalid results parameters*/);
    }

Функция «doAsyncCurl» делает то, что говорит на жестяной коробке, устанавливая значение тайм-аута http, равное половине значения токена отмены, так что HTTP-запрос должен испариться до вызова токена отмены и генерировать отрицательный результат. Я добавил токен отмены, чтобы попытаться решить мою проблему, как показано ниже.

Я оставляю это запущенным целую вечность - для начала все работает хорошо, но в конце концов (сотни, если не больше итераций через периодический вызов runTest ()) кажется, что одна из задач застревает и токен отмены не вызывается, и процесс тестирования завитка эффективно застрял.

Помимо определения того, какие URL-адреса являются проблематичными (и все они действительны), что можно сделать для диагностики неисправности? Или я с самого начала построил свои параллельные кудри совершенно неправильно? (Я ценю, что могу создать новые Curls для URL-адресов, которые закончили с предыдущего раунда, и оставить зависший один на один, вместо того, чтобы ждать, пока все они закончат, прежде чем начать новую партию, но меня не беспокоит эта эффективность усиление).