Add TimedAspect bean and metrics for FCM notifications#53
Conversation
Test Results72 tests 72 ✅ 1s ⏱️ Results for commit 5bd5d6a. ♻️ This comment has been updated with latest results. |
There was a problem hiding this comment.
Pull request overview
This PR adds Micrometer/Prometheus instrumentation around notification dispatch and FCM sending, and adds new tests around notification metrics exposure plus holiday notification generation. It extends the existing notification subsystem so operators can observe dispatch behavior and validate some of that behavior through unit, integration, and end-to-end tests.
Changes:
- Added
TimedAspect/AOP-based timing support and global metrics configuration usage for notification dispatch timing. - Instrumented
NotificationDispatchServiceandFcmServicewith new counters for dispatch outcomes, FCM send results, and token invalidation paths. - Added notification-focused tests: unit/integration/E2E metrics tests and a holiday-generation unit test suite.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
src/main/kotlin/com/moa/common/config/MetricsConfig.kt |
Enables AOP timing support and exposes the TimedAspect bean for Micrometer annotations. |
src/main/kotlin/com/moa/service/FcmService.kt |
Adds FCM send/result counters and token invalidation metrics during error handling. |
src/main/kotlin/com/moa/service/notification/NotificationDispatchService.kt |
Adds dispatch counters and a timed annotation around notification processing. |
src/test/kotlin/com/moa/service/notification/NotificationBatchServiceHolidayTest.kt |
Adds classicist-style unit coverage for public-holiday notification generation rules. |
src/test/kotlin/com/moa/service/notification/NotificationDispatchIntegrationTest.kt |
Verifies dispatch metrics and common tags inside a Spring integration context. |
src/test/kotlin/com/moa/service/notification/NotificationDispatchServiceMetricsTest.kt |
Adds unit tests for dispatch failure/pending metric increments. |
src/test/kotlin/com/moa/service/notification/PrometheusEndpointE2eTest.kt |
Verifies /actuator/prometheus exposes the new notification metrics over HTTP. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| .tag("reason", reason) | ||
| .register(meterRegistry) | ||
|
|
||
| @Timed(value = "moa.notification.dispatch", percentiles = [0.5, 0.95, 0.99]) |
| MessagingErrorCode.INVALID_ARGUMENT -> { | ||
| log.warn("유효하지 않은 FCM 토큰 삭제: {}", token) | ||
| fcmTokenRepository.deleteByToken(token) | ||
| tokenInvalidated("invalid_argument").increment() | ||
| } |
| assertThat(body).contains("moa_notification_dispatch_seconds") | ||
| assertThat(body).contains("quantile=\"0.95\"") |
| * | ||
| * 통합 테스트(`NotificationDispatchIntegrationTest`)와의 차이: | ||
| * - 통합: `MeterRegistry` 객체를 직접 주입받아 메트릭 값을 in-process로 단언. | ||
| * - E2E: 실제 HTTP 서버(Random Port)를 띄우고 `TestRestTemplate`으로 `/actuator/prometheus` |
| // 4) common tag — 운영 PromQL의 `deploy_color`, `app_version` 라벨 분리에 필수 | ||
| assertThat(body).contains("application=\"moa\"") | ||
| assertThat(body).contains("deploy_color=") | ||
| assertThat(body).contains("app_version=") | ||
| } | ||
|
|
| private fun pendingCounter(type: String): Counter = Counter.builder(METRIC_PENDING) | ||
| .description("발송 시도된 알림 수") | ||
| .tag("notification_type", type) | ||
| .register(meterRegistry) | ||
|
|
||
| private fun failedCounter(type: String, reason: String): Counter = Counter.builder(METRIC_FAILED) | ||
| .description("발송 실패한 알림 수") | ||
| .tag("notification_type", type) | ||
| .tag("reason", reason) | ||
| .register(meterRegistry) |
| private fun pendingCounter(type: String): Counter = Counter.builder(METRIC_PENDING) | ||
| .description("발송 시도된 알림 수") | ||
| .tag("notification_type", type) | ||
| .register(meterRegistry) |
| val tagKeys = pending?.id?.tags?.map { it.key }.orEmpty() | ||
| assertThat(tagKeys).contains("application", "deploy_color", "app_version", "notification_type") |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @TestConfiguration | ||
| class NoopSchedulerConfig { | ||
| @Bean | ||
| @Primary | ||
| fun noopDispatchScheduler(): NotificationDispatchScheduler = | ||
| mockk(relaxed = true) |
| private fun failedCounter(type: String, reason: String): Counter = Counter.builder(METRIC_FAILED) | ||
| .description("발송 실패한 알림 수") | ||
| .tag("notification_type", type) | ||
| .tag("reason", reason) | ||
| .register(meterRegistry) |
This pull request introduces comprehensive metrics and monitoring enhancements to the notification and FCM (Firebase Cloud Messaging) services, as well as adds a classicist-style unit test for the notification batch service's holiday logic. The main changes are grouped into metrics/monitoring improvements and testing additions.
Metrics and Monitoring Enhancements:
Metrics and AOP Configuration:
TimedAspectbean inMetricsConfigto support method-level timing annotations for metrics collection. (src/main/kotlin/com/moa/common/config/MetricsConfig.kt) [1] [2]FCM Service Metrics:
FcmServiceto track successful and failed FCM message sends, as well as automatic token invalidations due to specific error codes. These counters are incremented appropriately during FCM operations and error handling. (src/main/kotlin/com/moa/service/FcmService.kt) [1] [2] [3]Notification Dispatch Metrics:
NotificationDispatchServiceto monitor the number of pending notifications by type and failed notifications by type and reason. These metrics are incremented during notification processing, including attempts, failures due to missing tokens, message build errors, and FCM send failures. Also, annotated the main dispatch method with@Timedto collect execution time metrics. (src/main/kotlin/com/moa/service/notification/NotificationDispatchService.kt) [1] [2] [3] [4] [5] [6]Testing Additions:
Classicist-style Unit Test:
NotificationBatchServiceHolidayTest, a classicist unit test suite that uses fake repositories for all out-of-process dependencies and verifies notification log generation logic for public holidays, including various edge cases and idempotency. (src/test/kotlin/com/moa/service/notification/NotificationBatchServiceHolidayTest.kt)