/// <summary> /// Waits until the synchronization semaphore is available, creates a new operation and handles resolution. /// </summary> /// <param name="createTimerContext">Creates a <see cref="TimerContext"/> to measure operation latency.</param> /// <param name="resultProducer">Producer to generate operation calls as a producer-consumer.</param> /// <param name="onSuccess">Event handler for operation success.</param> /// <param name="onFailure"></param> /// <param name="logDiagnostics">Event handler for tracking diagnostics when latency goes above the threshold.</param> /// <param name="cancellationToken"></param> /// <returns></returns> public static async Task PerformOperationAsync( Func <TimerContext> createTimerContext, ICTLResultProducer <T> resultProducer, Action onSuccess, Action <Exception> onFailure, Action <T, TimeSpan> logDiagnostics) { while (resultProducer.HasMoreResults) { using (TimerContext timerContext = createTimerContext()) { await resultProducer.GetNextAsync().ContinueWith(task => { if (task.IsCompletedSuccessfully) { logDiagnostics(task.Result, timerContext.Elapsed); if (!resultProducer.HasMoreResults) { onSuccess(); } } else { onFailure(task.Exception); } }); } } }
/// <summary> /// Waits until the synchronization semaphore is available, creates a new operation and handles resolution. /// </summary> /// <param name="semaphoreSlim">Synchronization semaphore that defines maximum degree of parallelism.</param> /// <param name="diagnosticsLoggingThreshold">Latency threshold above which <paramref name="logDiagnostics"/> will be called.</param> /// <param name="createTimerContext">Creates a <see cref="TimerContext"/> to measure operation latency.</param> /// <param name="resultProducer">Producer to generate operation calls as a producer-consumer.</param> /// <param name="onSuccess">Event handler for operation success.</param> /// <param name="onFailure"></param> /// <param name="logDiagnostics">Event handler for tracking diagnostics when latency goes above the threshold.</param> /// <param name="cancellationToken"></param> /// <returns></returns> public static async Task PerformOperationAsync( SemaphoreSlim semaphoreSlim, long diagnosticsLoggingThreshold, Func <TimerContext> createTimerContext, ICTLResultProducer <T> resultProducer, Action onSuccess, Action <Exception> onFailure, Action <T> logDiagnostics, CancellationToken cancellationToken) { while (resultProducer.HasMoreResults) { await semaphoreSlim.WaitAsync(cancellationToken); using (TimerContext timerContext = createTimerContext()) { await resultProducer.GetNextAsync().ContinueWith(task => { semaphoreSlim.Release(); long latency = (long)timerContext.Elapsed.TotalMilliseconds; if (task.IsCompletedSuccessfully) { if (latency > diagnosticsLoggingThreshold) { logDiagnostics(task.Result); } onSuccess(); } else { onFailure(task.Exception); } }); } } }