4

I have a console app, where I need to access some url 200 times, wait for all of the requests to return and work on the 200 results.

I did it like that, in parallel:

var classNameTasks = Enumerable.Range(1, 200).Select(i => webApi.getSplittedClassName()).ToArray();
string[][] splittedClassNames = await Task.WhenAll(classNameTasks);
if (splittedClassNames[0] == null)
    result = new TextResult("Error accessing the web");

getSplittedClassName returns a string[], if the internet is off it will return null.

Now, as you can see, after the completion of all the tasks, I do an if to check the content, if its null -> internet issues.

The problem here is that I need to wait for the whole 200 requests to return before I can check the content.

I am looking for a way to right away detect a scenario where there is no internet, and I return null, without having to wait for the 200 requests.

svick
  • 236,525
  • 50
  • 385
  • 514
Ofek Agmon
  • 5,040
  • 14
  • 57
  • 101
  • 1
    Do you expect the Internet to fall down *during the task execution?* Or can you check for internet just prior to starting the tasks? – Robert Harvey Apr 30 '16 at 19:01
  • Strongly related: http://stackoverflow.com/q/27238232 – Robert Harvey Apr 30 '16 at 19:03
  • umm, I guess it could be both options. I am just trying to catch all the errors that can happen – Ofek Agmon Apr 30 '16 at 19:03
  • Do you want to wait on *all* tasks to complete before beginning work on them, or can you work on tasks as they are completed? – Robert Harvey Apr 30 '16 at 19:05
  • I could maybe do it without waiting for all the tasks, that will require changing my code. how would you go about it? – Ofek Agmon Apr 30 '16 at 19:07
  • I would probably use continuations. https://msdn.microsoft.com/en-us/library/dd270696(v=vs.110).aspx – Robert Harvey Apr 30 '16 at 19:12
  • [Process Tasks By Completion](http://sergeyteplyakov.blogspot.ru/2015/06/process-tasks-by-completion.html) (in Russian) and [sources on github](//github.com/SergeyTeplyakov/TplTipsAndTricks) – Qwertiy May 01 '16 at 10:20

1 Answers1

2

To do this you need

  1. A CancellationTokenSource to signal that the job is done.
  2. The WhenAll method from Tortuga.Anchor

    static async Task Test()
    {
        TextResult result;
    
        var cts = new CancellationTokenSource();
    
        var classNameTasks = Enumerable.Range(1, 200).Select(i => getSplittedClassName(cts)).ToArray();
        await classNameTasks.WhenAll(cts.Token);
        if (cts.IsCancellationRequested)
            result = new TextResult("Error accessing the web");
    
        string[][] splittedClassNames = classNameTasks.Select(t => t.Result).ToArray();
    
    }
    
    private static async Task<string[]> getSplittedClassName(CancellationTokenSource cts)
    {
        try
        {
            //real code goes here
            await Task.Delay(1000, cts.Token); //the token would be passed to the real web method
            return new string[0];
        }
        catch
        {
            cts.Cancel(); //stop trying
            return null;
        }
    }
    
Jonathan Allen
  • 68,373
  • 70
  • 259
  • 447
  • this is the right approach, although it would have been more correct (or - aligned with the OP) if instead of try/catch block the token is canceled in case of null value response (rather than exception) – shay__ May 01 '16 at 06:13
  • I fixed the return to be null, but I think there is still a bug. If I'm not mistaken, `await classNameTasks.WhenAll(cts.Token);` will throw an `AggregateException` containing a `OperationCanceledException`; – Jonathan Allen May 01 '16 at 06:42