forked from gongxuegit/tiku-backend.net
feat: enforce tenant isolation and shared question bank
This commit is contained in:
@@ -1,6 +1,17 @@
|
||||
using Tiku.Application;
|
||||
using Tiku.Application.Tenancy;
|
||||
using Tiku.Infrastructure;
|
||||
using Tiku.Worker;
|
||||
|
||||
var builder = Host.CreateApplicationBuilder(args);
|
||||
var connectionString = builder.Configuration.GetConnectionString("Database")
|
||||
?? builder.Configuration["DATABASE_URL"]
|
||||
?? throw new InvalidOperationException(
|
||||
"Database connection is required. Configure ConnectionStrings:Database or DATABASE_URL.");
|
||||
builder.Services.AddApplication();
|
||||
builder.Services.AddInfrastructure(connectionString);
|
||||
builder.Services.AddOptions<DomainLifecycleOptions>()
|
||||
.Bind(builder.Configuration.GetSection("TenantDomains"));
|
||||
builder.Services.AddHostedService<Worker>();
|
||||
|
||||
var host = builder.Build();
|
||||
|
||||
@@ -1,16 +1,43 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using Tiku.Application.Security;
|
||||
using Tiku.Application.Tenancy;
|
||||
|
||||
namespace Tiku.Worker;
|
||||
|
||||
public class Worker(ILogger<Worker> logger) : BackgroundService
|
||||
public class Worker(
|
||||
IServiceScopeFactory scopeFactory,
|
||||
IOptions<DomainLifecycleOptions> options,
|
||||
ILogger<Worker> logger) : BackgroundService
|
||||
{
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
if (logger.IsEnabled(LogLevel.Information))
|
||||
try
|
||||
{
|
||||
logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
|
||||
await using var scope = scopeFactory.CreateAsyncScope();
|
||||
scope.ServiceProvider.GetRequiredService<ITenantContextInitializer>()
|
||||
.InitializeSystem(null, "Tenant domain DNS and TLS lifecycle worker");
|
||||
var processed = await scope.ServiceProvider
|
||||
.GetRequiredService<ITenantDomainLifecycleService>()
|
||||
.ProcessPendingAsync(stoppingToken);
|
||||
if (processed > 0)
|
||||
{
|
||||
logger.LogInformation("Processed {Count} pending tenant domains.", processed);
|
||||
}
|
||||
}
|
||||
await Task.Delay(1000, stoppingToken);
|
||||
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
logger.LogError(exception, "Tenant domain lifecycle processing failed.");
|
||||
}
|
||||
|
||||
await Task.Delay(
|
||||
TimeSpan.FromSeconds(Math.Clamp(options.Value.PollSeconds, 10, 3600)),
|
||||
stoppingToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
{
|
||||
"TenantDomains": {
|
||||
"Enabled": true,
|
||||
"PollSeconds": 60,
|
||||
"BatchSize": 50,
|
||||
"DnsJsonEndpoint": "https://cloudflare-dns.com/dns-query",
|
||||
"VerificationRecordPrefix": "_tiku-verification",
|
||||
"AllowedCnameTargets": [],
|
||||
"GatewayBaseUrl": null,
|
||||
"GatewayApiKey": null
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
|
||||
Reference in New Issue
Block a user