66 lines
2.6 KiB
C#
66 lines
2.6 KiB
C#
using Microsoft.Extensions.Options;
|
|
using Tiku.Application.Security;
|
|
using Tiku.Application.Tenancy;
|
|
|
|
namespace Tiku.Api.Background;
|
|
|
|
internal sealed class DevelopmentTenantDomainLifecycleHostedService(
|
|
IServiceScopeFactory scopeFactory,
|
|
IOptions<DomainLifecycleOptions> domainOptions,
|
|
ILogger<DevelopmentTenantDomainLifecycleHostedService> logger) : BackgroundService
|
|
{
|
|
private readonly DomainLifecycleOptions options = domainOptions.Value;
|
|
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
{
|
|
if (!options.EnableDevelopmentLocalhostBypass) return;
|
|
|
|
var activeInterval = TimeSpan.FromSeconds(Math.Clamp(options.PollSeconds, 1, 3600));
|
|
var maxIdleInterval = TimeSpan.FromSeconds(Math.Clamp(
|
|
options.MaxIdlePollSeconds,
|
|
(int)activeInterval.TotalSeconds,
|
|
3600));
|
|
var consecutiveIdleIterations = 0;
|
|
while (!stoppingToken.IsCancellationRequested)
|
|
{
|
|
try
|
|
{
|
|
await using var scope = scopeFactory.CreateAsyncScope();
|
|
scope.ServiceProvider.GetRequiredService<ITenantContextInitializer>()
|
|
.InitializeSystem(null, "Development .localhost domain lifecycle");
|
|
var processed = await scope.ServiceProvider
|
|
.GetRequiredService<ITenantDomainLifecycleService>()
|
|
.ProcessPendingAsync(stoppingToken);
|
|
consecutiveIdleIterations = processed == 0 ? consecutiveIdleIterations + 1 : 0;
|
|
if (processed > 0)
|
|
logger.LogInformation("Processed {DomainCount} pending Development tenant domains.", processed);
|
|
}
|
|
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
|
|
{
|
|
break;
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
consecutiveIdleIterations++;
|
|
logger.LogError(exception, "Development tenant domain lifecycle iteration failed.");
|
|
}
|
|
|
|
await Task.Delay(
|
|
CalculateDelay(activeInterval, maxIdleInterval, consecutiveIdleIterations),
|
|
stoppingToken);
|
|
}
|
|
}
|
|
|
|
internal static TimeSpan CalculateDelay(
|
|
TimeSpan activeInterval,
|
|
TimeSpan maxIdleInterval,
|
|
int consecutiveIdleIterations)
|
|
{
|
|
if (consecutiveIdleIterations <= 1) return activeInterval;
|
|
|
|
var shift = Math.Min(consecutiveIdleIterations - 1, 20);
|
|
var delayTicks = activeInterval.Ticks * (1L << shift);
|
|
return TimeSpan.FromTicks(Math.Min(delayTicks, maxIdleInterval.Ticks));
|
|
}
|
|
}
|