본문 바로가기
사이드 프로젝트/캡처 이미지 정리 웹 사이트 프로젝트

[Node.js]병렬처리를 위한 Promise.all() vs Promise.allSettled()

by Baley 2023. 11. 21.

배경

해당 프로젝트의 경우 AWS S3에 이미지 파일을 업로드하고 S3 업로드된 이미지 파일을 네이버 CLOVA OCR API로 전송해 이미지에서 텍스트를 추출해야 한다.

S3에 Promise.all()을 통해 병렬 업로드하고 이미지 업로드에 성공하면 OCR 추출 단계로 넘어가 다시 Promise.all()을 사용해 CLOVA OCR API에 요청을 보낸다.

 

현재 코드 예시

export const put = async (req, res) => {
    try {
        const uploadedFiles = req.files;

        // 병렬로 이미지 업로드 진행
        const s3Results = await Promise.all(uploadedFiles.map(putImage));

        // 각 파일의 업로드 성공 여부를 확인
        const uploadSuccesses = s3Results.filter(s3Result => s3Result.$metadata.httpStatusCode == 200);
        const uploadFailures = s3Results.filter(s3Result => s3Result.$metadata.httpStatusCode !== 200);

        // 각 파일에 대해 OCR 추출을 병렬로 진행
        const ocrResults = await Promise.all(uploadSuccesses.map(sendOCRRequest));

        // OCR 추출 결과를 가지고 필요한 작업 수행
        // ...

        return res.status(200).json({
            //... 실패한 업로드 목록을 반환하거나 다른 처리를 할 수 있음
        });
    } catch (err) {
        console.error(err);
        return res.status(500).json({ status: 'error', error: err.message });
    }
};

S3로 이미지를 업로드하는 메소드인 uploadedFiles와 OCR API 요청을 보내는 sendOCRRequest메소드를 사용하는데 두 메소드들 중에 어떤 것이 reject되어 요청이 실패했는지 구별하여 에러처리를 하려다 보니 Promise.allSettled()을 사용할 수도 있겠단 생각이 들어 두 메소드의 차이를 알아보았다.

 

 

차이점

  • Promise.all(): promise 배열에 reject가 포함되면 전체 promise가 reject으로 간주되어 catch 구문에서 처리된다. 따라서 reject를 포함할 경우 다른 promise의 처리 결과를 기다리지 않아 reject이 발생하면 빠르게 처리할 수 있다.
  • Promise.allSettled(): reject, resolve의 여부에 상관없이 모든 promise의 처리가 완료된 결과를 반환한다.  모든 작업이 완료된 후에 작업이 성공했는지 실패했는지 여부와 각 작업의 결과를 확인할 수 있다. 반환값은 공식 매뉴얼에서 확인할 수 있다.

주요 차이점은 reject이 발생했을 때 다른 promise 작업들을 계속 이어할 수 있느냐 없느냐의 차이이다. 상황에 따라 유연하게 적용해 선택할 수 있다.

 

 

적용 시 고려사항

Promise.all은 모든 promise()가 성공해야 하는 경우에 사용하고, Promise.allSettled()는 실패 여부에 상관없이 promise의 처리가 완료되기를 기다리며 결과를 처리하고자 할 때 사용하는 것이 적절하다.

 

적용

나의 경우에는 이미지가 모두 S3에 업로드가 되어야 업로드된 이미지를 바탕으로 OCR 추출을 진행할 수 있다. 따라서 앞의 작업이 성공적으로 완료되어야만 뒤의 작업도 진행할 수 있다.

따라서 굳이 모든 작업의 결괏값을 가져오는 Promise.allSettled()를 사용할 필요가 없다고 판단하였다.

uploadedFiles와 sendOCRRequest 중에 어떤 것에서 reject가 발생했는지 확인하기 위해 Promise.allSettled()를 사용하기보다는 uploadFailures의 길이를 확인하여 에러를 발생시키도록 하였다.

const uploadFailures = s3Results.filter(s3Result => s3Result.$metadata.httpStatusCode !== 200);

if (uploadFailures.length > 0) {
    throw new Error("S3 upload has been failed");
}

참고

https://stackoverflow.com/questions/59784175/differences-between-promise-all-and-promise-allsettled-in-js

https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EB%8D%94%EC%9D%B4%EC%83%81-Promiseall-%EC%93%B0%EC%A7%80%EB%A7%90%EA%B3%A0-PromiseallSettled-%EC%82%AC%EC%9A%A9%ED%95%98%EC%9E%90

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled

 

댓글