feat(auth): add Redis authorization caching
This commit is contained in:
@@ -7,6 +7,7 @@ using Tiku.Infrastructure;
|
||||
using Tiku.Infrastructure.Assets;
|
||||
using Tiku.Infrastructure.Storage;
|
||||
using Tiku.Infrastructure.Observability;
|
||||
using Tiku.Infrastructure.Security;
|
||||
using OpenTelemetry.Metrics;
|
||||
|
||||
namespace Tiku.Worker;
|
||||
@@ -29,8 +30,21 @@ internal static class WorkerDependencyInjection
|
||||
"Database connection is required outside Development. Configure ConnectionStrings:Database or DATABASE_URL."));
|
||||
builder.Services.AddApplication();
|
||||
builder.Services.AddInfrastructure(connectionString);
|
||||
var redisConnectionString = builder.Configuration.GetConnectionString("Redis") ?? builder.Configuration["REDIS_URL"];
|
||||
builder.Services.AddOptions<AuthorizationCacheOptions>()
|
||||
.Bind(builder.Configuration.GetSection(AuthorizationCacheOptions.SectionName));
|
||||
if (!string.IsNullOrWhiteSpace(redisConnectionString))
|
||||
{
|
||||
builder.Services.AddRedisSecurity(redisConnectionString, builder.Environment.EnvironmentName);
|
||||
}
|
||||
else if (builder.Environment.IsProduction())
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Redis is required in Production for authorization cache invalidation retries.");
|
||||
}
|
||||
var otlpEndpoint = builder.Configuration["OpenTelemetry:OtlpEndpoint"];
|
||||
var telemetry = builder.Services.AddOpenTelemetry().WithMetrics(metrics => metrics.AddMeter(WorkerTelemetry.MeterName));
|
||||
var telemetry = builder.Services.AddOpenTelemetry().WithMetrics(metrics =>
|
||||
metrics.AddMeter(WorkerTelemetry.MeterName, AuthorizationCacheTelemetry.MeterName));
|
||||
if (Uri.TryCreate(otlpEndpoint, UriKind.Absolute, out var endpoint))
|
||||
{
|
||||
telemetry.WithMetrics(metrics => metrics.AddOtlpExporter(options => options.Endpoint = endpoint));
|
||||
@@ -109,6 +123,7 @@ internal static class WorkerDependencyInjection
|
||||
builder.Services.AddHostedService<SaasSubscriptionWorker>();
|
||||
builder.Services.AddHostedService<FeatureUsageWorker>();
|
||||
builder.Services.AddHostedService<BackgroundJobsWorker>();
|
||||
builder.Services.AddHostedService<AuthorizationCacheInvalidationWorker>();
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
||||
@@ -262,3 +262,21 @@ internal sealed class BackgroundJobsWorker(
|
||||
.ProcessPendingAsync($"{workerId}:{index}", batchSize, includeImmediateJobs: true, cancellationToken: cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class AuthorizationCacheInvalidationWorker(
|
||||
IServiceScopeFactory scopeFactory,
|
||||
IPeriodicProcessorLock processorLock,
|
||||
WorkerStateReporter stateReporter,
|
||||
IOptions<WorkerOptions> options,
|
||||
ILogger<AuthorizationCacheInvalidationWorker> logger)
|
||||
: PeriodicWorker(logger, processorLock, stateReporter, "authorization-cache-invalidations",
|
||||
TimeSpan.FromSeconds(options.Value.JobPollSeconds), options.Value.Enabled)
|
||||
{
|
||||
protected override async Task<int> ProcessAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await using var scope = scopeFactory.CreateAsyncScope();
|
||||
InitializeSystem(scope.ServiceProvider, "Authorization cache invalidation worker");
|
||||
return await scope.ServiceProvider.GetRequiredService<IAuthorizationCacheInvalidationProcessor>()
|
||||
.ProcessPendingAsync(cancellationToken: cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user