모바일 청첩장 프로젝트에서 청첩장 등록 API 실행 시 갤러리의 이미지 개수는 최대 9개까지 등록할 수 있도록 유효성 검사 로직을 구현했습니다.
하지만 이때 10개 이상의 이미지를 등록하면 콘솔에 에러 메세지는 정상적으로 출력되지만, invitations, calendars, maps의 데이터 값은 정상적으로 db에 등록이 되는 문제가 발생하였습니다.
에러가 발생하여 코드가 중단되어도 데이터 값은 정상적으로 db에 등록되는 이유는 다음과 같습니다.
우선 코드의 순서 상 invitations -> calendars -> maps -> galleries -> accounts -> contacts -> notices 순서대로 sequelize 메서드를 통해 db에 값이 등록됩니다. 이때 galleries에서 유효성 검사에 통과하지 못해 에러가 출력되면 galleries의 뒷 순서 데이터(accounts, contacts, notices)의 처리는 중단되지만, 그 전에 이미 실행된 데이터(invitations, calendars, maps)의 처리는 정상적으로 이루어지게 되는 것입니다.
이 문제를 해결하기 위해선 에러 처리가 난 후 그 전에 이루어진 데이터 처리를 무효화시켜주는 로직이 필요합니다. 이때 transaction을 활용할 수 있습니다.
transaction이란 하나의 작업 단위를 묶어서 처리하는 개념으로서, 데이터베이스에서 여러 작업이 있을 때 모두 성공하거나 모두 실패하도록 보장해주는 역할을 해줍니다.
이 transaction을 현재 문제 상황에 활용한다면 오류 발생 시 모든 db 변경 사항을 되돌림으로서 데이터 처리 과정을 모두 실패하도록 처리할 수 있습니다.
export const createInvitation = async (invitationData: InvitationData, transaction: Transaction) => {
try {
return await db.Invitation.create(invitationData, {transaction}); // db.Invitation으로 접근
} catch (err) {
throw new Error(`청첩장 등록 에러: ${(err as Error).message}`);
}
};
export const createInvitation = async ( userId: number, invitationData: Omit<InvitationData, 'userId'>,
calendars: CalendarData[], maps: MapData[], galleries: GalleryData[], accounts: AccountData[], contacts: ContactData[], notices: NoticeData[] ): Promise<{ id: number }> => {
const transaction = await db.sequelize.transaction();
try {
const newInvitation = await invitationRepository.createInvitation({ ...invitationData, userId }, transaction);
if (calendars && calendars.length > 0) { // 캘린더 정보가 들어오면 저장
const calendarsWithInvitationId = calendars.map((calendar) => ({
...calendar,
invitationId: newInvitation.id, // 생성된 초대장의 id
}));
await invitationRepository.createCalendar(calendarsWithInvitationId, transaction);
}
await transaction.commit();
return { id: newInvitation.id };
} catch (err) {
if(transaction) {
await transaction.rollback();
console.error('청첩장 등록 에러:', (err as Error).message);
}
if (err instanceof ClientError) { // ClientError의 경우 따로 처리
throw err;
}
위 과정을 통해 에러 발생 시 db에 데이터 값이 등록되는 문제를 해결할 수 있습니다.