Skip to content

Instantly share code, notes, and snippets.

@szalapski
Created January 26, 2021 13:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save szalapski/f46e4ea2215e4f7e4b454623af27d86d to your computer and use it in GitHub Desktop.
Save szalapski/f46e4ea2215e4f7e4b454623af27d86d to your computer and use it in GitHub Desktop.
public static class GeneralExtensions {
/// <summary>
/// Throws an exception if the task fails to complete within a number of milliseconds from when invoked.
/// </summary>
/// <param name="task">The task on which to enforce the timeout</param>
/// <param name="milliseconds">The timeout in milliseconds.</param>
/// <param name="operationDescription">The text description that should appear in the timeout exception message.
/// Useful for pinpointing the timed-out operation.</param>
/// <returns>The completed task, if the task completed in time.</returns>
/// <exception cref="TimeoutException">Thrown when the timeout is reached before the task is completed.</exception>
/// <exception cref="ArgumentNullException">The task is null.</exception>
/// <remarks>Does not cancel the task. Does not guarantee very precise timing. Does not consider the
/// running time of the task before this call was invoked, which may be considerable
/// (remember, most asynchronous Tasks in .NET start running immediately on creation).</remarks>
/// <example><code>await connection.QueryAsync(...).WithTimeout(2000);</code></example>
public static async Task WithTimeout(this Task task, int milliseconds, string? operationDescription = null)
{
// This was necessitated by https://github.com/StackExchange/Dapper/issues/927, but it maybe useful elsewhere too
if (task is null) throw new ArgumentNullException(nameof(task));
await Task.WhenAny(task, Task.Delay(milliseconds));
if (!task.IsCompleted)
{
string message = $"Operation {operationDescription ?? ""} timed out after {(decimal)milliseconds / 1000.0m} seconds.";
throw new TimeoutException(message);
}
}
/// <summary>
/// Throws an exception if the task fails to complete within a number of milliseconds from when invoked.
/// </summary>
/// <param name="task">The task on which to enforce the timeout</param>
/// <param name="milliseconds">The timeout in milliseconds.</param>
/// <param name="operationDescription">The text description that should appear in the timeout exception message.
/// Useful for pinpointing the timed-out operation.</param>
/// <returns>The completed task with a result, if the task completed in time.</returns>
/// <exception cref="TimeoutException">Thrown when the timeout is reached before the task is completed.</exception>
/// <exception cref="ArgumentNullException">The task is null.</exception>
/// <remarks>Does not cancel the task. Does not guarantee very precise timing. Does not consider the
/// running time of the task before this call was invoked, which may be considerable
/// (remember, most asynchronous Tasks in .NET start running immediately on creation).</remarks>
/// <example><code>int count = await connection.QueryAsync(...).WithTimeout(2000);</code></example>
public static async Task<T> WithTimeout<T>(this Task<T> task, int milliseconds, string? operationDescription = null)
{
await (task as Task).WithTimeout(milliseconds, operationDescription);
return await task;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment