In this tip, you will see a couple of examples for how to add time out for functions that may just hang.
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.
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:
public static T Execute(Func<t> function, TimeSpan timeout, Func<t> onTimeout)
Task<t> task = Task.Run(function);
Instead of returning a default value, you may also throw an exception in the
Unfortunately, in C#
Function is a concept different from
Action. Hence, I added an overload for
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:
Func<bool> theFunction = DoSomething;
TimeSpan timeout = TimeSpan.FromSeconds(3);
Func<bool> onTimeout = () =>
and then execute it:
bool success = TimedExecution<bool>.Execute(theFunction, timeout, onTimeout);
but you could write it more concisely, too:
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:
Func<bool> onTimeout = () =>
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.
- 18th March, 2020: First version
- 20th March, 2020: Added more info on the background, and the limitations for the use of the code