Click here to Skip to main content
15,880,405 members
Articles / Programming Languages / C#
Tip/Trick

Timeout for Functions

Rate me:
Please Sign up or sign in to vote.
4.76/5 (11 votes)
18 Mar 2020CPOL2 min read 30.4K   349   5   8
A short utility class implementing a timeout for functions
In this tip, you will see a couple of examples for how to add time out for functions that may just hang.

Introduction

When communicating with external services, some functions may just "hang": attempting to establish a TCP connection when the network or the other device is down takes 21s till you get a failure message. When the device is in your local network, you can normally be sure to get the connection within less than a second or not at all, and there is no need to waste so much time.

So it’s appropriate to add some time out. There are a couple of examples how to achieve that, but they require the repetition of (short) boiler plate code.

Thanks to generics and functional features of C# that can be encapsulated.

The Code

We need three items:

  • A function to execute
  • The timeout for that function
  • A function to execute in case of the timeout

The first step is to start a Task with the function. Task has a Wait(TimeSpan timeout) function, which returns true if the task completed in time. Here, we can return the Result property of the task. Otherwise, we execute the onTimeout function and return its result.

The code is simple:

C#
public static T Execute(Func<t> function, TimeSpan timeout, Func<t> onTimeout)
{
    Task<t> task = Task.Run(function);
    if (task.Wait(timeout))
    {
        // the function returned in time
        return task.Result;
    }
    else
    {
        // the function takes longer than the timeout
        return onTimeout();
    }
}

Instead of returning a default value, you may also throw an exception in the onTimeout function.

Unfortunately, in C# Function is a concept different from Action. Hence, I added an overload for Action, too.

Limitation: Cancellation

As you may find out, the original function stays alive after timeout - it continues to hang till it has run to completion. With the example of the TCP connection, that does not matter. If it consumes valuable ressources like CPU, that's bad.

Task.Run has an overload which takes a CancellationToken. But that does not help when the original function does not support cancellation (it must check the IsCancellationRequested property of the CancellationToken). If it does, you do not need this code, just supply a new CancellationTokenSource(timeout).Token to it.

This is a limitation for the use of this code.

Using the Code

Let’s add some examples.
I created a function which sleeps for a day before returning true – that corresponds to the „hanging“ function.

In the default value example, I set up 3 variables for the 3 items:

C#
Func<bool> theFunction = DoSomething;
TimeSpan timeout = TimeSpan.FromSeconds(3);
Func<bool> onTimeout = () =>
{
    // Log the timeout
    // Logger.Log("A timeout occurred");
    // then return a default value
    return false;
};

and then execute it:

C#
bool success = TimedExecution<bool>.Execute(theFunction, timeout, onTimeout);

but you could write it more concisely, too:

C#
bool success = TimedExecution<bool>.Execute(DoSomething, TimeSpan.FromSeconds(3), () => false);

The exceptional example works analogous. Here, the onTimeout function is set up to throw an exception:

C#
Func<bool> onTimeout = () =>
{
    // in this scenario, we want to receive an exception
    throw new TimeoutException("The function was to slow.");
};

In the example code, I added [TestMethod] attributes, which allow for executing and debugging these example functions from Visual Studio.

Points of Interest

You can now adjust the functions to your typical needs. Example, you might log the timeout directly in the Execute function. Or you only need a function which always throws a TimeoutException in case of timeout. Or whatever fits your requirements best. Now it's centralized and you can change the behavior at a single point.

History

  • 18th March, 2020: First version
  • 20th March, 2020: Added more info on the background, and the limitations for the use of the code

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionConversion to VB.net Pin
Padanian19-Mar-20 3:27
Padanian19-Mar-20 3:27 
QuestionTimed Out Method Runs to Completion. Pin
George Swan18-Mar-20 20:46
mveGeorge Swan18-Mar-20 20:46 
AnswerRe: Timed Out Method Runs to Completion. Pin
57thStIncident19-Mar-20 10:23
57thStIncident19-Mar-20 10:23 
GeneralRe: Timed Out Method Runs to Completion. Pin
George Swan19-Mar-20 22:08
mveGeorge Swan19-Mar-20 22:08 

My preferred way to timeout a method is to use a CancellationToken within the method and to observe its state. Something like this

C#
static async Task Main()
{
    var cts = new CancellationTokenSource();
    //'CancelAfter' may throw unhandled exception in debug mode
    //depending upon exception settings
    cts.CancelAfter(TimeSpan.FromSeconds(3));
    var token = cts.Token;
    var task = Task.Run(() =>
    {
        for (int i = 0; i < 10; i++)
        {
            token.ThrowIfCancellationRequested();
            Thread.Sleep(TimeSpan.FromSeconds(1));
            Console.WriteLine(i);
        }

        return true;
    }, token);
    try
    {
        bool result = await task;
        Console.WriteLine($"Completed successfully the result was {result}");

    }
    catch (OperationCanceledException ex)
    {
        Console.WriteLine(ex.Message);
    }

    Console.ReadLine();
}
It seems to me that the main advantage of this approach is a good separation of concerns between the threadpool thread and the main thread with the added bonus of correctly closing the threadpool thread and ensuring its early return to the pool.



modified 20-Mar-20 4:37am.

AnswerRe: Timed Out Method Runs to Completion. Pin
Bernhard Hiller19-Mar-20 22:54
Bernhard Hiller19-Mar-20 22:54 
QuestionNot sure ... Pin
User 1106097918-Mar-20 12:02
User 1106097918-Mar-20 12:02 
AnswerRe: Not sure ... Pin
Bernhard Hiller19-Mar-20 22:51
Bernhard Hiller19-Mar-20 22:51 
GeneralRe: Not sure ... Pin
User 1106097919-Mar-20 23:21
User 1106097919-Mar-20 23:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.