@@ -9,21 +9,32 @@ namespace PuppeteerSharp.Helpers
99 /// </summary>
1010 public static class TaskHelper
1111 {
12+ private static readonly Func < TimeSpan , Exception > DefaultExceptionFactory =
13+ timeout => new TimeoutException ( $ "Timeout Exceeded: { timeout . TotalMilliseconds } ms exceeded") ;
14+
1215 //Recipe from https://blogs.msdn.microsoft.com/pfxteam/2012/10/05/how-do-i-cancel-non-cancelable-async-operations/
1316 /// <summary>
1417 /// Cancels the <paramref name="task"/> after <paramref name="milliseconds"/> milliseconds
1518 /// </summary>
1619 /// <returns>The task result.</returns>
1720 /// <param name="task">Task to wait for.</param>
1821 /// <param name="milliseconds">Milliseconds timeout.</param>
19- /// <param name="exceptionToThrow">Optional exception to be thrown.</param>
20- public static Task WithTimeout (
21- this Task task ,
22- int milliseconds = 1_000 ,
23- Exception exceptionToThrow = null )
22+ /// <param name="exceptionFactory">Optional timeout exception factory.</param>
23+ public static Task WithTimeout ( this Task task , int milliseconds = 1_000 , Func < TimeSpan , Exception > exceptionFactory = null )
24+ => WithTimeout ( task , TimeSpan . FromMilliseconds ( milliseconds ) , exceptionFactory ) ;
25+
26+ //Recipe from https://blogs.msdn.microsoft.com/pfxteam/2012/10/05/how-do-i-cancel-non-cancelable-async-operations/
27+ /// <summary>
28+ /// Cancels the <paramref name="task"/> after a given <paramref name="timeout"/> period
29+ /// </summary>
30+ /// <returns>The task result.</returns>
31+ /// <param name="task">Task to wait for.</param>
32+ /// <param name="timeout">The timeout period.</param>
33+ /// <param name="exceptionFactory">Optional timeout exception factory.</param>
34+ public static Task WithTimeout ( this Task task , TimeSpan timeout , Func < TimeSpan , Exception > exceptionFactory = null )
2435 => task . WithTimeout (
25- ( ) => throw exceptionToThrow ?? new TimeoutException ( $ "Timeout Exceeded: { milliseconds } ms exceeded" ) ,
26- milliseconds ) ;
36+ ( ) => throw ( exceptionFactory ?? DefaultExceptionFactory ) ( timeout ) ,
37+ timeout ) ;
2738
2839 //Recipe from https://blogs.msdn.microsoft.com/pfxteam/2012/10/05/how-do-i-cancel-non-cancelable-async-operations/
2940 /// <summary>
@@ -33,16 +44,23 @@ public static Task WithTimeout(
3344 /// <param name="task">Task to wait for.</param>
3445 /// <param name="timeoutAction">Action to be executed on Timeout.</param>
3546 /// <param name="milliseconds">Milliseconds timeout.</param>
36- public static async Task WithTimeout (
37- this Task task ,
38- Func < Task > timeoutAction ,
39- int milliseconds = 1_000 )
47+ public static Task WithTimeout ( this Task task , Func < Task > timeoutAction , int milliseconds = 1_000 )
48+ => WithTimeout ( task , timeoutAction , TimeSpan . FromMilliseconds ( milliseconds ) ) ;
49+
50+ //Recipe from https://blogs.msdn.microsoft.com/pfxteam/2012/10/05/how-do-i-cancel-non-cancelable-async-operations/
51+ /// <summary>
52+ /// Cancels the <paramref name="task"/> after a given <paramref name="timeout"/> period
53+ /// </summary>
54+ /// <returns>The task result.</returns>
55+ /// <param name="task">Task to wait for.</param>
56+ /// <param name="timeoutAction">Action to be executed on Timeout.</param>
57+ /// <param name="timeout">The timeout period.</param>
58+ public static async Task WithTimeout ( this Task task , Func < Task > timeoutAction , TimeSpan timeout )
4059 {
41- if ( await TimeoutTask ( task , milliseconds ) )
60+ if ( await TimeoutTask ( task , timeout ) )
4261 {
4362 await timeoutAction ( ) ;
4463 }
45-
4664 await task ;
4765 }
4866
@@ -54,12 +72,20 @@ public static async Task WithTimeout(
5472 /// <param name="task">Task to wait for.</param>
5573 /// <param name="timeoutAction">Action to be executed on Timeout.</param>
5674 /// <param name="milliseconds">Milliseconds timeout.</param>
57- public static async Task < T > WithTimeout < T > (
58- this Task < T > task ,
59- Action timeoutAction ,
60- int milliseconds = 1_000 )
75+ public static Task < T > WithTimeout < T > ( this Task < T > task , Action timeoutAction , int milliseconds = 1_000 )
76+ => WithTimeout ( task , timeoutAction , TimeSpan . FromMilliseconds ( milliseconds ) ) ;
77+
78+ //Recipe from https://blogs.msdn.microsoft.com/pfxteam/2012/10/05/how-do-i-cancel-non-cancelable-async-operations/
79+ /// <summary>
80+ /// Cancels the <paramref name="task"/> after a given <paramref name="timeout"/> period
81+ /// </summary>
82+ /// <returns>The task result.</returns>
83+ /// <param name="task">Task to wait for.</param>
84+ /// <param name="timeoutAction">Action to be executed on Timeout.</param>
85+ /// <param name="timeout">The timeout period.</param>
86+ public static async Task < T > WithTimeout < T > ( this Task < T > task , Action timeoutAction , TimeSpan timeout )
6187 {
62- if ( await TimeoutTask ( task , milliseconds ) )
88+ if ( await TimeoutTask ( task , timeout ) )
6389 {
6490 timeoutAction ( ) ;
6591 return default ;
@@ -75,38 +101,46 @@ public static async Task<T> WithTimeout<T>(
75101 /// <returns>The task result.</returns>
76102 /// <param name="task">Task to wait for.</param>
77103 /// <param name="milliseconds">Milliseconds timeout.</param>
78- /// <param name="exceptionToThrow">Optional exception to be thrown.</param>
104+ /// <param name="exceptionFactory">Optional timeout exception factory.</param>
105+ /// <typeparam name="T">Task return type.</typeparam>
106+ public static Task < T > WithTimeout < T > ( this Task < T > task , int milliseconds = 1_000 , Func < TimeSpan , Exception > exceptionFactory = null )
107+ => WithTimeout ( task , TimeSpan . FromMilliseconds ( milliseconds ) , exceptionFactory ) ;
108+
109+ //Recipe from https://blogs.msdn.microsoft.com/pfxteam/2012/10/05/how-do-i-cancel-non-cancelable-async-operations/
110+ /// <summary>
111+ /// Cancels the <paramref name="task"/> after a given <paramref name="timeout"/> period
112+ /// </summary>
113+ /// <returns>The task result.</returns>
114+ /// <param name="task">Task to wait for.</param>
115+ /// <param name="timeout">The timeout period.</param>
116+ /// <param name="exceptionFactory">Optional timeout exception factory.</param>
79117 /// <typeparam name="T">Task return type.</typeparam>
80- public static async Task < T > WithTimeout < T > (
81- this Task < T > task ,
82- int milliseconds = 1_000 ,
83- Exception exceptionToThrow = null )
118+ public static async Task < T > WithTimeout < T > ( this Task < T > task , TimeSpan timeout , Func < TimeSpan , Exception > exceptionFactory = null )
84119 {
85- if ( await TimeoutTask ( task , milliseconds ) )
120+ if ( await TimeoutTask ( task , timeout ) )
86121 {
87- throw exceptionToThrow ?? new TimeoutException ( $ "Timeout Exceeded: { milliseconds } ms exceeded" ) ;
122+ throw ( exceptionFactory ?? DefaultExceptionFactory ) ( timeout ) ;
88123 }
89124
90125 return await task ;
91126 }
92127
93- private static async Task < bool > TimeoutTask ( Task task , int milliseconds )
128+ private static async Task < bool > TimeoutTask ( Task task , TimeSpan timeout )
94129 {
130+ if ( timeout <= TimeSpan . Zero )
131+ {
132+ await task ;
133+ return false ;
134+ }
135+
95136 var tcs = new TaskCompletionSource < bool > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
96137 using ( var cancellationToken = new CancellationTokenSource ( ) )
97138 {
98- if ( milliseconds > 0 )
99- {
100- cancellationToken . CancelAfter ( milliseconds ) ;
101- }
139+ cancellationToken . CancelAfter ( timeout ) ;
102140 using ( cancellationToken . Token . Register ( s => ( ( TaskCompletionSource < bool > ) s ) . TrySetResult ( true ) , tcs ) )
103141 {
104- if ( task != await Task . WhenAny ( task , tcs . Task ) )
105- {
106- return true ;
107- }
142+ return tcs . Task == await Task . WhenAny ( task , tcs . Task ) ;
108143 }
109- return false ;
110144 }
111145 }
112146 }
0 commit comments