/// <summary> /// Gets a TimeSpan value which defines how long to wait before trying again after an unsuccessful attempt to /// dequeue a message. /// </summary> /// <param name="attempt"> /// The number of attempts carried out so far. That is, after the first attempt (for the first retry), attempt /// will be set to 1, after the second attempt it is set to 2, and so on. /// </param> /// <returns> /// A TimeSpan value which defines how long to wait before the next attempt. /// </returns> public TimeSpan GetWaitTime(int attempt) { TimeSpan waitTime = inner.GetWaitTime(attempt); double random = rng.NextDouble(); double multiplier = max - (random * (max - min)); return(new TimeSpan(Convert.ToInt64(waitTime.Ticks * multiplier))); }
/// <summary> /// Gets a TimeSpan value which defines how long to wait before trying again after an unsuccessful attempt to /// dequeue a message. /// </summary> /// <param name="attempt"> /// The number of attempts carried out so far. That is, after the first attempt (for the first retry), attempt /// will be set to 1, after the second attempt it is set to 2, and so on. /// </param> /// <returns> /// A TimeSpan value which defines how long to wait before the next attempt. /// </returns> public TimeSpan GetWaitTime(int attempt) { if (inner.ShouldRetry(attempt)) { return(inner.GetWaitTime(attempt)); } // We don't know the last wait time used by the inner strategy yet, so let's go and discover it. int lastSupportedAttempt = 1; while (inner.ShouldRetry(lastSupportedAttempt + 1)) { lastSupportedAttempt++; } return(inner.GetWaitTime(lastSupportedAttempt)); }
/// <summary> /// Consumes one message from the queue, applying the given IRetryStrategy to wait for a message if the queue /// is empty. /// </summary> /// <param name="dequeueStrategy"> /// An instance of IRetryStrategy which defines how long and how often to query the queue for a single message. /// </param> /// <param name="cancellationToken"> /// A CancellationToken to use to check if the operation should be cancelled. /// </param> /// <returns> /// True if a message was successfully consumed, false otherwise. /// </returns> public bool One(IRetryStrategy dequeueStrategy, CancellationToken cancellationToken) { if (null == dequeueStrategy) { throw new ArgumentNullException("dequeueStrategy"); } for (int i = 1; ; i++) { if (cancellationToken.IsCancellationRequested) { return(false); } using (JobExecutionContext context = JobExecutionContext.Dequeue(this)) { if (context.Empty) { if (dequeueStrategy.ShouldRetry(i)) { Task.Delay(dequeueStrategy.GetWaitTime(i), cancellationToken) .ContinueWith(NoopTaskContinuation) .Wait(); continue; } break; } using (new JobPerfContext(this, context)) { return(context.Execute()); } } } return(false); }
/// <summary> /// Consumes one message from the queue, applying the given IRetryStrategy to wait for a message if the queue /// is empty. /// </summary> /// <param name="dequeueStrategy"> /// An instance of IRetryStrategy which defines how long and how often to query the queue for a single message. /// </param> /// <param name="cancellationToken"> /// A CancellationToken to use to check if the operation should be cancelled. /// </param> /// <returns> /// True if a message was successfully consumed, false otherwise. /// </returns> public bool One(IRetryStrategy dequeueStrategy, CancellationToken cancellationToken) { if (null == dequeueStrategy) { throw new ArgumentNullException("dequeueStrategy"); } for (int i = 1; ; i++) { if (cancellationToken.IsCancellationRequested) { return false; } using (JobExecutionContext context = JobExecutionContext.Dequeue(this)) { if (context.Empty) { if (dequeueStrategy.ShouldRetry(i)) { Task.Delay(dequeueStrategy.GetWaitTime(i), cancellationToken) .ContinueWith(NoopTaskContinuation) .Wait(); continue; } break; } return context.Execute(); } } return false; }