Skip to content

[FEAT] AI 핀 생성·축제 적재 후 Redis GEO 캐시 동기화#136

Merged
selnem merged 2 commits into
developfrom
feat/135-feat-redis-cache
Jun 18, 2026
Merged

[FEAT] AI 핀 생성·축제 적재 후 Redis GEO 캐시 동기화#136
selnem merged 2 commits into
developfrom
feat/135-feat-redis-cache

Conversation

@selnem

@selnem selnem commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

feat: AI 핀 생성·축제 적재 후 Redis GEO 캐시 동기화

🔗 Related Issue

✨ 작업 개요

BE PinGeoRedisService와 동일 규약의 PinGeoRedisPublisher를 AI 서비스에 추가하고, DB commit 성공 직후 geo:pins / geo:pins:{TYPE} / pin:info:{pinId}를 갱신하도록 연동했습니다.
이슈 핀 create/update, 축제 배치 import 경로에서 Redis GEO 캐시를 동기화해 지도 핀 조회 API(Cache-Aside)의 캐시 정합성을 맞춥니다.

주요 변경

  • 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_idpin:info payload용 region 조회
  • deps.pyPinGeoRedisPublisher DI 등록
  • 테스트 — publisher 단위 테스트, Issue/Festival 서비스 mock 보강

캐시 전략 (참고)

  • Read: BE Cache-Aside (Redis → miss/error 시 PostGIS DB)
  • Write: DB commit 후 Redis best-effort 갱신
  • 정합성 보정: BE 야간 스케줄러 전체 재적재

미포함 (후속 작업)

  • PolicyEventIngestService / ContestEventIngestService Redis 연동

체크리스트

  • Reviewers, Assignees, Labels를 모두 등록했나요?
  • .gitignore 설정을 하였나요?
  • PR 머지 전 반드시 CI가 정상적으로 작동하는지 확인해주세요!

📷 이미지 첨부 (선택)

  • 적재 전후 GET /api/map/cache/status ZCARD 비교 32->35 (issue 1개 적재, festival 2개 적재)
image

🧐 집중 리뷰 요청

  1. PinGeoRedisPublisher ↔ BE PinGeoRedisService 규약 일치

    • Redis key (geo:pins, geo:pins:{TYPE}, pin:info:{pinId})
    • JSON 필드명 (pinId, pinType, latitude, longitude, pinDetailAddress, pinLocation, discount)
    • pin:info TTL 48h
  2. DB commit 이후 Redis write 순서

    • IssueService create/update
    • FestivalEventIngestService batch import
      → 롤백 시 Redis 오염 없는지 확인
  3. 축제 배치 add_pins_batch pipeline

    • CREATED/UPDATED 건만 수집 후 commit 직후 일괄 발행
    • Redis 실패 시 warning만 남기고 API는 성공 (BE와 동일 best-effort)
  4. 테스트 커버리지

    • tests/test_pin_geo_redis_publisher.py — key/TTL/JSON/pipeline/remove
    • Festival batch 테스트에서 add_pins_batch 호출 mock 검증

BE PinGeoRedisService와 동일 규약의 PinGeoRedisPublisher를 추가하고,
DB commit 성공 직후 geo:pins·pin:info를 갱신한다.
이슈 핀 create/update와 축제 배치 import 경로에 연동해
지도 핀 조회 API Cache-Aside 캐시 정합성을 맞춘다.
@selnem selnem requested a review from taerimiiii June 18, 2026 03:40
@selnem selnem self-assigned this Jun 18, 2026
@selnem selnem added ♻️ refactor 기능 변화 없는 코드 리팩터링 ⭐ feat 새로운 기능 labels Jun 18, 2026
@selnem selnem linked an issue Jun 18, 2026 that may be closed by this pull request

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread app/services/IssueService.py Outdated
DB commit 이후 캐시 동기화 실패 시에도 API가 500으로 실패하지 않도록
좌표 파싱·region 조회·Redis 적재 예외를 warning 로그로만 남긴다.
@selnem

selnem commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +70 to +94
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)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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)

Comment on lines +663 to +670
async def _build_festival_geo_cache_item(
self,
*,
pin_id: int,
location_id: int,
detail_address: str,
pin_point,
) -> PinGeoCacheItem:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

_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 taerimiiii changed the title feat: AI 핀 생성·축제 적재 후 Redis GEO 캐시 동기화 [REAT] AI 핀 생성·축제 적재 후 Redis GEO 캐시 동기화 Jun 18, 2026
@taerimiiii taerimiiii changed the title [REAT] AI 핀 생성·축제 적재 후 Redis GEO 캐시 동기화 [FEAT] AI 핀 생성·축제 적재 후 Redis GEO 캐시 동기화 Jun 18, 2026

@taerimiiii taerimiiii left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

마지막까지 너모너모 수고 많으셨습니다!!
(∩•̀ω•́)⊃-*⋆ LGTM!!

@selnem selnem merged commit 8da680e into develop Jun 18, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⭐ feat 새로운 기능 ♻️ refactor 기능 변화 없는 코드 리팩터링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] redis 캐싱 Write 파트 구현

2 participants