개요
꽤 오래전 글에서 Next Cache Key를 구하는 알고리즘을 분석하고 실제로 동일하게 만들어보기까지 하면서 RSC paylaod를 관리해 볼 생각이었습니다. 이와 관련해 npm 라이브러리도 만들어보면서 큰 기대를 만들고 적용해 보려 했지만...
막상 만들고 적용해보니 쓸모가 없어졌는데, CMS에서 key를 생성해야 하는데 키 생성에 필요한 값들은 대부분 클라이언트에서 사용된다는 점, config 값을 사용해야 하는 점 등 생각보다 사용하는데 너무 많은 공수가 들어 잠시 접어뒀습니다.
그래서 이번 글에서는, Cache Key를 구하는 쪽에서 원하는 대로 set하는 쪽으로 방향을 틀어 제어한 방법을 공유해 보려 합니다.
왜 Cache Key 구하는 것에 집착을 했는지?
다음은 NextJS가 제공하는 custom cache handler 예제입니다.
캐시 흐름에 대해 보면, 요청이 들어올 때 get 메서드에서 key가 있다면 Cache HIT, 없다면 Cache MISS로 set 메서드를 통해 새 캐시를 저장합니다.
여기서 set 메서드에서 key를 커스텀 해서 저장한다면, get에서 key를 받아올 수가 없습니다. 이 key는 NextJS 내부에서 만들어지기 때문이죠. 따라서 제가 이 key를 구할 수만 있다면, 캐시에 접근해 관리를 해볼 생각이었습니다.
이 방법은 개요에서 소개한 것처럼, 더 효율적인 방법을 찾기 위해 잠시 중단했습니다.
두 번째 파라미터 ctx를 이용하자
문서엔 없지만, 구현체를 보면 get 메서드는 두 번째 파라미터 ctx를 제공합니다.
ctx 안에는 무엇이 있을까요? incremetal-cache 파일 안에서 확인해 볼 수 있습니다.
익숙한 옵션들이 많이 보이는데, 특히 눈에 띄는 건 tags입니다. 예제의 set 메서드에서 사용했죠. 예제에서 payload의 value는 { value, lastModified, tags }로 구성되어 있습니다.
tags는 무엇일까요? 예상했던 것처럼 On Demand 방식을 위한 Revalidate Tag의 tag입니다. 이제 get, set 메서드 간에 내부에서 생성되는 key 말고도 우리가 설정할 수 있는 tag를 공유할 수 있게 된 겁니다.
tags를 이용한 key 커스텀하기
next option을 이용해 다음과 같이 요청을 해보겠습니다.
이제 세팅한 tags를 이용해 동일하게 customKey를 만듭니다.
최종 저장된 값은 다음과 같습니다.
tags를 사용하지 않는 경우 리팩토링
tags를 설정하지 않는 요청이 더 많을 거라고 예상됩니다. 이 경우 key가 존재하지 않기 때문에, 캐시를 할 수 없습니다.
tags가 없는 경우는 그대로 NextJS의 key를 사용할 수 있게 리팩토링합니다. tags가 없다면 기존처럼 내부 캐시 파이프라인을 수행할 수 있게 하는 것이죠.
revalidate 과정을 없애자
NextJS가 알아서 해주는데 굳이 Cache를 핸들링 하려는 이유가 무엇일까요. CMS를 통해 외부에서 데이터를 관리한다면, On Demand로 revalidate 하기 굉장히 번거롭습니다.
- CMS에서 데이터 업데이트 시 Next 서비스로 queryString에 업데이트하고자 하는 tags를 포함해 요청하기
- 서비스에선 route handler를 이용해 CMS의 요청으로부터 queryString을 파싱, tags 추출
- revalidateTag 실행
보기엔 간결해 보이지만, 이 과정에서 CMS와 서비스 간의 CORS 설정이나, 무분별한 route handler 호출을 막기 위한 header 설정 등 굉장히 많은 공수가 들어가게 됩니다. 예외 처리해야 하는 코드 또한 늘어납니다.
반면 캐시를 커스텀 하면 어떻게 될까요. 단지 CMS에서 데이터 업데이트 시 저장소에 접근, customKey를 통해 Cache를 Purge 시키면 그만입니다. 그렇다면 자동으로 NextJS는 Cache MISS, DB에 접근해 새 데이터를 받아올 수 있는 것이죠. (다만 서비스와 CMS 간에 tags 관리는 더 연구가 필요해 보입니다.)
Sever Action을 이용하면 위의 과정을 거치진 않지만, 이 경우에도 즉시 Cache Purge를 통해 NextJS의 revalidate 실행하는 과정을 생략할 수 있습니다.
마무리
아직 POC 단계이지만 꾸준히 관심을 가지고 개선한 결과, 회사가 겪고 있는 기술적 챌린지를 하나씩 해결해 나간다는 점에서 큰 보람을 느낍니다.
사실 NextJS가 제공하는 가이드대로만 해도 문제를 해결할 수 있지만, 더 나은 방향으로 개선하기 위해 앞으로도 계속 다듬어 나가려고 합니다.