improvement: PushWorker 웹훅 발송 연동 (#158) #159
|
|
@ -26,6 +26,7 @@ public class PushWorker : BackgroundService
|
|||
private readonly IDuplicateChecker _duplicateChecker;
|
||||
private readonly IBulkJobStore _bulkJobStore;
|
||||
private readonly ITokenCacheService _tokenCache;
|
||||
private readonly IWebhookService _webhookService;
|
||||
private readonly IFcmSender _fcmSender;
|
||||
private readonly IApnsSender _apnsSender;
|
||||
private readonly ILogger<PushWorker> _logger;
|
||||
|
|
@ -37,6 +38,7 @@ public class PushWorker : BackgroundService
|
|||
IDuplicateChecker duplicateChecker,
|
||||
IBulkJobStore bulkJobStore,
|
||||
ITokenCacheService tokenCache,
|
||||
IWebhookService webhookService,
|
||||
IFcmSender fcmSender,
|
||||
IApnsSender apnsSender,
|
||||
ILogger<PushWorker> logger)
|
||||
|
|
@ -47,6 +49,7 @@ public class PushWorker : BackgroundService
|
|||
_duplicateChecker = duplicateChecker;
|
||||
_bulkJobStore = bulkJobStore;
|
||||
_tokenCache = tokenCache;
|
||||
_webhookService = webhookService;
|
||||
_fcmSender = fcmSender;
|
||||
_apnsSender = apnsSender;
|
||||
_logger = logger;
|
||||
|
|
@ -262,6 +265,21 @@ public class PushWorker : BackgroundService
|
|||
"푸시 발송 완료: requestId={RequestId}, 성공={Success}, 실패={Fail}, 총={Total}",
|
||||
pushMessage.RequestId, successCount, failCount, allResults.Count);
|
||||
|
||||
// [6.5] 웹훅 발송
|
||||
var webhookEvent = failCount > 0 && successCount == 0
|
||||
? WebhookEvent.PushFailed
|
||||
: WebhookEvent.PushSent;
|
||||
|
||||
_ = _webhookService.SendAsync(pushMessage.ServiceId, webhookEvent, new
|
||||
{
|
||||
request_id = pushMessage.RequestId,
|
||||
message_id = pushMessage.MessageId,
|
||||
send_type = pushMessage.SendType,
|
||||
success_count = successCount,
|
||||
fail_count = failCount,
|
||||
total_count = allResults.Count
|
||||
});
|
||||
|
||||
// [7] Bulk job 진행률 업데이트
|
||||
if (!string.IsNullOrEmpty(pushMessage.JobId))
|
||||
{
|
||||
|
|
|
|||
67
TASKS.md
67
TASKS.md
|
|
@ -21,11 +21,11 @@
|
|||
| **Account** | 9 | 9 | 0 | Phase 2-1 + 3-2 ✅ |
|
||||
| **Service** | 13 | 13 | 0 | Phase 2-1 ✅ |
|
||||
| **Device** | 7 | 7 | 0 | Phase 2-2 ✅ |
|
||||
| **Message** | 5 | 1 | 4 | Phase 3 ← 다음 |
|
||||
| **Push** | 8 | 5 | 3 | Phase 3 |
|
||||
| **Stats** | 5 | 0 | 5 | Phase 3-2 |
|
||||
| **Message** | 5 | 5 | 0 | Phase 3 ✅ |
|
||||
| **Push** | 8 | 8 | 0 | Phase 3 ✅ |
|
||||
| **Stats** | 5 | 5 | 0 | Phase 3-2 ✅ |
|
||||
| **File** | 6 | 6 | 0 | Phase 2-2 ✅ |
|
||||
| **총계** | **65** | **57** | **8** | - |
|
||||
| **총계** | **65** | **65** | **0** | ✅ 전체 구현 완료 |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -1656,9 +1656,9 @@ Milestone: Phase 3: 메시지 & Push Core
|
|||
| 10 | [Feature] 웹훅 설정 API | Feature | High | WHK-01 | ✅ |
|
||||
| 11 | [Feature] **웹훅 발송 서비스** | Feature | High | WHK-02 | ✅ |
|
||||
| 12 | [Feature] **DailyStatWorker 구현** | Feature | Medium | AAG-01 | ✅ |
|
||||
| 13 | [Feature] **DeadTokenCleanupWorker 구현** | Feature | Medium | DTK-01 | ⬜ |
|
||||
| 14 | [Feature] **데이터 보관 주기 관리 배치** | Feature | Medium | RET-01 | ⬜ |
|
||||
| 15 | [Feature] **Redis 토큰 캐시 관리** | Feature | Medium | - | ⬜ |
|
||||
| 13 | [Feature] **DeadTokenCleanupWorker 구현** | Feature | Medium | DTK-01 | ✅ |
|
||||
| 14 | [Feature] **데이터 보관 주기 관리 배치** | Feature | Medium | RET-01 | ✅ |
|
||||
| 15 | [Feature] **Redis 토큰 캐시 관리** | Feature | Medium | - | ✅ |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -1750,17 +1750,18 @@ Branch: feature/#XX-daily-stat-worker
|
|||
제목: [Feature] DeadTokenCleanupWorker 구현 (비활성 토큰 정리)
|
||||
Labels: Type/Feature, Priority/Medium, Status/Available
|
||||
Milestone: Phase 3-2: 통계 & Webhook & 배치
|
||||
Branch: feature/#XX-dead-token-cleanup
|
||||
Branch: feature/#150-dead-token-cleanup
|
||||
Gitea Issue: #150
|
||||
```
|
||||
|
||||
**상태**: ⬜ 대기
|
||||
**상태**: ✅ 완료 (PR #151 머지됨)
|
||||
|
||||
**설명**: 매주 일요일 03:00 KST에 비활성 상태로 7일 이상 경과한 Device 토큰을 물리 삭제하는 BackgroundService Worker를 구현한다.
|
||||
|
||||
> **📌 참조**: `Documents/BatchScheduler_Design.md` §5 (DeadTokenCleanupWorker)
|
||||
|
||||
**체크리스트 — Worker 구현**:
|
||||
- [ ] `SPMS.Infrastructure/Workers/DeadTokenCleanupWorker.cs` — BackgroundService 상속
|
||||
- [x] `SPMS.Infrastructure/Workers/DeadTokenCleanupWorker.cs` — BackgroundService 상속
|
||||
- Cron 스케줄: 매주 일요일 03:00 KST
|
||||
- 삭제 대상 조회:
|
||||
```sql
|
||||
|
|
@ -1777,17 +1778,17 @@ Branch: feature/#XX-dead-token-cleanup
|
|||
LIMIT 1000
|
||||
```
|
||||
- 삭제된 행 > 0 → 반복, = 0 → 완료
|
||||
- Redis 토큰 캐시 무효화 (삭제된 Device 기반)
|
||||
- Redis 토큰 캐시 무효화 → #15 구현 후 연동 예정
|
||||
- SystemLog에 정리 완료 로그
|
||||
|
||||
**체크리스트 — 안전장치**:
|
||||
- [ ] 배치 단위 삭제 (1000건씩) → DB 부하 분산
|
||||
- [ ] 삭제 전 카운트 로깅
|
||||
- [ ] 비정상 수치 감지 시 중단 (전체의 50% 이상이면 경고)
|
||||
- [x] 배치 단위 삭제 (1000건씩) → DB 부하 분산
|
||||
- [x] 삭제 전 카운트 로깅
|
||||
- [x] 비정상 수치 감지 시 중단 (전체의 50% 이상이면 경고)
|
||||
|
||||
**체크리스트 — 등록**:
|
||||
- [ ] `Program.cs` — `builder.Services.AddHostedService<DeadTokenCleanupWorker>()`
|
||||
- [ ] 환경별 활성화 설정 (Debug/Staging: 비활성, Release: 활성)
|
||||
- [x] `SPMS.Infrastructure/DependencyInjection.cs` — `AddHostedService<DeadTokenCleanupWorker>()`
|
||||
- [ ] 환경별 활성화 설정 (Debug/Staging: 비활성, Release: 활성) → MVP Phase에서 설정
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -1797,22 +1798,23 @@ Branch: feature/#XX-dead-token-cleanup
|
|||
제목: [Feature] 데이터 보관 주기 관리 배치
|
||||
Labels: Type/Feature, Priority/Medium, Status/Available
|
||||
Milestone: Phase 3-2: 통계 & Webhook & 배치
|
||||
Branch: feature/#XX-data-retention
|
||||
Branch: feature/#152-data-retention
|
||||
Gitea Issue: #152
|
||||
```
|
||||
|
||||
**상태**: ⬜ 대기
|
||||
**상태**: ✅ 완료 (PR #153 머지됨)
|
||||
|
||||
**설명**: 보관 주기가 지난 로그 데이터를 정리하는 배치 작업을 구현한다.
|
||||
|
||||
**체크리스트**:
|
||||
- [ ] `SPMS.Infrastructure/Workers/DataRetentionWorker.cs` — BackgroundService 상속
|
||||
- [x] `SPMS.Infrastructure/Workers/DataRetentionWorker.cs` — BackgroundService 상속
|
||||
- Cron 스케줄: 매일 04:00 KST
|
||||
- PushSendLog: 90일 이전 데이터 삭제
|
||||
- PushOpenLog: 90일 이전 데이터 삭제
|
||||
- WebhookLog: 30일 이전 데이터 삭제
|
||||
- SystemLog: 180일 이전 데이터 삭제
|
||||
- [ ] 배치 단위 삭제 (10000건씩)
|
||||
- [ ] SystemLog에 정리 완료 로그
|
||||
- [x] 배치 단위 삭제 (10000건씩)
|
||||
- [x] SystemLog에 정리 완료 로그
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -1822,28 +1824,25 @@ Branch: feature/#XX-data-retention
|
|||
제목: [Feature] Redis 토큰 캐시 관리
|
||||
Labels: Type/Feature, Priority/Medium, Status/Available
|
||||
Milestone: Phase 3-2: 통계 & Webhook & 배치
|
||||
Branch: feature/#XX-redis-token-cache
|
||||
Branch: feature/#154-redis-token-cache
|
||||
Gitea Issue: #154
|
||||
```
|
||||
|
||||
**상태**: ⬜ 대기
|
||||
**상태**: ✅ 완료 (PR #155 머지됨)
|
||||
|
||||
**설명**: 디바이스 토큰을 Redis에 캐싱하여 DB 조회를 최소화한다.
|
||||
|
||||
> **📌 참조**: MEMORY.md Redis 설정
|
||||
|
||||
**체크리스트 — Infrastructure Layer**:
|
||||
- [ ] `SPMS.Infrastructure/Caching/TokenCacheService.cs` — 토큰 캐시 관리
|
||||
- Key 형식: `device:token:{serviceId}:{userId}`
|
||||
- [x] `SPMS.Application/Interfaces/ITokenCacheService.cs` — 인터페이스 + CachedDeviceInfo record
|
||||
- [x] `SPMS.Infrastructure/Caching/TokenCacheService.cs` — Redis 기반 구현
|
||||
- Key 형식: `device:token:{serviceId}:{deviceId}`
|
||||
- TTL: 1시간
|
||||
- GetDeviceTokenAsync(serviceId, userId) → string?
|
||||
- SetDeviceTokenAsync(serviceId, userId, token)
|
||||
- InvalidateAsync(serviceId, userId)
|
||||
- InvalidateByServiceAsync(serviceId) — 서비스 전체 무효화
|
||||
- GetDeviceInfoAsync / SetDeviceInfoAsync / InvalidateAsync / InvalidateByServiceAsync
|
||||
|
||||
**체크리스트 — PushWorker 연동**:
|
||||
- [ ] 발송 시 Redis 캐시 우선 조회
|
||||
- [ ] 캐시 미스 시 DB 조회 후 캐시 저장
|
||||
- [ ] Device 삭제/비활성 시 캐시 무효화
|
||||
- [x] 발송 시 Redis 캐시 우선 조회 (single 발송)
|
||||
- [x] 캐시 미스 시 DB 조회 후 캐시 저장
|
||||
- [x] Device 등록/수정/삭제/수신동의 변경 시 캐시 무효화
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user