using Application.Abstractions.Cache; using Application.Abstractions.YouTube; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using StackExchange.Redis; namespace Infrastructure.YouTube; /// /// PubSubHubbub 구독 자동 갱신 BackgroundService /// 구독은 약 10일 후 만료 → 7일마다 재구독 /// internal sealed class YouTubePubSubRenewalService( IYouTubePubSubService pubSubService, IConnectionMultiplexer redis, ILogger logger ) : BackgroundService { private static readonly TimeSpan RenewalInterval = TimeSpan.FromDays(7); private static readonly TimeSpan InitialDelay = TimeSpan.FromSeconds(30); protected override async Task ExecuteAsync(CancellationToken stoppingToken) { await Task.Delay(InitialDelay, stoppingToken); logger.LogInformation("[PubSub Renewal] 서비스 시작 — 갱신 주기: {Interval}일", RenewalInterval.TotalDays); while (!stoppingToken.IsCancellationRequested) { try { await RenewAllSubscriptionsAsync(stoppingToken); } catch (Exception ex) { logger.LogError(ex, "[PubSub Renewal] 구독 갱신 중 오류"); } await Task.Delay(RenewalInterval, stoppingToken); } } private async Task RenewAllSubscriptionsAsync(CancellationToken ct) { var db = redis.GetDatabase(); var channelIds = await db.SetMembersAsync(CacheKeys.YouTubePubSubChannels); if (channelIds.Length == 0) { logger.LogInformation("[PubSub Renewal] 구독 중인 채널 없음"); return; } var renewed = 0; foreach (var channelId in channelIds) { var id = channelId.ToString(); var success = await pubSubService.SubscribeAsync(id, ct); if (success) { renewed++; } // 요청 간 1초 간격 await Task.Delay(TimeSpan.FromSeconds(1), ct); } logger.LogInformation("[PubSub Renewal] {Renewed}/{Total} 채널 구독 갱신 완료", renewed, channelIds.Length); } }