Compare commits
2 Commits
965b693a19
...
a1440baf3d
Author | SHA1 | Date | |
---|---|---|---|
a1440baf3d | |||
ddd99ec703 |
@@ -27,13 +27,12 @@ namespace OpenCand.API.Config
|
|||||||
// Default policy: 200 requests per minute with burst of 100
|
// Default policy: 200 requests per minute with burst of 100
|
||||||
options.AddFixedWindowLimiter(policyName: DefaultPolicy, options =>
|
options.AddFixedWindowLimiter(policyName: DefaultPolicy, options =>
|
||||||
{
|
{
|
||||||
options.PermitLimit = 200;
|
options.PermitLimit = 400;
|
||||||
options.Window = TimeSpan.FromMinutes(1);
|
options.Window = TimeSpan.FromMinutes(1);
|
||||||
options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
|
options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
|
||||||
options.QueueLimit = 100; // Burst capacity
|
options.QueueLimit = 100; // Burst capacity
|
||||||
});
|
});
|
||||||
|
|
||||||
// Candidato Search policy: 300 requests per minute with burst of 200
|
|
||||||
options.AddFixedWindowLimiter(policyName: CandidatoSearchPolicy, options =>
|
options.AddFixedWindowLimiter(policyName: CandidatoSearchPolicy, options =>
|
||||||
{
|
{
|
||||||
options.PermitLimit = 300;
|
options.PermitLimit = 300;
|
||||||
@@ -42,22 +41,12 @@ namespace OpenCand.API.Config
|
|||||||
options.QueueLimit = 200; // Burst capacity
|
options.QueueLimit = 200; // Burst capacity
|
||||||
});
|
});
|
||||||
|
|
||||||
// CPF Reveal policy: 15 requests per minute without burst
|
|
||||||
options.AddFixedWindowLimiter(policyName: CpfRevealPolicy, options =>
|
options.AddFixedWindowLimiter(policyName: CpfRevealPolicy, options =>
|
||||||
{
|
{
|
||||||
options.PermitLimit = 15;
|
options.PermitLimit = 20;
|
||||||
options.Window = TimeSpan.FromMinutes(1);
|
options.Window = TimeSpan.FromMinutes(1);
|
||||||
options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
|
options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
|
||||||
options.QueueLimit = 0; // No burst
|
options.QueueLimit = 5; // Burst capacity
|
||||||
});
|
|
||||||
|
|
||||||
// CPF Reveal policy: 25 requests per minute with 10 burst
|
|
||||||
options.AddFixedWindowLimiter(policyName: EstatisticaPolicy, options =>
|
|
||||||
{
|
|
||||||
options.PermitLimit = 25;
|
|
||||||
options.Window = TimeSpan.FromMinutes(1);
|
|
||||||
options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
|
|
||||||
options.QueueLimit = 10; // No burst
|
|
||||||
});
|
});
|
||||||
|
|
||||||
options.OnRejected = async (context, token) =>
|
options.OnRejected = async (context, token) =>
|
||||||
@@ -67,7 +56,7 @@ namespace OpenCand.API.Config
|
|||||||
var retryAfter = GetRetryAfter(context);
|
var retryAfter = GetRetryAfter(context);
|
||||||
if (retryAfter.HasValue)
|
if (retryAfter.HasValue)
|
||||||
{
|
{
|
||||||
context.HttpContext.Response.Headers.Add("Retry-After", retryAfter.Value.ToString());
|
context.HttpContext.Response.Headers.Append("Retry-After", retryAfter.Value.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
await context.HttpContext.Response.WriteAsync(
|
await context.HttpContext.Response.WriteAsync(
|
||||||
|
@@ -1,10 +1,13 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.RateLimiting;
|
||||||
|
using OpenCand.API.Config;
|
||||||
|
|
||||||
namespace OpenCand.API.Controllers
|
namespace OpenCand.API.Controllers
|
||||||
{
|
{
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("v1/[controller]")]
|
[Route("v1/[controller]")]
|
||||||
[Produces("application/json")]
|
[Produces("application/json")]
|
||||||
|
[EnableRateLimiting(RateLimitingConfig.DefaultPolicy)]
|
||||||
public class BaseController : Controller
|
public class BaseController : Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.RateLimiting;
|
using Microsoft.AspNetCore.RateLimiting;
|
||||||
using Microsoft.VisualBasic;
|
|
||||||
using OpenCand.API.Config;
|
using OpenCand.API.Config;
|
||||||
using OpenCand.API.Model;
|
using OpenCand.API.Model;
|
||||||
using OpenCand.API.Services;
|
using OpenCand.API.Services;
|
||||||
@@ -9,7 +8,6 @@ using OpenCand.Core.Utils;
|
|||||||
|
|
||||||
namespace OpenCand.API.Controllers
|
namespace OpenCand.API.Controllers
|
||||||
{
|
{
|
||||||
[EnableRateLimiting(RateLimitingConfig.DefaultPolicy)]
|
|
||||||
public class CandidatoController : BaseController
|
public class CandidatoController : BaseController
|
||||||
{
|
{
|
||||||
private readonly OpenCandService openCandService;
|
private readonly OpenCandService openCandService;
|
||||||
|
@@ -1,12 +1,10 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.RateLimiting;
|
|
||||||
using OpenCand.API.Config;
|
|
||||||
using OpenCand.API.Model;
|
using OpenCand.API.Model;
|
||||||
using OpenCand.API.Services;
|
using OpenCand.API.Services;
|
||||||
|
using static OpenCand.API.Model.GetValueSumRequest;
|
||||||
|
|
||||||
namespace OpenCand.API.Controllers
|
namespace OpenCand.API.Controllers
|
||||||
{
|
{
|
||||||
[EnableRateLimiting(RateLimitingConfig.EstatisticaPolicy)]
|
|
||||||
public class EstatisticaController : BaseController
|
public class EstatisticaController : BaseController
|
||||||
{
|
{
|
||||||
private readonly EstatisticaService estatisticaService;
|
private readonly EstatisticaService estatisticaService;
|
||||||
|
@@ -36,7 +36,8 @@ namespace OpenCand.API
|
|||||||
{
|
{
|
||||||
FileProvider = new PhysicalFileProvider(Path.Combine(workingDir, "fotos_cand")),
|
FileProvider = new PhysicalFileProvider(Path.Combine(workingDir, "fotos_cand")),
|
||||||
RequestPath = "/assets/fotos"
|
RequestPath = "/assets/fotos"
|
||||||
}); app.UseHttpsRedirection();
|
});
|
||||||
|
app.UseHttpsRedirection();
|
||||||
|
|
||||||
// Use rate limiting middleware
|
// Use rate limiting middleware
|
||||||
app.UseRateLimiter();
|
app.UseRateLimiter();
|
||||||
@@ -53,11 +54,18 @@ namespace OpenCand.API
|
|||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
}
|
}
|
||||||
private static void SetupServices(WebApplicationBuilder builder)
|
|
||||||
|
private static void SetupServices(WebApplicationBuilder builder)
|
||||||
{
|
{
|
||||||
builder.Services.Configure<FotosSettings>(builder.Configuration.GetSection("FotosSettings"));
|
builder.Services.Configure<FotosSettings>(builder.Configuration.GetSection("FotosSettings"));
|
||||||
builder.Services.AddMemoryCache();
|
|
||||||
|
// Configure memory cache with size limit from appsettings
|
||||||
|
var sizeLimitMB = builder.Configuration.GetValue<int>("CacheSettings:SizeLimitMB", 15);
|
||||||
|
builder.Services.AddMemoryCache(options =>
|
||||||
|
{
|
||||||
|
options.SizeLimit = sizeLimitMB * 1024L * 1024L; // Convert MB to bytes
|
||||||
|
});
|
||||||
|
|
||||||
builder.Services.AddScoped(provider => new OpenCandRepository(provider.GetRequiredService<IConfiguration>(), provider.GetService<IMemoryCache>()));
|
builder.Services.AddScoped(provider => new OpenCandRepository(provider.GetRequiredService<IConfiguration>(), provider.GetService<IMemoryCache>()));
|
||||||
builder.Services.AddScoped(provider => new CandidatoRepository(provider.GetRequiredService<IConfiguration>(), provider.GetService<IMemoryCache>()));
|
builder.Services.AddScoped(provider => new CandidatoRepository(provider.GetRequiredService<IConfiguration>(), provider.GetService<IMemoryCache>()));
|
||||||
builder.Services.AddScoped(provider => new BemCandidatoRepository(provider.GetRequiredService<IConfiguration>(), provider.GetService<IMemoryCache>()));
|
builder.Services.AddScoped(provider => new BemCandidatoRepository(provider.GetRequiredService<IConfiguration>(), provider.GetService<IMemoryCache>()));
|
||||||
@@ -66,7 +74,7 @@ namespace OpenCand.API
|
|||||||
|
|
||||||
builder.Services.AddScoped<OpenCandService>();
|
builder.Services.AddScoped<OpenCandService>();
|
||||||
builder.Services.AddScoped<EstatisticaService>();
|
builder.Services.AddScoped<EstatisticaService>();
|
||||||
|
|
||||||
// Add cache preload background service
|
// Add cache preload background service
|
||||||
builder.Services.AddHostedService<CachePreloadService>();
|
builder.Services.AddHostedService<CachePreloadService>();
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Npgsql;
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace OpenCand.Repository
|
namespace OpenCand.Repository
|
||||||
{
|
{
|
||||||
@@ -56,7 +58,8 @@ namespace OpenCand.Repository
|
|||||||
_cache.Set(cacheKey, result, new MemoryCacheEntryOptions
|
_cache.Set(cacheKey, result, new MemoryCacheEntryOptions
|
||||||
{
|
{
|
||||||
SlidingExpiration = expiration ?? DefaultCacheExpiration,
|
SlidingExpiration = expiration ?? DefaultCacheExpiration,
|
||||||
Priority = priority ?? DefaultCachePriority
|
Priority = priority ?? DefaultCachePriority,
|
||||||
|
Size = EstimateSize(result)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +102,8 @@ namespace OpenCand.Repository
|
|||||||
_cache.Set(cacheKey, result, new MemoryCacheEntryOptions
|
_cache.Set(cacheKey, result, new MemoryCacheEntryOptions
|
||||||
{
|
{
|
||||||
SlidingExpiration = expiration ?? DefaultCacheExpiration,
|
SlidingExpiration = expiration ?? DefaultCacheExpiration,
|
||||||
Priority = priority ?? DefaultCachePriority
|
Priority = priority ?? DefaultCachePriority,
|
||||||
|
Size = EstimateSize(result)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,5 +137,25 @@ namespace OpenCand.Repository
|
|||||||
{
|
{
|
||||||
return identifier != null ? $"{entityName}_{identifier}" : entityName;
|
return identifier != null ? $"{entityName}_{identifier}" : entityName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Estimates the memory size of an object by serializing it to JSON
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Type of the object</typeparam>
|
||||||
|
/// <param name="obj">The object to estimate size for</param>
|
||||||
|
/// <returns>Estimated size in bytes</returns>
|
||||||
|
private static long EstimateSize<T>(T obj)
|
||||||
|
{
|
||||||
|
if (obj == null) return 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var json = JsonSerializer.Serialize(obj);
|
||||||
|
return Encoding.UTF8.GetByteCount(json);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return 1024; // Default estimate if serialization fails
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,5 +12,8 @@
|
|||||||
"Path": "./fotos_cand",
|
"Path": "./fotos_cand",
|
||||||
"ApiBasePath": "http://localhost:5299/assets/fotos"
|
"ApiBasePath": "http://localhost:5299/assets/fotos"
|
||||||
},
|
},
|
||||||
|
"CacheSettings": {
|
||||||
|
"SizeLimitMB": 15
|
||||||
|
},
|
||||||
"AllowedHosts": "*"
|
"AllowedHosts": "*"
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user