| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283 |
- using Application.Abstractions.Data;
- using Application.Abstractions.YouTube;
- using Microsoft.EntityFrameworkCore;
- using Microsoft.Extensions.DependencyInjection;
- using Microsoft.Extensions.Hosting;
- using Microsoft.Extensions.Logging;
- namespace Infrastructure.YouTube;
- /// <summary>
- /// 1시간마다 활성 채널의 YouTube 정보를 갱신하여 Redis 캐시에 저장
- /// channels.list는 id 파라미터로 최대 50개 채널을 한 번에 조회 가능 (1 unit/요청)
- /// 채널 50개 이하 → 1시간에 1 unit만 사용
- /// </summary>
- internal sealed class YouTubeChannelCacheRefreshService(
- IServiceScopeFactory scopeFactory,
- IYouTubeApiService youTubeApi,
- IYouTubeChannelCache channelCache,
- ILogger<YouTubeChannelCacheRefreshService> logger
- ) : BackgroundService
- {
- private static readonly TimeSpan RefreshInterval = TimeSpan.FromHours(1);
- private static readonly TimeSpan InitialDelay = TimeSpan.FromSeconds(15);
- private const int BatchSize = 50; // YouTube API 최대 50개/요청
- protected override async Task ExecuteAsync(CancellationToken stoppingToken)
- {
- await Task.Delay(InitialDelay, stoppingToken);
- logger.LogInformation("[ChannelCache] 채널 캐시 갱신 서비스 시작 — 주기: {Interval}시간", RefreshInterval.TotalHours);
- while (!stoppingToken.IsCancellationRequested)
- {
- try
- {
- await RefreshAllChannelsAsync(stoppingToken);
- }
- catch (Exception ex)
- {
- logger.LogError(ex, "[ChannelCache] 채널 캐시 갱신 중 오류");
- }
- await Task.Delay(RefreshInterval, stoppingToken);
- }
- }
- private async Task RefreshAllChannelsAsync(CancellationToken ct)
- {
- // DB에서 활성 채널 SID 목록 조회 (Scoped DbContext)
- List<string> channelIds;
- using (var scope = scopeFactory.CreateScope())
- {
- var db = scope.ServiceProvider.GetRequiredService<IAppDbContext>();
- channelIds = await db.Channel.AsNoTracking().Where(c => c.IsActive).Select(c => c.SID).ToListAsync(ct);
- }
- if (channelIds.Count == 0)
- {
- return;
- }
- // 50개씩 배치로 YouTube API 호출
- var refreshed = 0;
- for (var i = 0; i < channelIds.Count; i += BatchSize)
- {
- var batch = channelIds.Skip(i).Take(BatchSize).ToList();
- var results = await youTubeApi.GetChannelsByIdsAsync(batch, ct);
- foreach (var info in results)
- {
- await channelCache.SetAsync(info);
- refreshed++;
- }
- // 배치 간 1초 대기 (API rate limit 방어)
- if (i + BatchSize < channelIds.Count)
- {
- await Task.Delay(TimeSpan.FromSeconds(1), ct);
- }
- }
- logger.LogInformation("[ChannelCache] {Refreshed}/{Total} 채널 캐시 갱신 완료", refreshed, channelIds.Count);
- }
- }
|