mirror of
https://github.com/Sarsoo/Spotify.NET.git
synced 2024-12-23 22:56:25 +00:00
More docs regarding retry_handling
This commit is contained in:
parent
d31a9e4ea1
commit
7bc5015950
50
SpotifyAPI.Docs/docs/retry_handling.md
Normal file
50
SpotifyAPI.Docs/docs/retry_handling.md
Normal 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);
|
||||||
|
```
|
@ -40,11 +40,6 @@ module.exports = {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{ to: 'news', label: 'News', position: 'left' },
|
{ 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',
|
href: 'https://github.com/JohnnyCrazy/SpotifyAPI-NET',
|
||||||
label: 'GitHub',
|
label: 'GitHub',
|
||||||
|
@ -12,6 +12,7 @@ module.exports = {
|
|||||||
'logging',
|
'logging',
|
||||||
'proxy',
|
'proxy',
|
||||||
'pagination',
|
'pagination',
|
||||||
|
'retry_handling',
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -93,7 +93,25 @@ function Home() {
|
|||||||
<h1 className="hero__title">
|
<h1 className="hero__title">
|
||||||
{siteConfig.title}
|
{siteConfig.title}
|
||||||
<span style={{ marginLeft: '50px' }} />
|
<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>
|
</h1>
|
||||||
<p className="hero__subtitle">{siteConfig.tagline}</p>
|
<p className="hero__subtitle">{siteConfig.tagline}</p>
|
||||||
<div className={styles.buttons}>
|
<div className={styles.buttons}>
|
||||||
|
@ -36,7 +36,7 @@ namespace SpotifyAPI.Web
|
|||||||
|
|
||||||
Assert.AreEqual(2, retryCalled);
|
Assert.AreEqual(2, retryCalled);
|
||||||
Assert.AreEqual(setup.Response.Object, response);
|
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]
|
[Test]
|
||||||
@ -67,7 +67,7 @@ namespace SpotifyAPI.Web
|
|||||||
|
|
||||||
Assert.AreEqual(1, retryCalled);
|
Assert.AreEqual(1, retryCalled);
|
||||||
Assert.AreEqual(successResponse.Object, response);
|
Assert.AreEqual(successResponse.Object, response);
|
||||||
setup.Sleep.Verify(s => s(50000), Times.Once);
|
setup.Sleep.Verify(s => s(TimeSpan.FromMilliseconds(50)), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -97,7 +97,7 @@ namespace SpotifyAPI.Web
|
|||||||
|
|
||||||
Assert.AreEqual(1, retryCalled);
|
Assert.AreEqual(1, retryCalled);
|
||||||
Assert.AreEqual(successResponse.Object, response);
|
Assert.AreEqual(successResponse.Object, response);
|
||||||
setup.Sleep.Verify(s => s(50000), Times.Once);
|
setup.Sleep.Verify(s => s(TimeSpan.FromMilliseconds(50)), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -117,13 +117,13 @@ namespace SpotifyAPI.Web
|
|||||||
{
|
{
|
||||||
TooManyRequestsConsumesARetry = true,
|
TooManyRequestsConsumesARetry = true,
|
||||||
RetryTimes = 10,
|
RetryTimes = 10,
|
||||||
RetryAfter = 50
|
RetryAfter = TimeSpan.FromMilliseconds(50)
|
||||||
};
|
};
|
||||||
var response = await handler.HandleRetry(setup.Request.Object, setup.Response.Object, setup.Retry);
|
var response = await handler.HandleRetry(setup.Request.Object, setup.Response.Object, setup.Retry);
|
||||||
|
|
||||||
Assert.AreEqual(10, retryCalled);
|
Assert.AreEqual(10, retryCalled);
|
||||||
Assert.AreEqual(setup.Response.Object, response);
|
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]
|
[Test]
|
||||||
@ -143,18 +143,18 @@ namespace SpotifyAPI.Web
|
|||||||
{
|
{
|
||||||
TooManyRequestsConsumesARetry = true,
|
TooManyRequestsConsumesARetry = true,
|
||||||
RetryTimes = 10,
|
RetryTimes = 10,
|
||||||
RetryAfter = 50
|
RetryAfter = TimeSpan.FromMilliseconds(50)
|
||||||
};
|
};
|
||||||
var response = await handler.HandleRetry(setup.Request.Object, setup.Response.Object, setup.Retry);
|
var response = await handler.HandleRetry(setup.Request.Object, setup.Response.Object, setup.Retry);
|
||||||
|
|
||||||
Assert.AreEqual(0, retryCalled);
|
Assert.AreEqual(0, retryCalled);
|
||||||
Assert.AreEqual(setup.Response.Object, response);
|
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
|
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<IResponse> Response { get; set; } = new Mock<IResponse>();
|
||||||
public Mock<IRequest> Request { get; set; } = new Mock<IRequest>();
|
public Mock<IRequest> Request { get; set; } = new Mock<IRequest>();
|
||||||
public IRetryHandler.RetryFunc Retry { get; set; }
|
public IRetryHandler.RetryFunc Retry { get; set; }
|
||||||
|
@ -9,12 +9,12 @@ namespace SpotifyAPI.Web
|
|||||||
{
|
{
|
||||||
public class SimpleRetryHandler : IRetryHandler
|
public class SimpleRetryHandler : IRetryHandler
|
||||||
{
|
{
|
||||||
private readonly Func<int, Task> _sleep;
|
private readonly Func<TimeSpan, Task> _sleep;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Specifies after how many miliseconds should a failed request be retried.
|
/// Specifies after how many miliseconds should a failed request be retried.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int RetryAfter { get; set; }
|
public TimeSpan RetryAfter { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maximum number of tries for one failed request.
|
/// Maximum number of tries for one failed request.
|
||||||
@ -38,10 +38,10 @@ namespace SpotifyAPI.Web
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public SimpleRetryHandler() : this(Task.Delay) { }
|
public SimpleRetryHandler() : this(Task.Delay) { }
|
||||||
public SimpleRetryHandler(Func<int, Task> sleep)
|
public SimpleRetryHandler(Func<TimeSpan, Task> sleep)
|
||||||
{
|
{
|
||||||
_sleep = sleep;
|
_sleep = sleep;
|
||||||
RetryAfter = 50;
|
RetryAfter = TimeSpan.FromMilliseconds(50);
|
||||||
RetryTimes = 10;
|
RetryTimes = 10;
|
||||||
TooManyRequestsConsumesARetry = false;
|
TooManyRequestsConsumesARetry = false;
|
||||||
RetryErrorCodes = new[] {
|
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)
|
if (response.StatusCode != (HttpStatusCode)429)
|
||||||
{
|
{
|
||||||
@ -59,7 +59,7 @@ namespace SpotifyAPI.Web
|
|||||||
}
|
}
|
||||||
if (int.TryParse(response.Headers["Retry-After"], out int secondsToWait))
|
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!");
|
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,
|
IRetryHandler.RetryFunc retry,
|
||||||
int triesLeft)
|
int triesLeft)
|
||||||
{
|
{
|
||||||
var secondsToWait = ParseTooManyRetriesToMs(response);
|
var secondsToWait = ParseTooManyRetries(response);
|
||||||
if (secondsToWait != null && (!TooManyRequestsConsumesARetry || triesLeft > 0))
|
if (secondsToWait != null && (!TooManyRequestsConsumesARetry || triesLeft > 0))
|
||||||
{
|
{
|
||||||
await _sleep(secondsToWait.Value).ConfigureAwait(false);
|
await _sleep(secondsToWait.Value).ConfigureAwait(false);
|
||||||
|
Loading…
Reference in New Issue
Block a user