Skip to content

Commit 5100bc8

Browse files
ArdenHideCopilot
andauthored
Retries for HTTP calls via Polly lib (#352)
* Retries for HTTP calls via Polly lib * - update retrying code - use dependencies * - save code * - cleanup * - include retries * - use retries for getData rpc call * - fix test * - fix test * Update src/MetaDataAPI/Routing/Requests/GetMetadataRequestHandler.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent eac4f3e commit 5100bc8

7 files changed

Lines changed: 41 additions & 13 deletions

File tree

src/MetaDataAPI/DefaultServiceProvider.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using MetaDataAPI.Services.Strapi;
66
using GraphQL.Client.Abstractions;
77
using MetaDataAPI.Services.ChainsInfo;
8+
using Poolz.Finance.CSharp.Polly.Extensions;
89
using Microsoft.Extensions.DependencyInjection;
910
using poolz.finance.csharp.contracts.LockDealNFT;
1011
using MediatR.Extensions.FluentValidation.AspNetCore;
@@ -21,6 +22,7 @@ public static class DefaultServiceProvider
2122
serviceCollection.AddFluentValidation([Assembly.GetExecutingAssembly()]);
2223

2324
serviceCollection.AddSingleton<IHttpClientFactory, HttpClientFactory>();
25+
serviceCollection.AddSingleton<IRetryExecutor, RetryExecutor>();
2426
serviceCollection.AddSingleton<IWeb3Factory, Web3Factory>();
2527
serviceCollection.AddSingleton<IGraphQLClient, StrapiGraphQLClient>();
2628
serviceCollection.AddSingleton<IStrapiClient, StrapiClient>();

src/MetaDataAPI/MetaDataAPI.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
<PackageReference Include="Net.Cache.DynamoDb.ERC20" Version="2.0.2" />
2222
<PackageReference Include="Net.Utils.GraphQL" Version="1.0.0" />
2323
<PackageReference Include="Pinata.Client" Version="1.0.0" />
24+
<PackageReference Include="Poolz.Finance.CSharp.Polly.Extensions" Version="1.0.0" />
2425
<PackageReference Include="Poolz.Finance.CSharp.Strapi" Version="1.3.5" />
2526
<PackageReference Include="PuppeteerSharp" Version="20.2.4" />
2627
<PackageReference Include="Utils.EnvironmentManager" Version="4.2.0" />

src/MetaDataAPI/Routing/Requests/GetMetadataRequestHandler.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using MetaDataAPI.Models.Errors;
66
using MetaDataAPI.Services.Http;
77
using MetaDataAPI.Services.ChainsInfo;
8+
using Poolz.Finance.CSharp.Polly.Extensions;
89
using poolz.finance.csharp.contracts.LockDealNFT;
910

1011
namespace MetaDataAPI.Routing.Requests;
@@ -13,7 +14,8 @@ public class GetMetadataRequestHandler(
1314
IServiceProvider serviceProvider,
1415
IChainManager chainManager,
1516
ILockDealNFTService lockDealNft,
16-
IWeb3Factory web3Factory
17+
IWeb3Factory web3Factory,
18+
IRetryExecutor retry
1719
) : IRequestHandler<GetMetadataRequest, LambdaResponse>
1820
{
1921
public Task<LambdaResponse> Handle(GetMetadataRequest request, CancellationToken cancellationToken)
@@ -28,12 +30,14 @@ public Task<LambdaResponse> Handle(GetMetadataRequest request, CancellationToken
2830
}
2931

3032
lockDealNft.Initialize(web3Factory.Create(chainId.ToRpcUrl()), chainInfo.LockDealNFT);
31-
if (!lockDealNft.IsPoolIdInSupplyRange(poolId))
33+
var isPoolIdInSupplyRange = retry.Execute(_ => lockDealNft.IsPoolIdInSupplyRange(poolId), ct: cancellationToken);
34+
35+
if (!isPoolIdInSupplyRange)
3236
{
3337
return Task.FromResult<LambdaResponse>(new PoolIdNotInSupplyRangeResponse(poolId));
3438
}
3539

36-
var poolsInfo = lockDealNft.FetchPoolInfo(poolId);
40+
var poolsInfo = retry.Execute(_ => lockDealNft.FetchPoolInfo(poolId), ct: cancellationToken);
3741
var provider = AbstractProvider.CreateFromPoolInfo(poolsInfo, chainInfo, serviceProvider);
3842
var metadata = provider.GetErc721Metadata();
3943

src/MetaDataAPI/Services/Erc20/Erc20Provider.cs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,16 @@
44
using MetaDataAPI.Services.Http;
55
using EnvironmentManager.Extensions;
66
using MetaDataAPI.Services.ChainsInfo;
7+
using Poolz.Finance.CSharp.Polly.Extensions;
78
using Net.Cache.DynamoDb.ERC20.DynamoDb.Models;
89

910
namespace MetaDataAPI.Services.Erc20;
1011

11-
public class Erc20Provider(IErc20CacheService erc20Cache, IWeb3Factory web3Factory) : IErc20Provider
12+
public class Erc20Provider(
13+
IErc20CacheService erc20Cache,
14+
IWeb3Factory web3Factory,
15+
IRetryExecutor retry
16+
) : IErc20Provider
1217
{
1318
public Erc20Token GetErc20Token(ChainInfo chainInfo, EthereumAddress address)
1419
{
@@ -17,11 +22,14 @@ public Erc20Token GetErc20Token(ChainInfo chainInfo, EthereumAddress address)
1722

1823
public Erc20Token GetErc20Token(string rpcUrl, long chainId, EthereumAddress address)
1924
{
20-
var cache = erc20Cache.GetOrAddAsync(
21-
new HashKey(chainId, address),
22-
() => Task.FromResult(web3Factory.Create(rpcUrl)),
23-
() => Task.FromResult(new EthereumAddress(Env.MULTI_CALL_V3_ADDRESS.GetRequired()))
24-
).GetAwaiter().GetResult();
25+
var cache = retry.Execute(_ =>
26+
{
27+
return erc20Cache.GetOrAddAsync(
28+
new HashKey(chainId, address),
29+
() => Task.FromResult(web3Factory.Create(rpcUrl)),
30+
() => Task.FromResult(new EthereumAddress(Env.MULTI_CALL_V3_ADDRESS.GetRequired()))
31+
).GetAwaiter().GetResult();
32+
});
2533
return new Erc20Token(cache);
2634
}
2735
}

src/MetaDataAPI/Services/Http/FailureOnlyLoggingHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
namespace MetaDataAPI.Services.Http;
22

3-
public class FailureOnlyLoggingHandler(HttpMessageHandler inner) : DelegatingHandler(inner)
3+
public class FailureOnlyLoggingHandler(HttpMessageHandler innerHandler) : DelegatingHandler(innerHandler)
44
{
55
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage req, CancellationToken ct)
66
{

src/MetaDataAPI/Services/Strapi/StrapiClient.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
using Net.Utils.GraphQL.Extensions;
55
using MetaDataAPI.Services.ChainsInfo;
66
using MetaDataAPI.Services.Strapi.Models;
7+
using Poolz.Finance.CSharp.Polly.Extensions;
78

89
namespace MetaDataAPI.Services.Strapi;
910

10-
public class StrapiClient(IGraphQLClient graphQlClient) : IStrapiClient
11+
public class StrapiClient(IGraphQLClient graphQlClient, IRetryExecutor retry) : IStrapiClient
1112
{
1213
private const string NameOfLockDealNFT = "LockDealNFT";
1314

@@ -55,7 +56,9 @@ public class StrapiClient(IGraphQLClient graphQlClient) : IStrapiClient
5556
.WithParameter(chainFilter)
5657
.Build();
5758

58-
var response = await graphQlClient.SendQueryAsync<StrapiDataResponse>(new GraphQLQuery(query));
59+
var response = await retry.ExecuteAsync(async token =>
60+
await graphQlClient.SendQueryAsync<StrapiDataResponse>(new GraphQLQuery(query), cancellationToken: token)
61+
);
5962

6063
var data = response.EnsureNoErrors();
6164

tests/MetaDataAPI.Tests/Services/Erc20/Erc20ProviderTests.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using MetaDataAPI.Services.ChainsInfo;
1111
using Net.Cache.DynamoDb.ERC20.Rpc.Models;
1212
using Net.Cache.DynamoDb.ERC20.DynamoDb.Models;
13+
using Poolz.Finance.CSharp.Polly.Extensions;
1314

1415
namespace MetaDataAPI.Tests.Services.Erc20;
1516

@@ -26,6 +27,7 @@ internal void ShouldReceiveExpectedErc20FromDynamoDb()
2627
Environment.SetEnvironmentVariable(nameof(Env.BASE_URL_OF_RPC), baseRpcUrl);
2728
Environment.SetEnvironmentVariable(nameof(Env.MULTI_CALL_V3_ADDRESS), EthereumAddress.ZeroAddress);
2829

30+
var retryExecutor = new Mock<IRetryExecutor>();
2931
var cacheProvider = new Mock<IErc20CacheService>();
3032
var web3Factory = new Mock<IWeb3Factory>();
3133
var web3 = new Mock<IWeb3>();
@@ -47,7 +49,15 @@ internal void ShouldReceiveExpectedErc20FromDynamoDb()
4749
))
4850
.ReturnsAsync(cacheItem);
4951

50-
var provider = new Erc20Provider(cacheProvider.Object, web3Factory.Object);
52+
retryExecutor
53+
.Setup(x => x.Execute(
54+
It.IsAny<Func<CancellationToken, Erc20TokenDynamoDbEntry>>(),
55+
It.IsAny<DefaultRetryStrategyOptions<Erc20TokenDynamoDbEntry>>(),
56+
It.IsAny<CancellationToken>()
57+
))
58+
.Returns((Func<CancellationToken, Erc20TokenDynamoDbEntry> action, DefaultRetryStrategyOptions<Erc20TokenDynamoDbEntry> _, CancellationToken token) => action(token));
59+
60+
var provider = new Erc20Provider(cacheProvider.Object, web3Factory.Object, retryExecutor.Object);
5161

5262
var result = provider.GetErc20Token(
5363
new ChainInfo(chainId, EthereumAddress.ZeroAddress),

0 commit comments

Comments
 (0)