5

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!

Mathieu Guindon
  • 69,817
  • 8
  • 107
  • 235
jamesdeath123
  • 4,268
  • 11
  • 52
  • 93
  • You'd have to be able to modify `api.Query` to add timeout functionality. As you've provided no information about what it is, it's impossible to tell you how to do so. (There's no way to time out around the call, as you have no way to interrupt it based on what you posted here.) – Ken White Aug 29 '13 at 02:24
  • @KenWhite api.Query is not in my control either. You mean without editing it, I cannot time out AskAPI method? – jamesdeath123 Aug 29 '13 at 02:26
  • I can't answer that, because you've provided exactly three lines of code (`{}` doesn't count) totally out of context, with absolutely no other information. Based on precisely what you've posted, the answer would be "No, you cannot". – Ken White Aug 29 '13 at 02:35

1 Answers1

8

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);
sgbj
  • 2,264
  • 17
  • 14