Skip to content

Commit

Permalink
updated
Browse files Browse the repository at this point in the history
  • Loading branch information
HaikAsatryan committed Sep 13, 2024
1 parent a3b88e9 commit ad52da7
Show file tree
Hide file tree
Showing 13 changed files with 213 additions and 24 deletions.
17 changes: 9 additions & 8 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
<Project>
<ItemGroup>
<PackageVersion Include="AspNetCore.HealthChecks.NpgSql" Version="8.0.1" />
<PackageVersion Include="AspNetCore.HealthChecks.Rabbitmq" Version="8.0.1" />
<PackageVersion Include="AspNetCore.HealthChecks.NpgSql" Version="8.0.2" />
<PackageVersion Include="AspNetCore.HealthChecks.Rabbitmq" Version="8.0.2" />
<PackageVersion Include="AspNetCore.HealthChecks.Prometheus.Metrics" Version="8.0.1" />
<PackageVersion Include="AspNetCore.HealthChecks.Redis" Version="8.0.1" />
<PackageVersion Include="AspNetCore.HealthChecks.UI.Client" Version="8.0.1" />
<PackageVersion Include="EFCore.NamingConventions" Version="8.0.3" />
<PackageVersion Include="Elastic.CommonSchema.Serilog" Version="8.11.1" />
<PackageVersion Include="EntityFrameworkCore.Exceptions.PostgreSQL" Version="8.1.3" />
<PackageVersion Include="FluentDateTime" Version="3.0.0" />
<PackageVersion Include="FluentValidation.AspNetCore" Version="11.3.0" />
<PackageVersion Include="Hangfire" Version="1.8.14" />
Expand All @@ -16,7 +17,7 @@
<PackageVersion Include="MassTransit.RabbitMQ" Version="8.2.5" />
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="8.0.8" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.8" />
<PackageVersion Include="MediatR" Version="12.4.0" />
<PackageVersion Include="MediatR" Version="12.4.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand All @@ -25,20 +26,20 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageVersion>
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.0" />
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="8.9.1" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageVersion Include="NetArchTest.Rules" Version="1.3.2" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0" />
<PackageVersion Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.7.0-rc.1" />
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.GrpcNetClient" Version="1.7.0-beta.1" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.9.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.9.0" />
<PackageVersion Include="Otp.NET" Version="1.3.0" />
<PackageVersion Include="Pandatech.DistributedCache" Version="1.2.3" />
<PackageVersion Include="Pandatech.DistributedCache" Version="2.0.0" />
<PackageVersion Include="Pandatech.EFCore.AuditBase" Version="1.1.0" />
<PackageVersion Include="PandaTech.FileExporter" Version="3.3.1" />
<PackageVersion Include="PandaTech.FileExporter" Version="3.3.2" />
<PackageVersion Include="Pandatech.FluentMinimalApiMapper" Version="1.1.0" />
<PackageVersion Include="Pandatech.CommissionCalculator" Version="3.3.0" />
<PackageVersion Include="Pandatech.Communicator" Version="1.0.6" />
Expand All @@ -47,7 +48,7 @@
<PackageVersion Include="Pandatech.MassTransit.PostgresOutbox" Version="1.0.7" />
<PackageVersion Include="Pandatech.PandaVaultClient" Version="3.1.0" />
<PackageVersion Include="Pandatech.RegexBox" Version="2.0.1" />
<PackageVersion Include="Pandatech.ResponseCrafter" Version="3.0.0" />
<PackageVersion Include="Pandatech.ResponseCrafter" Version="3.0.1" />
<PackageVersion Include="Serilog.AspNetCore" Version="8.0.2" />
<PackageVersion Include="SonarAnalyzer.CSharp" Version="9.32.0.97167">
<PrivateAssets>all</PrivateAssets>
Expand Down
11 changes: 6 additions & 5 deletions src/Pandatech.CleanArchitecture.Api/Extensions/StartupLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ namespace Pandatech.CleanArchitecture.Api.Extensions;

public static class StartupLogger
{
private static readonly Stopwatch _stopwatch = new();
private static readonly Stopwatch Stopwatch = new();

public static WebApplicationBuilder LogStartAttempt(this WebApplicationBuilder builder)
{
_stopwatch.Start();
Stopwatch.Start();
var now = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture);
Console.WriteLine(JsonConvert.SerializeObject(new
{
Expand All @@ -22,16 +22,17 @@ public static WebApplicationBuilder LogStartAttempt(this WebApplicationBuilder b
return builder;
}

public static void LogStartSuccess()
public static WebApplication LogStartSuccess(this WebApplication app)
{
_stopwatch.Stop();
Stopwatch.Stop();
var now = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture);
var initializationTime = Math.Round(_stopwatch.Elapsed.TotalMilliseconds / 1000, 2);
var initializationTime = Math.Round(Stopwatch.Elapsed.TotalMilliseconds / 1000, 2);
Console.WriteLine(JsonConvert.SerializeObject(new
{
Timestamp = now,
Event = "ApplicationStartSuccess",
InitializationTime = $"{initializationTime} seconds"
}));
return app;
}
}
2 changes: 1 addition & 1 deletion src/Pandatech.CleanArchitecture.Api/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,5 @@
app.MapEndpoints();

AssemblyRegistry.RemoveAllAssemblies();
StartupLogger.LogStartSuccess();
app.LogStartSuccess();
app.Run();
3 changes: 2 additions & 1 deletion src/Pandatech.CleanArchitecture.Api/appsettings.Local.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"ConnectionStrings": {
"Postgres": "Server=localhost;Port=5432;Database=pandatech_clean_architecture;User Id=test;Password=test;Pooling=true;",
"Redis": "localhost:6379",
"RabbitMq": "amqp://test:test@localhost:5672"
"RabbitMq": "amqp://test:test@localhost:5672",
"PersistentStorage": "/persistence"
},
"Security": {
"SuperUser": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ public static WebApplicationBuilder AddMediatrWithBehaviors(this WebApplicationB
{
var assemblies = AssemblyRegistry.GetAllAssemblies();
builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(assemblies.ToArray()));
builder.Services.AddScoped(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
builder.Services.AddScoped(typeof(IPipelineBehavior<,>), typeof(ValidationBehaviorWithoutResponse<,>));
builder.Services.AddScoped(typeof(IPipelineBehavior<,>), typeof(ValidationBehaviorWithResponse<,>));
builder.Services.AddValidatorsFromAssemblies(assemblies);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,4 @@
</PackageReference>
</ItemGroup>


<ItemGroup>
<PackageVersion Update="MediatR" Version="12.2.0"/>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public static WebApplicationBuilder AddInfrastructureLayer(this WebApplicationBu
.AddGridify()
.AddRepositories()
.AddCommunicator()
.AddResilienceDefaultPipeline()
.AddDistributedCache(options =>
{
options.RedisConnectionString = builder.Configuration.GetRedisUrl();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using EFCore.PostgresExtensions.Extensions;
using EntityFramework.Exceptions.PostgreSQL;
using Microsoft.AspNetCore.Builder;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
Expand All @@ -18,6 +19,7 @@ public static WebApplicationBuilder AddPostgresContext(this WebApplicationBuilde
builder.Services.AddDbContextPool<PostgresContext>(options =>
options.UseNpgsql(connectionString)
.UseQueryLocks()
.UseExceptionProcessor()
.UseSnakeCaseNamingConvention());
return builder;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ public static WebApplicationBuilder ConfigureOpenTelemetry(this WebApplicationBu
.WithTracing(tracing =>
{
tracing.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddGrpcClientInstrumentation();
.AddHttpClientInstrumentation();
});

return builder;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Http.Resilience;
using Pandatech.CleanArchitecture.Infrastructure.Helpers;
using Polly;

namespace Pandatech.CleanArchitecture.Infrastructure.Extensions;

public static class ResilienceExtensions
{
public static WebApplicationBuilder AddResilienceDefaultPipeline(this WebApplicationBuilder builder)
{
builder.Services.AddResiliencePipeline(ResilienceDefaultPipelineProvider.DefaultPipelineName,
pipelineBuilder =>
{
pipelineBuilder.AddRetry(ResilienceDefaultPipelineProvider.DefaultNetworkRetryOptions)
.AddRetry(ResilienceDefaultPipelineProvider.TooManyRequestsRetryOptions)
.AddCircuitBreaker(ResilienceDefaultPipelineProvider.DefaultCircuitBreakerOptions)
.AddTimeout(TimeSpan.FromSeconds(8));
});
return builder;
}

public static IHttpResiliencePipelineBuilder AddResilienceDefaultPipeline(this IHttpClientBuilder builder)
{
return builder.AddResilienceHandler("DefaultPipeline",
resilienceBuilder =>
{
resilienceBuilder.AddRetry(ResilienceHttpOptions.DefaultTooManyRequestsRetryOptions)
.AddRetry(ResilienceHttpOptions.DefaultNetworkRetryOptions)
.AddCircuitBreaker(ResilienceHttpOptions.DefaultCircuitBreakerOptions)
.AddTimeout(TimeSpan.FromSeconds(8));
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System.Net;
using Polly;
using Polly.CircuitBreaker;
using Polly.Registry;
using Polly.Retry;

namespace Pandatech.CleanArchitecture.Infrastructure.Helpers;

public static class ResilienceDefaultPipelineProvider
{
public static ResiliencePipeline GetDefaultPipeline(
this ResiliencePipelineProvider<string> resiliencePipelineProvider)
{
return resiliencePipelineProvider.GetPipeline(DefaultPipelineName);
}

internal const string DefaultPipelineName = "DefaultPipeline";

internal static RetryStrategyOptions TooManyRequestsRetryOptions =>
new()
{
MaxRetryAttempts = 5,
BackoffType = DelayBackoffType.Exponential,
UseJitter = true,
Delay = TimeSpan.FromMilliseconds(3000),
ShouldHandle = new PredicateBuilder()
.Handle<HttpRequestException>(exception => exception.StatusCode == HttpStatusCode.TooManyRequests)
};

internal static RetryStrategyOptions DefaultNetworkRetryOptions =>
new()
{
MaxRetryAttempts = 7,
BackoffType = DelayBackoffType.Exponential,
UseJitter = true,
Delay = TimeSpan.FromMilliseconds(800),
ShouldHandle = new PredicateBuilder()
.Handle<HttpRequestException>(exception => exception.StatusCode == HttpStatusCode.RequestTimeout ||
(int)exception.StatusCode! >= 500)
};

internal static CircuitBreakerStrategyOptions DefaultCircuitBreakerOptions =>
new()
{
FailureRatio = 0.5,
SamplingDuration = TimeSpan.FromSeconds(30),
MinimumThroughput = 200,
BreakDuration = TimeSpan.FromSeconds(45),
ShouldHandle = new PredicateBuilder().Handle<Exception>()
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
using System.Net;
using Microsoft.Extensions.Http.Resilience;
using Polly;

namespace Pandatech.CleanArchitecture.Infrastructure.Helpers;

internal static class ResilienceHttpOptions
{
public static HttpRetryStrategyOptions DefaultTooManyRequestsRetryOptions =>
new()
{
MaxRetryAttempts = 5,
BackoffType = DelayBackoffType.Exponential,
UseJitter = true,
Delay = TimeSpan.FromMilliseconds(3000),
ShouldHandle = args =>
{
if (args.Outcome.Exception is HttpRequestException httpException)
{
return ValueTask.FromResult((int)httpException.StatusCode! == 429);
}
if (args.Outcome.Result is not null && args.Outcome.Result.StatusCode == HttpStatusCode.TooManyRequests)
{
return ValueTask.FromResult(true);
}
return ValueTask.FromResult(false);
},
DelayGenerator = args =>
{
if (args.Outcome.Result is null)
{
return ValueTask.FromResult<TimeSpan?>(null);
}
if (!args.Outcome.Result.Headers.TryGetValues("Retry-After", out var values))
{
return ValueTask.FromResult<TimeSpan?>(null);
}
var retryAfterValue = values.FirstOrDefault();
if (int.TryParse(retryAfterValue, out var retryAfterSeconds))
{
return ValueTask.FromResult<TimeSpan?>(TimeSpan.FromSeconds(retryAfterSeconds));
}
if (!DateTimeOffset.TryParseExact(retryAfterValue,
"R", // RFC1123 pattern
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None,
out var retryAfterDate))
{
return ValueTask.FromResult<TimeSpan?>(null);
}
var retryDelay = retryAfterDate - DateTimeOffset.UtcNow;
return ValueTask.FromResult<TimeSpan?>(retryDelay > TimeSpan.Zero ? retryDelay : TimeSpan.MinValue);
}
};

public static HttpRetryStrategyOptions DefaultNetworkRetryOptions =>
new()
{
MaxRetryAttempts = 7,
BackoffType = DelayBackoffType.Exponential,
UseJitter = true,
Delay = TimeSpan.FromMilliseconds(800),
ShouldHandle = args =>
{
if (args.Outcome.Exception is HttpRequestException httpException)
{
return ValueTask.FromResult((int)httpException.StatusCode! >= 500 ||
(int)httpException.StatusCode! == 408);
}
return ValueTask.FromResult(args.Outcome.Result is not null &&
(args.Outcome.Result.StatusCode == HttpStatusCode.RequestTimeout ||
(int)args.Outcome.Result.StatusCode >= 500));
}
};

public static HttpCircuitBreakerStrategyOptions DefaultCircuitBreakerOptions =>
new()
{
FailureRatio = 0.5,
SamplingDuration = TimeSpan.FromSeconds(30),
MinimumThroughput = 200,
BreakDuration = TimeSpan.FromSeconds(45),
ShouldHandle = args =>
{
if (args.Outcome.Exception is not null)
{
return ValueTask.FromResult(true);
}
return args.Outcome.Result is null
? ValueTask.FromResult(false)
: ValueTask.FromResult(!args.Outcome.Result.IsSuccessStatusCode);
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<ItemGroup>
<PackageReference Include="EFCore.NamingConventions"/>
<PackageReference Include="Elastic.CommonSchema.Serilog" />
<PackageReference Include="EntityFrameworkCore.Exceptions.PostgreSQL" />
<PackageReference Include="Hangfire.Dashboard.Basic.Authentication"/>
<PackageReference Include="Hangfire.EntityFrameworkCore"/>
<PackageReference Include="Hangfire.PostgreSql"/>
Expand All @@ -16,12 +17,12 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Http.Resilience" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL"/>
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol"/>
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore"/>
<PackageReference Include="OpenTelemetry.Extensions.Hosting"/>
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore"/>
<PackageReference Include="OpenTelemetry.Instrumentation.GrpcNetClient"/>
<PackageReference Include="OpenTelemetry.Instrumentation.Http"/>
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime"/>
<PackageReference Include="AspNetCore.HealthChecks.NpgSql"/>
Expand Down

0 comments on commit ad52da7

Please sign in to comment.