Skip to content

Commit

Permalink
nuget add
Browse files Browse the repository at this point in the history
  • Loading branch information
HaikAsatryan committed Sep 13, 2024
1 parent d23c6da commit 484ecf3
Show file tree
Hide file tree
Showing 12 changed files with 213 additions and 26 deletions.
3 changes: 3 additions & 0 deletions src/Pandatech.VerticalSlices/AssemblyReference.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace Pandatech.VerticalSlices;

public record AssemblyReference();
13 changes: 7 additions & 6 deletions src/Pandatech.VerticalSlices/Pandatech.VerticalSlices.csproj
Original file line number Diff line number Diff line change
@@ -1,44 +1,45 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<ItemGroup>
<PackageReference Include="AspNetCore.HealthChecks.NpgSql" Version="8.0.1"/>
<PackageReference Include="AspNetCore.HealthChecks.NpgSql" Version="8.0.2" />
<PackageReference Include="AspNetCore.HealthChecks.Prometheus.Metrics" Version="8.0.1"/>
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="8.0.1"/>
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="8.0.2" />
<PackageReference Include="AspNetCore.HealthChecks.Redis" Version="8.0.1"/>
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="8.0.1"/>
<PackageReference Include="EFCore.NamingConventions" Version="8.0.3"/>
<PackageReference Include="Elastic.CommonSchema.Serilog" Version="8.11.1" />
<PackageReference Include="EntityFrameworkCore.Exceptions.PostgreSQL" Version="8.1.3" />
<PackageReference Include="FluentDateTime" Version="3.0.0"/>
<PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0"/>
<PackageReference Include="Hangfire" Version="1.8.14"/>
<PackageReference Include="Hangfire.Dashboard.Basic.Authentication" Version="7.0.1"/>
<PackageReference Include="Hangfire.EntityFrameworkCore" Version="0.6.0"/>
<PackageReference Include="Hangfire.PostgreSql" Version="1.20.9"/>
<PackageReference Include="MassTransit.RabbitMQ" Version="8.2.5" />
<PackageReference Include="MediatR" Version="12.4.0" />
<PackageReference Include="MediatR" Version="12.4.1" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.8" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers; buildtransitive" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.8" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers; buildtransitive" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="8.9.1" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4"/>
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0"/>
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.8.0-rc.1"/>
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0"/>
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0"/>
<PackageReference Include="OpenTelemetry.Instrumentation.GrpcNetClient" Version="1.8.0-beta.1"/>
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.9.0"/>
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.9.0"/>
<PackageReference Include="Pandatech.Communicator" Version="1.0.6" />
<PackageReference Include="Pandatech.Crypto" Version="2.5.0"/>
<PackageReference Include="Pandatech.DistributedCache" Version="1.2.3" />
<PackageReference Include="Pandatech.DistributedCache" Version="2.0.0" />
<PackageReference Include="Pandatech.EFCore.AuditBase" Version="1.1.0"/>
<PackageReference Include="PandaTech.FileExporter" Version="3.3.2" />
<PackageReference Include="Pandatech.FluentMinimalApiMapper" Version="1.1.0"/>
<PackageReference Include="Pandatech.GridifyExtensions" Version="1.5.4" />
<PackageReference Include="Pandatech.MassTransit.PostgresOutbox" Version="1.0.7"/>
<PackageReference Include="Pandatech.PandaVaultClient" Version="3.1.0"/>
<PackageReference Include="Pandatech.RegexBox" Version="2.0.1" />
<PackageReference Include="Pandatech.ResponseCrafter" Version="3.0.0"/>
<PackageReference Include="Pandatech.ResponseCrafter" Version="3.0.1" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.2" />
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.32.0.97167" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers; buildtransitive" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.7.3" />
Expand Down
12 changes: 3 additions & 9 deletions src/Pandatech.VerticalSlices/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
.ConfigureOpenTelemetry()
.AddEndpoints()
.AddGridify()
.AddResilienceDefaultPipeline()
.AddCommunicator()
.AddDistributedCache(options =>
{
Expand Down Expand Up @@ -63,7 +64,7 @@
app.MapPandaEndpoints();
app.MapEndpoints();

StartupLogger.LogStartSuccess();
app.LogStartSuccess();
app.Run();

//todo Set appropriate name in github repo (ex. be-pt-pandatech-website).
Expand All @@ -75,11 +76,4 @@
//todo Delete health checks and other configs of unrelated services. For example you might not need RMQ or Redis in this project.
//todo Update all Nuget packages.
//todo Include all required configurations in appsettings{environment}.json.
//todo Update ReadMm.md file.

//Delete below rows if you have no integration Pandatech.VerticalSlices.Tests in your solution.

namespace Pandatech.VerticalSlices
{
public class Program;
}
//todo Update ReadMm.md file.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using EFCore.PostgresExtensions.Extensions;
using EntityFramework.Exceptions.PostgreSQL;
using Microsoft.EntityFrameworkCore;
using Pandatech.VerticalSlices.Context;
using Pandatech.VerticalSlices.SharedKernel.Helpers;
Expand All @@ -15,6 +16,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 @@ -27,8 +27,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,33 @@
using Microsoft.Extensions.Http.Resilience;
using Pandatech.VerticalSlices.SharedKernel.Helpers;
using Polly;

namespace Pandatech.VerticalSlices.SharedKernel.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
Expand Up @@ -22,7 +22,7 @@ public static WebApplicationBuilder LogStartAttempt(this WebApplicationBuilder b
return builder;
}

public static void LogStartSuccess()
public static WebApplication LogStartSuccess(this WebApplication app)
{
_stopwatch.Stop();
var now = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture);
Expand All @@ -33,5 +33,7 @@ public static void LogStartSuccess()
Event = "ApplicationStartSuccess",
InitializationTime = $"{initializationTime} seconds"
}));

return app;
}
}
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.VerticalSlices.SharedKernel.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.VerticalSlices.SharedKernel.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);
}
};
}
3 changes: 2 additions & 1 deletion src/Pandatech.VerticalSlices/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_vertical_slices;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 @@ -12,7 +12,7 @@

namespace Pandatech.VerticalSlices.Tests.Configurations;

public class ApiFactory : WebApplicationFactory<Program>, IAsyncLifetime
public class ApiFactory : WebApplicationFactory<AssemblyReference>, IAsyncLifetime
{
private readonly PostgreSqlContainer _dbContainer = new PostgreSqlBuilder()
.Build();
Expand Down Expand Up @@ -88,8 +88,6 @@ private void SetEnvironments()
Environment.SetEnvironmentVariable("RABBITMQ_ROUTING_KEY_DLX", "panda-dlx");
Environment.SetEnvironmentVariable("RABBITMQ_QUEUE_NAME_DLX", "panda-dlx");
Environment.SetEnvironmentVariable("RABBITMQ_URI", "amqp://guest:guest@localhost:5672");
Environment.SetEnvironmentVariable("ELASTIC_SEARCH_URL", "http://localhost:9200");
Environment.SetEnvironmentVariable("ELASTIC_INDEX_NAME", "panda");
Environment.SetEnvironmentVariable("CORS_ALLOWED_ORIGINS", "http://localhost:3000");
Environment.SetEnvironmentVariable("USER_MANAGEMENT_ADDRESS", "http://localhost:5000");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Bogus" Version="35.6.0" />
<PackageReference Include="FluentAssertions" Version="6.12.0"/>
<PackageReference Include="Bogus" Version="35.6.1" />
<PackageReference Include="FluentAssertions" Version="6.12.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.8" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="Respawn" Version="6.2.1"/>
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.32.0.97167">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Testcontainers.PostgreSql" Version="3.9.0"/>
<PackageReference Include="Testcontainers.PostgreSql" Version="3.10.0" />
<PackageReference Include="xunit" Version="2.9.0"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down

0 comments on commit 484ecf3

Please sign in to comment.