| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283 |
- using Microsoft.EntityFrameworkCore;
- using bitforum.Constants;
- using bitforum.Services;
- namespace bitforum.Workers
- {
- public class MailQueueWorker : BackgroundService
- {
- private readonly ILogger<MailQueueWorker> _logger;
- private readonly IServiceScopeFactory _scopeFactory;
- private readonly int _workerCount = 2; // 병렬 처리할 Worker 개수
- public MailQueueWorker(ILogger<MailQueueWorker> logger, IServiceScopeFactory scopeFactory)
- {
- _logger = logger;
- _scopeFactory = scopeFactory;
- }
- protected override async Task ExecuteAsync(CancellationToken stoppingToken)
- {
- _logger.LogInformation("MailQueueWorker 시작됨.");
- // 병렬 작업자 처리 지시
- await Task.WhenAll(
- Enumerable.Range(0, _workerCount).Select(_ => Task.Run(() => ProcessQueueAsync(stoppingToken))).ToArray()
- );
- }
- private async Task ProcessQueueAsync(CancellationToken stoppingToken)
- {
- var mailService = _scopeFactory.CreateScope().ServiceProvider.GetRequiredService<IMailService>();
- while (!stoppingToken.IsCancellationRequested)
- {
- using (var scope = _scopeFactory.CreateScope())
- {
- var db = scope.ServiceProvider.GetRequiredService<DefaultDbContext>();
- // 발송되지 않는 메일 확인
- var email = await db.EmailLog.Where(x => x.Status == MailStatus.Pending || x.Status == MailStatus.Processing).OrderBy(x => x.CreatedAt).Take(1).FirstOrDefaultAsync(stoppingToken);
- if (email is null)
- {
- await Task.Delay(3000, stoppingToken);
- continue;
- }
- try
- {
- // 상태를 "Processing"으로 변경하여 중복 처리 방지
- email.Status = MailStatus.Processing;
- await db.SaveChangesAsync(stoppingToken);
- // 메일 전송 시도
- await mailService.SendEmailAsync(new SendData(
- email.ToAddress, email.Subject, email.Message ?? string.Empty
- ));
- // 성공 시 "Sent"로 변경
- email.Status = MailStatus.Sent;
- }
- catch (Exception e)
- {
- _logger.LogError(e, "메일 전송 중 오류 발생");
- email.Status = MailStatus.Failed;
- continue;
- }
- email.ProcessedAt = DateTime.UtcNow;
- await db.SaveChangesAsync(stoppingToken);
- }
- }
- }
- public override async Task StopAsync(CancellationToken stoppingToken)
- {
- _logger.LogInformation($"{nameof(MailQueueWorker)} is stopping.");
- await base.StopAsync(stoppingToken);
- }
- }
- }
|