2

A Generic Timeout Helper

 9 months ago
source link: https://weblogs.asp.net/ricardoperes/a-generic-timeout-helper
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

A Generic Timeout Helper

Monday, October 23, 2023

Another post that hopefully may come in handy to someone!

Some APIs, but not all, notably older ones, allow passing a timeout value for the maximum allowed duration of its completion. What for those that don’t have such parameter? Well, I wrote one helper method to assist in those cases. All it takes is an action and the desired time slot, and it will throw an exception if the action takes longer than it should, leaving it for us to deal with the situation. Here is the code:

public static class RestrainedExtensions
{
     private static void ExecuteRestrainedCommon(Task actionTask, TimeSpan maxDelay)
     {
         var delayTask = Task.Delay(maxDelay);
         var finishedTaskIndex = Task.WaitAny(actionTask, delayTask);
         if (finishedTaskIndex != 0)
         {
             throw new TimeoutException("Action did not finish in the desired time slot.");
         }
     }

public static void ExecuteRestrained<T>(Func<T> func, TimeSpan maxDelay)
     {
         var executionTask = Task.Run(() =>
         {
             func();
         });
         ExecuteRestrainedCommon(executionTask, maxDelay);
     }

public static void ExecuteRestrained(Action action, TimeSpan maxDelay)
     {
         var executionTask = Task.Run(() =>
         {
             action();
         });
         ExecuteRestrainedCommon(executionTask, maxDelay);
     } }

As you can see, the RestrainedExtensions class offers two overloads of the ExecuteRestrained method, this is to make our lives easier when we want to execute some method that has a return type or otherwise. Essentially what we do is, we create two tasks, one which just executes a delay and the other which tries to execute our action, and we wait for the first to complete; if this wasn’t our action, then we throw an TimeoutException.

An alternate implementation of ExecuteRestrained, making use of the new WaitAsync method, could be:

private static void ExecuteRestrainedCommon(Task actionTask, TimeSpan maxDelay)
{
actionTask.WaitAsync(maxDelay).ConfigureAwait(false).GetAwaiter().GetResult();
}

If the action to be awaited does not run in the desired time slot, WaitAsync throws a TimeoutException.

Here’s a simple usage:

RestrainedExtensions.ExecuteRestrained(Console.ReadLine, TimeSpan.FromSeconds(3));

As you can imagine, this gives the user 3 seconds to enter something at the console before throwing an exception. Simple enough, probably has something to it, but surely can be used in most cases! As always, feel free to share your thoughts! Winking smile


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK