From ee42b12c2b4ff08ad1cafbd6b3762a00191f7c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=B4=EA=B3=A4?= Date: Wed, 4 Mar 2026 13:32:06 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20[changes]=20=EA=B3=84=EC=A2=8C=20?= =?UTF-8?q?=EC=9E=85=EC=B6=9C=EA=B8=88=EB=82=B4=EC=97=AD=20=EB=AC=B4?= =?UTF-8?q?=ED=95=9C=EB=A3=A8=ED=94=84=20=EB=B2=84=EA=B7=B8=20=EB=B6=84?= =?UTF-8?q?=EC=84=9D=20=EB=AC=B8=EC=84=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 근본 원인: splitDateRangeMonthly() cursor 이동 버그 - 재현 조건, 검증 결과, 교훈/방지 규칙 포함 - 코드베이스 전체 유사 패턴 점검 결과 포함 --- sam/docs/INDEX.md | 4 + .../20260304_eaccount_infinite_loop_fix.md | 165 ++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 sam/docs/changes/20260304_eaccount_infinite_loop_fix.md diff --git a/sam/docs/INDEX.md b/sam/docs/INDEX.md index 16ab051..aeed526 100644 --- a/sam/docs/INDEX.md +++ b/sam/docs/INDEX.md @@ -222,6 +222,10 @@ docs/ ### changes/ — 변경 이력 > 파일명 형식: `YYYYMMDD_description.md` +| 문서 | 설명 | +|------|------| +| [20260304_eaccount_infinite_loop_fix.md](changes/20260304_eaccount_infinite_loop_fix.md) | 계좌 입출금내역 부분 월 조회 시 무한루프 크래시 수정 | + --- ### data/ — 데이터 분석 diff --git a/sam/docs/changes/20260304_eaccount_infinite_loop_fix.md b/sam/docs/changes/20260304_eaccount_infinite_loop_fix.md new file mode 100644 index 0000000..e754f9f --- /dev/null +++ b/sam/docs/changes/20260304_eaccount_infinite_loop_fix.md @@ -0,0 +1,165 @@ +# 계좌 입출금내역 부분 월 조회 시 무한루프 크래시 수정 + +**날짜:** 2026-03-04 +**작업자:** Claude Code + +--- + +## 변경 개요 + +계좌 입출금내역 페이지에서 **날짜를 수동 입력**하여 조회 시 500 에러가 발생하는 문제를 수정했다. +편의 버튼(이번달, 지난달 등)은 항상 전체 월(1일~말일)을 사용하여 문제가 없었으나, +수동으로 날짜를 입력하면 **부분 월**(예: 12/01~12/18)이 되어 무한루프가 발생했다. + +--- + +## 근본 원인 + +### `splitDateRangeMonthly()` 함수의 cursor 이동 버그 + +긴 기간 조회 시 바로빌 SOAP API의 한계로 인해 기간을 **월별 청크**로 분할하는 함수에서, +endDate가 **월 중간**일 때 cursor가 **같은 달 1일로 되돌아가** 무한루프가 발생했다. + +```php +// ❌ 버그 코드 — endDate가 월 중간이면 무한루프 +$cursor = $chunkEnd->copy()->addDay()->startOfMonth(); + +// 예시: endDate = 20251218 +// chunkEnd = 20251218 +// → addDay() = 20251219 +// → startOfMonth() = 20251201 ← 같은 달 1일로 되돌아감! +// → while($cursor <= $end) 조건 여전히 true → 무한 반복 +``` + +```php +// ✅ 수정 코드 — chunkStart 기준으로 다음 월로 이동 +$cursor = $chunkStart->copy()->addMonth()->startOfMonth(); + +// 예시: startDate = 20251201 +// chunkStart = 20251201 +// → addMonth() = 20260101 +// → startOfMonth() = 20260101 ← 다음 달로 정상 이동 +// → while($cursor <= $end) 조건 false → 루프 종료 +``` + +### 재현 조건 + +| 조건 | 결과 | +|------|------| +| 전체 월 (12/01~12/31) | 정상 — `addDay()` = 01/01 → `startOfMonth()` = 01/01 | +| 부분 월 (12/01~12/18) | **무한루프** — `addDay()` = 12/19 → `startOfMonth()` = 12/01 | +| 다중 월 (12/01~02/18) | **무한루프** — 마지막 월이 부분 월이면 동일 증상 | + +### 증상 + +- PHP 프로세스가 메모리 한도(256M/512M)에 도달하여 **Fatal Error로 크래시** +- Laravel 로그에 에러 기록 없음 (try-catch 밖에서 프로세스가 종료) +- 프론트엔드에 `서버 응답 오류 (500):` (빈 응답 본문) + +--- + +## 수정된 파일 + +| 파일 | 변경 내용 | +|------|----------| +| `app/Http/Controllers/Barobill/EaccountController.php` | `splitDateRangeMonthly()` cursor 이동 로직 수정 | + +--- + +## 검증 결과 + +tinker에서 수정 전후 비교 테스트: + +``` +=== 수정 전 (버그): 20251201~20251218 === +→ 같은 청크 무한 반복 (10회 제한으로 강제 중단) + +=== 수정 후: 20251201~20251218 === +→ [{start: 20251201, end: 20251218}] ← 1개 청크, 정상 + +=== 수정 후: 20251201~20260218 (다중 월) === +→ [{20251201~20251231}, {20260101~20260131}, {20260201~20260218}] ← 3개 청크, 정상 + +=== 수정 후: 20251215~20251231 === +→ [{start: 20251215, end: 20251231}] ← 1개 청크, 정상 +``` + +--- + +## 동일 패턴 코드베이스 점검 결과 + +`sam/mng` 전체를 검색하여 유사 패턴을 점검했다: + +| 파일 | 함수 | 패턴 | 위험도 | +|------|------|------|--------| +| `EaccountController.php` | `splitDateRangeMonthly()` | 월별 청크 분할 | ✅ 수정 완료 | +| `DashboardStatService.php` | `generateDateRange()` | `addDay()` 단순 증가 | 안전 | +| `InspectionCycle.php` | `getHolidayDates()` | `addDay()` 단순 증가 | 안전 | +| `CorporateCardController.php` | `getNextBusinessDay()` | `addDay()` 단순 증가 | 안전 | +| `PartitionManagementService.php` | `addPartitions()` | `for` 루프 (고정 횟수) | 안전 | + +> **결론**: `EaccountController` 외에 동일 버그 패턴 없음. +> 다른 코드들은 모두 `addDay()` 단순 증가 패턴을 사용하여 무한루프 위험 없음. + +--- + +## 교훈 및 방지 규칙 + +### R1. 날짜 cursor 이동 시 `chunkEnd` 기반 이동 금지 + +```php +// ❌ 위험: chunkEnd가 월 중간이면 startOfMonth()가 같은 달로 되돌림 +$cursor = $chunkEnd->copy()->addDay()->startOfMonth(); + +// ✅ 안전: chunkStart 기준으로 항상 다음 월로 이동 +$cursor = $chunkStart->copy()->addMonth()->startOfMonth(); +``` + +### R2. 날짜 루프에 안전장치(max iterations) 추가 권장 + +```php +$maxIterations = 120; // 10년 = 120개월 +$iterations = 0; + +while ($cursor->lte($end) && $iterations < $maxIterations) { + // ... 청크 처리 ... + $iterations++; +} + +if ($iterations >= $maxIterations) { + Log::error('날짜 분할 루프 안전장치 작동', compact('startDate', 'endDate')); +} +``` + +### R3. 부분 월 테스트 필수 + +날짜 범위를 분할하는 코드 작성/수정 시 반드시 다음 케이스를 테스트: + +- [ ] 전체 월 (01일~말일) +- [ ] 부분 월 — 시작 (01일~중간) +- [ ] 부분 월 — 끝 (중간~말일) +- [ ] 다중 월 (마지막 월이 부분 월) +- [ ] 같은 날 (시작일 = 종료일) + +--- + +## 부수 개선 사항 + +이 문제 조사 과정에서 추가로 발견/수정된 항목: + +| 항목 | 내용 | +|------|------| +| WSDL 캐싱 | `WSDL_CACHE_NONE` → `WSDL_CACHE_BOTH` (4개 바로빌 컨트롤러 전체) | +| 소켓 타임아웃 | `default_socket_timeout` 60→120초 연장 | +| Shutdown handler | PHP Fatal Error 감지 시 Laravel 로그에 기록 | +| SOAP 호출 로깅 | 호출 시작/완료 시간 + 소요시간(ms) 기록 | + +--- + +## 관련 문서 + +- `app/Http/Controllers/Barobill/EaccountController.php` — 바로빌 계좌 입출금내역 + +--- + +**최종 업데이트**: 2026-03-04