가져오기
const fetchIntakePurposeCategory = async (mid: string, intakePurposeId: number) => {
const session = await getSession();
const validatedFields = NutrientIntakePurposes.findOneV1.inputParams.parse({
pInvokerOperatorId: session?.user.operator_id,
pThisOperatorMenuIdentifier: mid,
pIp: session?.user.operator_ip,
pIntakePurposeId: intakePurposeId,
pCallDate: spCallDate(),
});
const data = await NutrientIntakePurposesRepository.findOneV1(validatedFields);
return data[0];
};
const cacheKey = (mid: string, intakePurposeId: number) => `${mid}-${intakePurposeId}`;
const cachedFetch = unstable_cache((mid, intakePurposeId) => fetchIntakePurposeCategory(mid, intakePurposeId), {
tags: (mid, intakePurposeId) => `${mid}-${intakePurposeId}`,
revalidate: 60, // 60초마다 캐시 재검증
key: cacheKey,
});
export async function getIntakePurposeCategory(params: {
mid: string;
intakePurposeId: number;
}): Promise<ActionResponse<z.infer<typeof NutrientIntakePurposes.findOneV1.outputRs>>> {
const session = await getSession();
try {
const data = await cachedFetch(params.mid, params.intakePurposeId);
revalidatePath(`/intake-purpose`);
return {
status: 'SUCCESS',
message: '대분류(섭취목적 카테고리 목록)을 불러왔습니다.',
data: data,
};
} catch (error) {
return errorHandler(error);
}
}
업데이트
export async function updateIntakePurposeCategory(formData: FormData): Promise<ActionResponse> {
const session = await getSession();
try {
const validatedFields = NutrientIntakePurposes.updateV1.inputParams.parse({
pInvokerOperatorId: session?.user.operator_id,
pThisOperatorMenuIdentifier: formData.get('pThisOperatorMenuIdentifier'),
pIp: session?.user.operator_ip,
pIntakePurposeId: Number(formData.get('pIntakePurposeId')),
pIntakePurposeName: formData.get('pIntakePurposeName'),
pGender: formData.get('pGender') === null ? null : Number(formData.get('pGender')),
pAdminMemo: formData.get('pAdminMemo'),
pIsEnabled: Number(formData.get('pIsEnabled')),
pIsRequired: Number(formData.get('pIsRequired')),
pCallDate: spCallDate(),
});
try {
await NutrientIntakePurposesRepository.updateV1(validatedFields);
const cacheKeyToInvalidate = cacheKey(
validatedFields.pThisOperatorMenuIdentifier,
validatedFields.pIntakePurposeId,
);
await unstable_cache.invalidateTags([cacheKeyToInvalidate]);
revalidatePath(`/intake-purpose`);
} catch (error) {
console.log(error);
}
// await NutrientIntakePurposesRepository.updateV1(validatedFields);
// const cacheKeyToInvalidate = cacheKey(
// validatedFields.pThisOperatorMenuIdentifier,
// validatedFields.pIntakePurposeId,
// );
// await unstable_cache.invalidateTags([cacheKeyToInvalidate]);
// revalidatePath(`/intake-purpose`);
return {
status: 'SUCCESS',
message: ZOD_SUCCESS_MESSAGE,
};
} catch (error) {
console.log('error', error);
return errorHandler(error);
}
}
문제상황
→ try catch 문안에 try catch로 감싸면 문제없이 작동하지만 그냥 쓰면 위와 같은 에러가 발생한다.
https://github.com/vercel/next.js/issues/50765
실제로 캐시 무효화를 위해 revalidateTag를 다양한 방법으로 사용해 보았지만 의도대로 작동하지 않는 경우가 많았다. 오히려 revalidate를 이용해 캐시 무효화를 하는 것이 안전한 것 같다.
// 섭취목적 카테고리 수정
export async function updateIntakePurposeCategory(formData: FormData): Promise<ActionResponse> {
const session = await getSession();
try {
const validatedFields = NutrientIntakePurposes.updateV1.inputParams.parse({
pInvokerOperatorId: session?.user.operator_id,
pThisOperatorMenuIdentifier: formData.get('pThisOperatorMenuIdentifier'),
pIp: session?.user.operator_ip,
pIntakePurposeId: Number(formData.get('pIntakePurposeId')),
pIntakePurposeName: formData.get('pIntakePurposeName'),
pGender: formData.get('pGender') === null ? null : Number(formData.get('pGender')),
pAdminMemo: formData.get('pAdminMemo'),
pIsEnabled: Number(formData.get('pIsEnabled')),
pIsRequired: Number(formData.get('pIsRequired')),
pCallDate: spCallDate(),
});
await NutrientIntakePurposesRepository.updateV1(validatedFields);
revalidatePath(`/intake-purpose/${validatedFields.pIntakePurposeId}`);
return {
status: 'SUCCESS',
message: ZOD_SUCCESS_MESSAGE,
};
} catch (error) {
console.log('error', error);
return errorHandler(error);
}
}
⇒ 위 방법으로 되는 것 같았지만 빌드에서 결국 문제가 생기고 말았다.