diff --git a/SPMS.API/Controllers/PublicController.cs b/SPMS.API/Controllers/PublicController.cs index 47ffc71..f6d16e3 100644 --- a/SPMS.API/Controllers/PublicController.cs +++ b/SPMS.API/Controllers/PublicController.cs @@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore; using Swashbuckle.AspNetCore.Annotations; using SPMS.Domain.Common; using SPMS.Infrastructure; +using SPMS.Infrastructure.Messaging; namespace SPMS.API.Controllers; @@ -14,10 +15,17 @@ namespace SPMS.API.Controllers; public class PublicController : ControllerBase { private readonly AppDbContext _dbContext; + private readonly RabbitMQConnection _rabbitConnection; + private readonly RabbitMQInitializer _rabbitInitializer; - public PublicController(AppDbContext dbContext) + public PublicController( + AppDbContext dbContext, + RabbitMQConnection rabbitConnection, + RabbitMQInitializer rabbitInitializer) { _dbContext = dbContext; + _rabbitConnection = rabbitConnection; + _rabbitInitializer = rabbitInitializer; } [HttpPost("health")] @@ -39,11 +47,26 @@ public class PublicController : ControllerBase allHealthy = false; } - // 2. Redis 연결 확인 (Phase 2에서 구현 예정) + // 2. Redis 연결 확인 (Phase 3-2에서 구현 예정) checks["redis"] = new { status = "not_configured" }; - // 3. RabbitMQ 연결 확인 (Phase 2에서 구현 예정) - checks["rabbitmq"] = new { status = "not_configured" }; + // 3. RabbitMQ 연결 확인 + var rabbitConnected = _rabbitConnection.IsConnected; + var rabbitInitialized = _rabbitInitializer.IsInitialized; + if (rabbitConnected && rabbitInitialized) + { + checks["rabbitmq"] = new { status = "healthy" }; + } + else + { + checks["rabbitmq"] = new + { + status = "unhealthy", + connected = rabbitConnected, + initialized = rabbitInitialized + }; + allHealthy = false; + } if (allHealthy) { diff --git a/SPMS.Infrastructure/DependencyInjection.cs b/SPMS.Infrastructure/DependencyInjection.cs index cadd401..87d794f 100644 --- a/SPMS.Infrastructure/DependencyInjection.cs +++ b/SPMS.Infrastructure/DependencyInjection.cs @@ -58,7 +58,8 @@ public static class DependencyInjection // RabbitMQ services.Configure(configuration.GetSection(RabbitMQSettings.SectionName)); services.AddSingleton(); - services.AddHostedService(); + services.AddSingleton(); + services.AddHostedService(sp => sp.GetRequiredService()); services.AddScoped(); // Push Senders diff --git a/SPMS.Infrastructure/Messaging/RabbitMQConnection.cs b/SPMS.Infrastructure/Messaging/RabbitMQConnection.cs index bb80f6e..94d4c22 100644 --- a/SPMS.Infrastructure/Messaging/RabbitMQConnection.cs +++ b/SPMS.Infrastructure/Messaging/RabbitMQConnection.cs @@ -12,6 +12,8 @@ public class RabbitMQConnection : IAsyncDisposable private readonly SemaphoreSlim _semaphore = new(1, 1); private IConnection? _connection; + public bool IsConnected => _connection is { IsOpen: true }; + public RabbitMQConnection( IOptions settings, ILogger logger) diff --git a/SPMS.Infrastructure/Messaging/RabbitMQInitializer.cs b/SPMS.Infrastructure/Messaging/RabbitMQInitializer.cs index 7926e2f..0016765 100644 --- a/SPMS.Infrastructure/Messaging/RabbitMQInitializer.cs +++ b/SPMS.Infrastructure/Messaging/RabbitMQInitializer.cs @@ -6,11 +6,14 @@ using SPMS.Application.Settings; namespace SPMS.Infrastructure.Messaging; -public class RabbitMQInitializer : IHostedService +public class RabbitMQInitializer : BackgroundService { private readonly RabbitMQConnection _connection; private readonly RabbitMQSettings _settings; private readonly ILogger _logger; + private static readonly TimeSpan RetryInterval = TimeSpan.FromSeconds(30); + + public bool IsInitialized { get; private set; } public RabbitMQInitializer( RabbitMQConnection connection, @@ -22,19 +25,26 @@ public class RabbitMQInitializer : IHostedService _logger = logger; } - public async Task StartAsync(CancellationToken cancellationToken) + protected override async Task ExecuteAsync(CancellationToken stoppingToken) { - try + while (!stoppingToken.IsCancellationRequested) { - await InitializeAsync(cancellationToken); - } - catch (Exception ex) - { - _logger.LogWarning(ex, "RabbitMQ 초기화 실패 — 서버는 계속 실행됩니다. 메시지 발송 시 재연결을 시도합니다."); + try + { + await InitializeAsync(stoppingToken); + IsInitialized = true; + _logger.LogInformation("RabbitMQ 초기화 완료"); + return; + } + catch (Exception ex) + { + _logger.LogWarning(ex, "RabbitMQ 초기화 실패 — {RetrySeconds}초 후 재시도합니다.", RetryInterval.TotalSeconds); + await Task.Delay(RetryInterval, stoppingToken); + } } } - public async Task InitializeAsync(CancellationToken cancellationToken) + private async Task InitializeAsync(CancellationToken cancellationToken) { await using var channel = await _connection.CreateChannelAsync(cancellationToken); @@ -87,6 +97,4 @@ public class RabbitMQInitializer : IHostedService _logger.LogInformation("Queue 선언 및 바인딩 완료: {Queue} → {Exchange} (routing_key: schedule)", _settings.ScheduleQueue, _settings.Exchange); } - - public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; }