[FEAT] AI 핀 생성·축제 적재 후 Redis GEO 캐시 동기화#136
Conversation
BE PinGeoRedisService와 동일 규약의 PinGeoRedisPublisher를 추가하고, DB commit 성공 직후 geo:pins·pin:info를 갱신한다. 이슈 핀 create/update와 축제 배치 import 경로에 연동해 지도 핀 조회 API Cache-Aside 캐시 정합성을 맞춘다.
There was a problem hiding this comment.
Code Review
This pull request introduces a Redis-based GEO cache publisher (PinGeoRedisPublisher) to cache and publish pin location data for both festival and issue pins. It integrates this publisher into FestivalEventIngestService and IssueService to sync pin coordinates and region information to Redis. The review feedback highlights a potential issue in IssueService._sync_issue_pin_geo_cache where failures during cache synchronization (such as coordinate parsing or database lookup errors) are not caught, which could cause API requests to fail with a 500 error even after a successful database commit. It is recommended to wrap this synchronization logic in a try-except block to ensure it behaves as a best-effort operation.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
DB commit 이후 캐시 동기화 실패 시에도 API가 500으로 실패하지 않도록 좌표 파싱·region 조회·Redis 적재 예외를 warning 로그로만 남긴다.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces a Redis-based GEO cache publisher (PinGeoRedisPublisher) to mirror and synchronize pin location data in Redis. It integrates this publisher into FestivalEventIngestService and IssueService to automatically update the cache when pins are created or updated, and adds corresponding unit tests. The review feedback suggests two improvements: chunking the Redis pipeline operations in add_pins_batch to prevent potential performance bottlenecks with large datasets, and adding a missing type annotation to the pin_point parameter in _build_festival_geo_cache_item.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| async def add_pins_batch(self, items: list[PinGeoCacheItem]) -> None: | ||
| if not items: | ||
| return | ||
| try: | ||
| async with self._redis.pipeline(transaction=False) as pipe: | ||
| for item in items: | ||
| member = str(item.pin_id) | ||
| pipe.geoadd(GEO_KEY_ALL, (item.lng, item.lat, member)) | ||
| pipe.geoadd(f"{GEO_KEY_PREFIX}{item.pin_type}", (item.lng, item.lat, member)) | ||
| pipe.set( | ||
| f"{PIN_INFO_KEY_PREFIX}{item.pin_id}", | ||
| _build_pin_info_json( | ||
| pin_id=item.pin_id, | ||
| pin_type=item.pin_type, | ||
| lat=item.lat, | ||
| lng=item.lng, | ||
| detail_address=item.detail_address, | ||
| region=item.region, | ||
| discount=item.discount, | ||
| ), | ||
| ex=PIN_INFO_TTL_SECONDS, | ||
| ) | ||
| await pipe.execute() | ||
| except Exception as exc: | ||
| logger.warning("Redis GEO 핀 batch 추가 실패 count=%s: %s", len(items), exc) |
There was a problem hiding this comment.
import_all을 통해 대량의 축제 데이터를 한 번에 적재할 때, add_pins_batch 메서드는 모든 아이템을 단일 Redis 파이프라인으로 처리합니다. 만약 처리해야 할 데이터가 수천 개 이상으로 매우 많아지면, 단일 파이프라인의 크기가 너무 커져 Redis 서버의 이벤트 루프를 일시적으로 차단하거나 클라이언트/서버 메모리를 과도하게 점유할 위험이 있습니다.\n\n안정적인 처리를 위해 파이프라인 요청을 적절한 크기(예: 500개)로 청크(chunk)화하여 나누어 실행하는 것을 권장합니다.
async def add_pins_batch(self, items: list[PinGeoCacheItem], chunk_size: int = 500) -> None:\n if not items:\n return\n try:\n for i in range(0, len(items), chunk_size):\n chunk = items[i : i + chunk_size]\n async with self._redis.pipeline(transaction=False) as pipe:\n for item in chunk:\n member = str(item.pin_id)\n pipe.geoadd(GEO_KEY_ALL, (item.lng, item.lat, member))\n pipe.geoadd(f\"{GEO_KEY_PREFIX}{item.pin_type}\", (item.lng, item.lat, member))\n pipe.set(\n f\"{PIN_INFO_KEY_PREFIX}{item.pin_id}\",\n _build_pin_info_json(\n pin_id=item.pin_id,\n pin_type=item.pin_type,\n lat=item.lat,\n lng=item.lng,\n detail_address=item.detail_address,\n region=item.region,\n discount=item.discount,\n ),\n ex=PIN_INFO_TTL_SECONDS,\n )\n await pipe.execute()\n except Exception as exc:\n logger.warning(\"Redis GEO 핀 batch 추가 실패 count=%s: %s\", len(items), exc)| async def _build_festival_geo_cache_item( | ||
| self, | ||
| *, | ||
| pin_id: int, | ||
| location_id: int, | ||
| detail_address: str, | ||
| pin_point, | ||
| ) -> PinGeoCacheItem: |
There was a problem hiding this comment.
_build_festival_geo_cache_item 메서드의 pin_point 매개변수에 타입 어노테이션이 누락되어 있습니다. 코드의 일관성과 정적 타입 검사(MyPy 등)의 정확성을 높이기 위해 Any 또는 적절한 기하학 타입을 명시해 주는 것이 좋습니다. 이미 파일 상단에 typing.Any가 임포트되어 있으므로 이를 활용할 수 있습니다.
async def _build_festival_geo_cache_item(\n self,\n *,\n pin_id: int,\n location_id: int,\n detail_address: str,\n pin_point: Any,\n ) -> PinGeoCacheItem:
taerimiiii
left a comment
There was a problem hiding this comment.
마지막까지 너모너모 수고 많으셨습니다!!
(∩•̀ω•́)⊃-*⋆ LGTM!!
feat: AI 핀 생성·축제 적재 후 Redis GEO 캐시 동기화
🔗 Related Issue
✨ 작업 개요
주요 변경
PinGeoRedisPublisher추가 — BE write 규약 미러링 (add_pin,add_pins_batch,remove_pin)IssueService— create/update commit 후_sync_issue_pin_geo_cache호출FestivalEventIngestService— import batch commit 후add_pins_batch호출 (CREATED/UPDATED)LocationRepo.get_region_by_id—pin:infopayload용 region 조회deps.py—PinGeoRedisPublisherDI 등록캐시 전략 (참고)
미포함 (후속 작업)
PolicyEventIngestService/ContestEventIngestServiceRedis 연동체크리스트
📷 이미지 첨부 (선택)
GET /api/map/cache/statusZCARD 비교 32->35 (issue 1개 적재, festival 2개 적재)🧐 집중 리뷰 요청
PinGeoRedisPublisher↔ BEPinGeoRedisService규약 일치geo:pins,geo:pins:{TYPE},pin:info:{pinId})pinId,pinType,latitude,longitude,pinDetailAddress,pinLocation,discount)pin:infoTTL 48hDB commit 이후 Redis write 순서
IssueServicecreate/updateFestivalEventIngestServicebatch import→ 롤백 시 Redis 오염 없는지 확인
축제 배치
add_pins_batchpipeline테스트 커버리지
tests/test_pin_geo_redis_publisher.py— key/TTL/JSON/pipeline/removeadd_pins_batch호출 mock 검증