public static async Task <T> TryWithExponentialBackoff <T>(Func <Task <T> > taskToTry, Action <Exception> onError = null, int maxNrOfRetries = -1, int maxDelayInMs = -1, int initialExponent = 0) { int retryCount = initialExponent; Stopwatch timer = Stopwatch.StartNew(); do { timer.Restart(); try { Task <T> task = taskToTry(); var result = await task; if (!task.IsFaulted && !task.IsFaulted) { return(result); } } catch (Exception e) { onError.InvokeIfNotNull(e); } retryCount++; int delay = (int)(Math.Pow(2, retryCount) - timer.ElapsedMilliseconds); if (delay > maxDelayInMs && maxDelayInMs > 0) { delay = maxDelayInMs; } if (delay > 0) { await TaskV2.Delay(delay); } if (retryCount >= maxNrOfRetries && maxNrOfRetries > 0) { throw new OperationCanceledException("No success after " + retryCount + " retries"); } } while (true); }
/// <summary> /// This will create an EventHandler where the first call is executed and the last call is executed but /// every call in between that is below the passed millisecond threshold is ignored /// </summary> public static EventHandler <T> AsThrottledDebounce <T>(this EventHandler <T> self, double delayInMs) { bool currentlyThrottling = false; bool needsFinalCall = false; object threadLock = new object(); Func <object, T, Task> asyncEventHandler = async(sender, eventArgs) => { lock (threadLock) { if (currentlyThrottling) { needsFinalCall = true; return; } currentlyThrottling = true; self(sender, eventArgs); } await TaskV2.Delay(TimeSpan.FromMilliseconds(delayInMs)); lock (threadLock) { if (needsFinalCall) { try { self(sender, eventArgs); } catch (Exception e) { Log.e(e); } } currentlyThrottling = false; needsFinalCall = false; } }; return((sender, eventArgs) => { asyncEventHandler(sender, eventArgs); }); }
/// <summary> /// This will create an EventHandler where the first call is executed and the last call is executed but /// every call in between that is below the passed millisecond threshold is ignored /// </summary> public static EventHandler <T> AsThrottledDebounce <T>(this EventHandler <T> self, double delayInMs, bool skipFirstEvent = false) { object threadLock = new object(); T latestEventArgs; Stopwatch s = Stopwatch.StartNew(); bool triggerFirstEvent = !skipFirstEvent; Func <object, T, Task> asyncEventHandler = async(sender, eventArgs) => { lock (threadLock) { latestEventArgs = eventArgs; s.Restart(); if (triggerFirstEvent) { triggerFirstEvent = false; self(sender, latestEventArgs); } } await TaskV2.Delay(TimeSpan.FromMilliseconds(delayInMs * 1.1f)); lock (threadLock) { if (s.ElapsedMilliseconds >= delayInMs) { s.Restart(); self(sender, latestEventArgs); if (!skipFirstEvent) { triggerFirstEvent = true; } } } }; return((sender, eventArgs) => { asyncEventHandler(sender, eventArgs); }); }
/// <summary> /// This will create an async func where the first call is executed and the last call is executed but /// every call in between that is below the passed millisecond threshold is ignored /// </summary> /// <param name="skipFirstEvent"> if set to true there will be no instant execution of the very first call to the debounced async func </param> /// <exception cref="TaskCanceledException"> If the func was canceled because another one after it replaced it the returned Task will indicate this </exception> public static Func <T, Task> AsThrottledDebounce <T>(this Func <T, Task> self, double delayInMs, bool skipFirstEvent = false) { int triggerFirstEvent = skipFirstEvent ? 0 : 1; int last = 0; return(async(t) => { var current = Interlocked.Increment(ref last); if (!skipFirstEvent && ThreadSafety.FlipToFalse(ref triggerFirstEvent)) { await self(t); } else { await TaskV2.Delay((int)delayInMs); if (current == last) { await self(t); } else { throw new TaskCanceledException(); } } }); }
private async Task RunInternetCheckLoop(Task firstInetCheck) { await firstInetCheck; await TaskV2.RunRepeated(async() => { HasInetAsync = RunInternetCheck(); await HasInetAsync; return(true); }, delayInMsBetweenIterations : 3000, cancelToken : cancelToken.Token); }
public InternetStateManager() { #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed TaskV2.RunRepeated(async() => { await HasInet(await RestFactory.instance.HasInternet()); return(true); }, delayInMsBetweenIterations: 3000, cancelToken: cancelToken.Token); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed }
private async Task MonitorProgress(IProgress targetProgressToUpdate, int updateIntervalInMs) { do { targetProgressToUpdate.SetCount(ElapsedMilliseconds, timerDurationInMs); await TaskV2.Delay(updateIntervalInMs); } while (!timerTask.IsCompleted); targetProgressToUpdate.SetComplete(); }
public static async Task WithTimeout(this Task self, int timeoutInMs) { var completedTask = await Task.WhenAny(self, TaskV2.Delay(timeoutInMs)); if (completedTask != self) { throw new TimeoutException(); } await self; // use await to propagate exceptions }
public Task Run(Func <CancellationToken, Task> asyncAction, CancellationTokenSource cancellationTokenSource) { if (!ReferenceEquals(Cancel, cancellationTokenSource)) { cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationTokenSource.Token, Cancel.Token); } var t = TaskV2.Run(async() => { ThrowIfCancellationRequested(cancellationTokenSource); await asyncAction(cancellationTokenSource.Token); ThrowIfCancellationRequested(cancellationTokenSource); }, cancellationTokenSource, Scheduler); return(AddToManagedTasks(t)); }
/// <summary> /// This will create an EventHandler where the first call is executed and the last call is executed but /// every call in between that is below the passed millisecond threshold is ignored /// </summary> public static EventHandler <T> AsThrottledDebounce <T>(this EventHandler <T> self, double delayInMs, bool skipFirstEvent = false) { object threadLock = new object(); T latestEventArgs; Stopwatch s = Stopwatch.StartNew(); bool triggerFirstEvent = !skipFirstEvent; Func <object, T, Task> asyncEventHandler = async(sender, eventArgs) => { lock (threadLock) { latestEventArgs = eventArgs; s.Restart(); if (triggerFirstEvent) { triggerFirstEvent = false; self(sender, eventArgs); } } var delay = TaskV2.Delay((int)(delayInMs * 1.1f)); await HandlerTaskResultIfNeeded(eventArgs); await delay; if (s.ElapsedMilliseconds >= delayInMs) { lock (threadLock) { if (s.ElapsedMilliseconds >= delayInMs) { s.Reset(); // Stop (and reset) and only continue below self(sender, latestEventArgs); if (!skipFirstEvent) { triggerFirstEvent = true; } } } await HandlerTaskResultIfNeeded(latestEventArgs); s.Restart(); } }; return((sender, eventArgs) => { asyncEventHandler(sender, eventArgs).ContinueWithSameContext(finishedTask => { // A failed task cant be awaited but it can be logged if (finishedTask.Exception != null) { Log.e(finishedTask.Exception); } }); }); }
private async Task NewTimerTask(int timerDurationInMs) { this.timerDurationInMs = timerDurationInMs; cancellationToken = new CancellationTokenSource(); timer = StopwatchV2.StartNewV2(); await TaskV2.Delay(timerDurationInMs, cancellationToken.Token); int durationSoFar = (int)timer.ElapsedMilliseconds; if (durationSoFar < timerDurationInMs) { await TaskV2.Delay(timerDurationInMs - durationSoFar); } Stop(); }
public async Task <T> Run <T>(Func <CancellationToken, Task <T> > asyncFunction, CancellationTokenSource cancellationTokenSource) { if (!ReferenceEquals(Cancel, cancellationTokenSource)) { cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationTokenSource.Token, Cancel.Token); } Task <T> t = TaskV2.Run(async() => { ThrowIfCancellationRequested(cancellationTokenSource); T result = await asyncFunction(cancellationTokenSource.Token); ThrowIfCancellationRequested(cancellationTokenSource); return(result); }, cancellationTokenSource, Scheduler); await AddToManagedTasks(t); return(await t); }
public static async Task RunRepeated(Func <Task <bool> > task, int delayInMsBetweenIterations, CancellationToken cancelToken, int delayInMsBeforeFirstExecution = 0, float repetitions = -1) { if (delayInMsBeforeFirstExecution > 0) { await Delay(delayInMsBeforeFirstExecution); } while (repetitions != 0) { cancelToken.ThrowIfCancellationRequested(); if (!await task()) { break; } await TaskV2.Delay(delayInMsBetweenIterations); repetitions--; } }
public static async Task MonitorPositionForProgress(this Stream self, Action <long> onProgress, CancellationTokenSource cancel, int delayInMsBetweenProgress = 10) { onProgress.ThrowErrorIfNull("onProgress"); long progress = 0; do { cancel?.Token.ThrowIfCancellationRequested(); await TaskV2.Delay(delayInMsBetweenProgress); long newProgress = 100l * self.Position / self.Length; if (progress != newProgress) { onProgress(newProgress); } progress = newProgress; } while (progress < 100); }
public async Task WhenAllTasksCompleted(int millisecondsDelay = 50, bool flushQueueAfterCompletion = false) { await Task.WhenAll(Tasks); if (millisecondsDelay > 0) { await TaskV2.Delay(millisecondsDelay); } // If there were new tasks added in the meantime, do another wait for the remaining tasks: if (!IsAllTasksCompleted()) { await WhenAllTasksCompleted(); } if (flushQueueAfterCompletion) { Tasks.Clear(); } // Automatically flush task queue after all are done? }
/// <summary> /// This will create an EventHandler where the first call is executed and the last call is executed but /// every call in between that is below the passed millisecond threshold is ignored /// </summary> /// <param name="skipFirstEvent"> if set to true there will be no instant execution of the very first call to the debounced async func </param> public static EventHandler <T> AsThrottledDebounce <T>(this EventHandler <T> self, double delayInMs, bool skipFirstEvent = false) { int triggerFirstEvent = skipFirstEvent ? 0 : 1; int last = 0; return((sender, eventArgs) => { var current = Interlocked.Increment(ref last); if (!skipFirstEvent && ThreadSafety.FlipToFalse(ref triggerFirstEvent)) { self(sender, eventArgs); } else { TaskV2.Delay((int)delayInMs).ContinueWithSameContext(task => { if (current == last) { self(sender, eventArgs); } }); } }); }