Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

timing out a method call [duplicate]

The original method calling is like:

public string AskAPI(string uri)
{
    return api.Query(uri);
}

where the api is simply a imported dll reference.

Right now I want to add a time out feature to the AskAPI method, so that if the api.Query takes longer than, say 30 seconds, AskAPI will throw an exception.

Seems I won't be able to get it working. Can anyone share their thoughts about this?

Thanks!

like image 723
jamesdeath123 Avatar asked Aug 29 '13 02:08

jamesdeath123


1 Answers

You could use Tasks to do this, here's an example:

public string AskAPI(string uri, int millis)
{
    using (var task = new Task<string>(() => api.Query(uri)))
    {
        task.Start();
        task.Wait(millis);
        if (!task.IsCompleted) throw new TimeoutException();
        return task.Result;
    }   
}

Thanks to Guillaume for suggesting to use a TimeoutException.

But as Jim Mischel points out, this won't stop the task from completing, in which case it'd be best if you could modify the API you're calling because then you could make full use of the CancellationToken class which was made for this kind of thing.

Other than that, the only other quick solution I can think of (which may be inadvisable) would be to wrap the method (or combine it) with something like this:

public T Await<T>(Func<T> fun, int millis)
{
    using (var cancel = new CancellationTokenSource(millis))
    using (var task = new Task<T>(() =>
    {
        T result = default(T);
        var thread = new Thread(() => result = fun());
        thread.Start();
        while (!cancel.Token.IsCancellationRequested && thread.IsAlive) ; // Wait for a sign from above
        thread.Abort();
        cancel.Token.ThrowIfCancellationRequested();
        return result;
    }, cancel.Token))
    {
        task.Start();
        task.Wait(millis);
        cancel.Cancel();
        if (!task.IsCompleted) throw new TimeoutException();
        return task.Result;
    }
}

And then call it using:

Await(() => AskAPI("http://some.uri"), 30000);
like image 151
sgbj Avatar answered Oct 26 '22 21:10

sgbj