97 lines
4.1 KiB
C#
97 lines
4.1 KiB
C#
using Microsoft.Extensions.Options;
|
|
using Tiku.Application.Jobs;
|
|
using Tiku.Application.PlatformBilling;
|
|
using Tiku.Application.Security;
|
|
using Tiku.Application.Tenancy;
|
|
using Tiku.Infrastructure.Messaging;
|
|
|
|
namespace Tiku.Worker;
|
|
|
|
public class Worker(
|
|
IServiceScopeFactory scopeFactory,
|
|
IOptions<DomainLifecycleOptions> options,
|
|
MessagingOptions messagingOptions,
|
|
ILogger<Worker> logger) : BackgroundService
|
|
{
|
|
private readonly string workerId = $"{Environment.MachineName}:{Guid.NewGuid():N}";
|
|
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
{
|
|
while (!stoppingToken.IsCancellationRequested)
|
|
{
|
|
try
|
|
{
|
|
var domainCount = await ProcessTenantDomainsAsync(stoppingToken);
|
|
var subscriptionCount = await ProcessSaasSubscriptionsAsync(stoppingToken);
|
|
var usageReconciliationCount = await ProcessFeatureUsageReconciliationAsync(stoppingToken);
|
|
var jobCount = await ProcessBackgroundJobsAsync(stoppingToken);
|
|
if (domainCount > 0 || subscriptionCount > 0 || usageReconciliationCount > 0 || jobCount > 0)
|
|
{
|
|
logger.LogInformation(
|
|
"Worker processed {DomainCount} pending tenant domains, {SubscriptionCount} SaaS subscriptions, {UsageReconciliationCount} tenant usage reconciliations, and {JobCount} background jobs.",
|
|
domainCount,
|
|
subscriptionCount,
|
|
usageReconciliationCount,
|
|
jobCount);
|
|
}
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
|
|
private async Task<int> ProcessTenantDomainsAsync(CancellationToken stoppingToken)
|
|
{
|
|
await using var scope = scopeFactory.CreateAsyncScope();
|
|
scope.ServiceProvider.GetRequiredService<ITenantContextInitializer>()
|
|
.InitializeSystem(null, "Tenant domain DNS and TLS lifecycle worker");
|
|
return await scope.ServiceProvider
|
|
.GetRequiredService<ITenantDomainLifecycleService>()
|
|
.ProcessPendingAsync(stoppingToken);
|
|
}
|
|
|
|
private async Task<int> ProcessBackgroundJobsAsync(CancellationToken stoppingToken)
|
|
{
|
|
await using var scope = scopeFactory.CreateAsyncScope();
|
|
scope.ServiceProvider.GetRequiredService<ITenantContextInitializer>()
|
|
.InitializeSystem(null, "Background job lease worker");
|
|
return await scope.ServiceProvider
|
|
.GetRequiredService<IBackgroundJobService>()
|
|
.ProcessPendingAsync(
|
|
workerId,
|
|
20,
|
|
includeImmediateJobs: !messagingOptions.IsConfigured,
|
|
cancellationToken: stoppingToken);
|
|
}
|
|
|
|
private async Task<int> ProcessSaasSubscriptionsAsync(CancellationToken stoppingToken)
|
|
{
|
|
await using var scope = scopeFactory.CreateAsyncScope();
|
|
scope.ServiceProvider.GetRequiredService<ITenantContextInitializer>()
|
|
.InitializeSystem(null, "SaaS subscription lifecycle discovery worker");
|
|
return await scope.ServiceProvider
|
|
.GetRequiredService<ISaasSubscriptionLifecycleService>()
|
|
.ProcessDueAsync(cancellationToken: stoppingToken);
|
|
}
|
|
|
|
private async Task<int> ProcessFeatureUsageReconciliationAsync(CancellationToken stoppingToken)
|
|
{
|
|
await using var scope = scopeFactory.CreateAsyncScope();
|
|
scope.ServiceProvider.GetRequiredService<ITenantContextInitializer>()
|
|
.InitializeSystem(null, "Tenant feature usage reconciliation discovery worker");
|
|
return await scope.ServiceProvider
|
|
.GetRequiredService<IFeatureUsageReconciliationService>()
|
|
.ProcessDueAsync(stoppingToken);
|
|
}
|
|
}
|