More docs regarding retry_handling

This commit is contained in:
Jonas Dellinger 2020-06-03 19:12:12 +02:00
parent d31a9e4ea1
commit 7bc5015950
6 changed files with 85 additions and 21 deletions

View File

@ -0,0 +1,50 @@
---
id: retry_handling
title: Retry Handling
---
In [Error Handling](error_handling.md) we already found out that requests can fail. We provide a way to automatically retry requests via retry handlers. Note, by default no retries are performed.
```csharp
var config = SpotifyClientConfig
.CreateDefault()
.WithRetryHandler(new YourCustomRetryHandler())
```
[`IRetryHandler`](https://github.com/JohnnyCrazy/SpotifyAPI-NET/blob/master/SpotifyAPI.Web/Http/Interfaces/IRetryHandler.cs) only needs one function:
```csharp
public class YourCustomRetryHandler : IRetryHandler
{
public Task<IResponse> HandleRetry(IRequest request, IResponse response, IRetryHandler.RetryFunc retry)
{
// request is the sent request and response the received response, obviously?
// don't retry:
return response;
// retry once
var newResponse = retry(request);
return newResponse;
// use retry as often as you want, make sure to return a response
}
}
```
## SimpleRetryHandler
A `SimpleRetryHandler` is included, which contains the following retry logic:
* Retries the (configurable) status codes: 500, 502, 503 and 429
* `RetryAfter` - specifies the delay between retried calls
* `RetryTimes` - specifies the maxiumum amount of performed retries per call
* `TooManyRequestsConsumesARetry` - Whether a failure of type "Too Many Requests" should use up one of the retry attempts.
```csharp
var config = SpotifyClientConfig
.CreateDefault()
.WithRetryHandler(new SimpleRetryHandler() { RetryAfter = TimeSpan.FromSeconds(1) });
var spotify = new SpotifyClient(config);
```

View File

@ -40,11 +40,6 @@ module.exports = {
]
},
{ to: 'news', label: 'News', position: 'left' },
{
href: 'https://www.nuget.org/packages/SpotifyAPI.Web/',
label: 'NuGET',
position: 'right',
},
{
href: 'https://github.com/JohnnyCrazy/SpotifyAPI-NET',
label: 'GitHub',

View File

@ -12,6 +12,7 @@ module.exports = {
'logging',
'proxy',
'pagination',
'retry_handling',
]
},
{

View File

@ -93,7 +93,25 @@ function Home() {
<h1 className="hero__title">
{siteConfig.title}
<span style={{ marginLeft: '50px' }} />
<GitHubButton href="https://github.com/JohnnyCrazy/SpotifyAPI-NET" data-icon="octicon-star" data-size="large" data-show-count="true" aria-label="Star JohnnyCrazy/SpotifyAPI-NET on GitHub">Star</GitHubButton>
<GitHubButton
href="https://github.com/JohnnyCrazy/SpotifyAPI-NET"
data-icon="octicon-star"
data-size="large"
data-show-count="true"
aria-label="Star JohnnyCrazy/SpotifyAPI-NET on GitHub">Star</GitHubButton>
<br />
<a href="https://www.nuget.org/packages/SpotifyAPI.Web/" rel="noopener noreferrer">
<img
alt="Nuget"
src="https://img.shields.io/nuget/v/SpotifyAPI.Web?label=SpotifyAPI.Web&style=flat-square">
</img>{' '}
</a>
<a href="https://www.nuget.org/packages/SpotifyAPI.Web.Auth/" rel="noopener noreferrer">
<img
alt="Nuget"
src="https://img.shields.io/nuget/v/SpotifyAPI.Web.Auth?label=SpotifyAPI.Web.Auth&style=flat-square">
</img>
</a>
</h1>
<p className="hero__subtitle">{siteConfig.tagline}</p>
<div className={styles.buttons}>

View File

@ -36,7 +36,7 @@ namespace SpotifyAPI.Web
Assert.AreEqual(2, retryCalled);
Assert.AreEqual(setup.Response.Object, response);
setup.Sleep.Verify(s => s(50000), Times.Exactly(2));
setup.Sleep.Verify(s => s(TimeSpan.FromMilliseconds(50)), Times.Exactly(2));
}
[Test]
@ -67,7 +67,7 @@ namespace SpotifyAPI.Web
Assert.AreEqual(1, retryCalled);
Assert.AreEqual(successResponse.Object, response);
setup.Sleep.Verify(s => s(50000), Times.Once);
setup.Sleep.Verify(s => s(TimeSpan.FromMilliseconds(50)), Times.Once);
}
[Test]
@ -97,7 +97,7 @@ namespace SpotifyAPI.Web
Assert.AreEqual(1, retryCalled);
Assert.AreEqual(successResponse.Object, response);
setup.Sleep.Verify(s => s(50000), Times.Once);
setup.Sleep.Verify(s => s(TimeSpan.FromMilliseconds(50)), Times.Once);
}
[Test]
@ -117,13 +117,13 @@ namespace SpotifyAPI.Web
{
TooManyRequestsConsumesARetry = true,
RetryTimes = 10,
RetryAfter = 50
RetryAfter = TimeSpan.FromMilliseconds(50)
};
var response = await handler.HandleRetry(setup.Request.Object, setup.Response.Object, setup.Retry);
Assert.AreEqual(10, retryCalled);
Assert.AreEqual(setup.Response.Object, response);
setup.Sleep.Verify(s => s(50), Times.Exactly(10));
setup.Sleep.Verify(s => s(TimeSpan.FromMilliseconds(50)), Times.Exactly(10));
}
[Test]
@ -143,18 +143,18 @@ namespace SpotifyAPI.Web
{
TooManyRequestsConsumesARetry = true,
RetryTimes = 10,
RetryAfter = 50
RetryAfter = TimeSpan.FromMilliseconds(50)
};
var response = await handler.HandleRetry(setup.Request.Object, setup.Response.Object, setup.Retry);
Assert.AreEqual(0, retryCalled);
Assert.AreEqual(setup.Response.Object, response);
setup.Sleep.Verify(s => s(50), Times.Exactly(0));
setup.Sleep.Verify(s => s(TimeSpan.FromMilliseconds(50)), Times.Exactly(0));
}
private class Setup
{
public Mock<Func<int, Task>> Sleep { get; set; } = new Mock<Func<int, Task>>();
public Mock<Func<TimeSpan, Task>> Sleep { get; set; } = new Mock<Func<TimeSpan, Task>>();
public Mock<IResponse> Response { get; set; } = new Mock<IResponse>();
public Mock<IRequest> Request { get; set; } = new Mock<IRequest>();
public IRetryHandler.RetryFunc Retry { get; set; }

View File

@ -9,12 +9,12 @@ namespace SpotifyAPI.Web
{
public class SimpleRetryHandler : IRetryHandler
{
private readonly Func<int, Task> _sleep;
private readonly Func<TimeSpan, Task> _sleep;
/// <summary>
/// Specifies after how many miliseconds should a failed request be retried.
/// </summary>
public int RetryAfter { get; set; }
public TimeSpan RetryAfter { get; set; }
/// <summary>
/// Maximum number of tries for one failed request.
@ -38,10 +38,10 @@ namespace SpotifyAPI.Web
/// </summary>
/// <returns></returns>
public SimpleRetryHandler() : this(Task.Delay) { }
public SimpleRetryHandler(Func<int, Task> sleep)
public SimpleRetryHandler(Func<TimeSpan, Task> sleep)
{
_sleep = sleep;
RetryAfter = 50;
RetryAfter = TimeSpan.FromMilliseconds(50);
RetryTimes = 10;
TooManyRequestsConsumesARetry = false;
RetryErrorCodes = new[] {
@ -51,7 +51,7 @@ namespace SpotifyAPI.Web
};
}
private static int? ParseTooManyRetriesToMs(IResponse response)
private static TimeSpan? ParseTooManyRetries(IResponse response)
{
if (response.StatusCode != (HttpStatusCode)429)
{
@ -59,7 +59,7 @@ namespace SpotifyAPI.Web
}
if (int.TryParse(response.Headers["Retry-After"], out int secondsToWait))
{
return secondsToWait * 1000;
return TimeSpan.FromSeconds(secondsToWait);
}
throw new APIException("429 received, but unable to parse Retry-After Header. This should not happen!");
@ -78,7 +78,7 @@ namespace SpotifyAPI.Web
IRetryHandler.RetryFunc retry,
int triesLeft)
{
var secondsToWait = ParseTooManyRetriesToMs(response);
var secondsToWait = ParseTooManyRetries(response);
if (secondsToWait != null && (!TooManyRequestsConsumesARetry || triesLeft > 0))
{
await _sleep(secondsToWait.Value).ConfigureAwait(false);