0

I have an async operation that takes in an List of Airline as parameter and returns some data, and I have a list of Airlines for which I want to get data for.

However, if I can't get the data for all those Airlines after some predefined amount of time, I want to stop waiting and return something else to the user.

public async Task Run()
{
    var watch = System.Diagnostics.Stopwatch.StartNew();
    await RunAirline();
    watch.Stop();
    Console.WriteLine($"Total Execution Time: {watch.ElapsedMilliseconds + Environment.NewLine}");
    //return $"Total Execution Time: {watch.ElapsedMilliseconds + Environment.NewLine}";
    //Console.ReadLine();
}

private static async Task RunAirline()
{
    try
    {
        List<string> AirlineList = GetAirLineCodes();
        List<Task<WebsiteDataModel.WebsiteDataModel>> taskList = new List<Task<WebsiteDataModel.WebsiteDataModel>>();
        foreach (string AirlineCode in AirlineList)
        {
            taskList.Add(Task.Run(() => CallindividualAirline(AirlineCode)));

        }
        var result = await Task.WhenAll(taskList);
        foreach (WebsiteDataModel.WebsiteDataModel model in result)
        {
            Display(model);
        }
    }
    catch (Exception Ex)
    {
        Console.WriteLine(Ex.Message.ToString());
    }
}

private static List<string> GetAirLineCodes()
{
    return new List<string>() 
    {
        "A",
        "B",
        "C"
    };
}

private static void Display(WebsiteDataModel.WebsiteDataModel result)
{
    Console.WriteLine($"Website Content as {result.DataContent} , Website Name as :  {result.WebsiteName} Status as : {result.Status} , Content length as : {result.WebsiteData.Length} ----- Error as  : {result.error.FaultException.ToString()}." + Environment.NewLine);
}

private static WebsiteDataModel.WebsiteDataModel CallindividualAirline(string AirlineCode)
{
    WebsiteDataModel.WebsiteDataModel LobjWebsiteDataModel = new WebsiteDataModel.WebsiteDataModel();
    WebsiteDataModel.ErrorData LobjErrorData = new WebsiteDataModel.ErrorData();
    try
    {
        switch (AirlineCode)
        {
            // calling Airline API...........
            case "A":
                ClsAirOne LobjAirOne = new ClsAirOne();
                LobjWebsiteDataModel = LobjAirOne.GetAirDataData("https://book.xxxxx.com");
                return LobjWebsiteDataModel;
            case "B":
                ClsAirTwo LobjAirTwo = new ClsAirTwo();
                LobjWebsiteDataModel = LobjAirTwo.GetAirData("https://book.xxxxx.in");
                return LobjWebsiteDataModel;
            case "C":
                ClsAirThree LobjAirThree = new ClsAirThree();
                LobjWebsiteDataModel = LobjAirThree.GetAirData("https://xxxxx.in/");
                return LobjWebsiteDataModel;

            default:
                return LobjWebsiteDataModel;
        }


    }
    catch (Exception Ex)
    {

        LobjWebsiteDataModel.Status = "0";
        LobjWebsiteDataModel.WebsiteData = "";
        LobjErrorData.FaultException = "ERR-01" + Ex.Message.ToString();
        LobjWebsiteDataModel.error = LobjErrorData;
        return LobjWebsiteDataModel;
    }
}
jamesnet214
  • 1,044
  • 13
  • 21
  • Does it help? https://stackoverflow.com/questions/9846615/async-task-whenall-with-timeout – feihoa May 15 '21 at 10:38
  • 2
    [`CancellationTokenSource`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource?view=netcore-3.1) – aepot May 15 '21 at 11:08
  • @feihoa..........Combinations of these two snippets achieves my output.................await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(timeout));var completedResults = tasks .Where(t => t.Status == TaskStatus.RanToCompletion) .Select(t => t.Result) .ToList(); – VIGNESH WARAN May 15 '21 at 16:59
  • var result = await Task.WhenAny(Task.WhenAll(taskList), Task.Delay(TimeSpan.FromSeconds(Convert.ToDouble(ConfigurationManager.AppSettings["TimeOutInSeconds"])))); Whether this snippet cancels all tasks which are not completed within a particular time – VIGNESH WARAN Aug 05 '21 at 04:43

1 Answers1

4

The best way to do this is to cancel each operation passed to the Task.WhenAll. You can create a cancellation token source with a timeout, and then pass its CancellationToken down to the methods that actually do the I/O.

E.g.:

public async Task Run()
{
  ...
  using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
  await RunAirline(cts.Token);
  ...
}

private static async Task RunAirline(CancellationToken cancellationToken)
{
  ...
  foreach (string AirlineCode in AirlineList)
    taskList.Add(Task.Run(() => CallindividualAirline(AirlineCode, cancellationToken)));
  ...
}

private static WebsiteDataModel.WebsiteDataModel CallindividualAirline(string AirlineCode, CancellationToken cancellationToken)
{
  ...
  ClsAirOne LobjAirOne = new ClsAirOne();
  LobjWebsiteDataModel = LobjAirOne.GetAirDataData("https://book.xxxxx.com", cancellationToken);
  ...
  ClsAirTwo LobjAirTwo = new ClsAirTwo();
  LobjWebsiteDataModel = LobjAirTwo.GetAirData("https://book.xxxxx.in", cancellationToken);
  ...
}
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810