sourcetip

Node.js 모범 사례 예외 처리

fileupload 2023. 5. 18. 21:25
반응형

Node.js 모범 사례 예외 처리

나는 며칠 전에 node.js를 시도하기 시작했습니다.프로그램에 처리되지 않은 예외가 있을 때마다 노드가 종료된다는 것을 깨달았습니다.처리되지 않은 예외가 발생할 때 작업자 스레드만 죽고 컨테이너는 여전히 요청을 수신할 수 있는 일반 서버 컨테이너와는 다릅니다.이로 인해 다음과 같은 몇 가지 질문이 제기됩니다.

  • 아이즈process.on('uncaughtException')그것을 막는 유일한 효과적인 방법은?
  • 할 것이다process.on('uncaughtException')비동기 프로세스를 실행하는 동안에도 처리되지 않은 예외가 발생합니까?
  • 감지되지 않은 예외의 경우 활용할 수 있는 이미 구축된 모듈(예: 이메일 보내기 또는 파일 쓰기)이 있습니까?

node.js에서 발견되지 않은 예외를 처리하기 위한 일반적인 모범 사례를 보여줄 수 있는 포인터/기사를 주시면 감사하겠습니다.

업데이트: Joyent는 이제 그들만의 가이드를 가지고 있습니다.다음 정보는 요약에 더 가깝습니다.

안전하게 "던지기" 오류

문자 그대로 오류를 던지는 대신 코드 아키텍처에 따라 다음 방법 중 하나를 사용하여 오류를 안전하게 "던질" 수 있기 때문에 탐지되지 않은 오류를 최대한 방지하는 것이 이상적입니다.

  • 동기화 코드의 경우 오류가 발생하면 다음 오류를 반환합니다.

    // Define divider as a syncrhonous function
    var divideSync = function(x,y) {
        // if error condition?
        if ( y === 0 ) {
            // "throw" the error safely by returning it
            return new Error("Can't divide by zero")
        }
        else {
            // no error occured, continue on
            return x/y
        }
    }
    
    // Divide 4/2
    var result = divideSync(4,2)
    // did an error occur?
    if ( result instanceof Error ) {
        // handle the error safely
        console.log('4/2=err', result)
    }
    else {
        // no error occured, continue on
        console.log('4/2='+result)
    }
    
    // Divide 4/0
    result = divideSync(4,0)
    // did an error occur?
    if ( result instanceof Error ) {
        // handle the error safely
        console.log('4/0=err', result)
    }
    else {
        // no error occured, continue on
        console.log('4/0='+result)
    }
    
  • 기반 비동기) , 의 첫 인수는 " " " " " (" " " " " " " " " 입니다.errerr 오니다입입니다. 오류가 발생하지 않으면err이라null 모든 는 " 인수다같습다니음과는다른▁the다니" 뒤에 .err인수:

    var divide = function(x,y,next) {
        // if error condition?
        if ( y === 0 ) {
            // "throw" the error safely by calling the completion callback
            // with the first argument being the error
            next(new Error("Can't divide by zero"))
        }
        else {
            // no error occured, continue on
            next(null, x/y)
        }
    }
    
    divide(4,2,function(err,result){
        // did an error occur?
        if ( err ) {
            // handle the error safely
            console.log('4/2=err', err)
        }
        else {
            // no error occured, continue on
            console.log('4/2='+result)
        }
    })
    
    divide(4,0,function(err,result){
        // did an error occur?
        if ( err ) {
            // handle the error safely
            console.log('4/0=err', err)
        }
        else {
            // no error occured, continue on
            console.log('4/0='+result)
        }
    })
    
  • 오류가 발생할 수 있는 이벤트 코드의 경우 오류를 던지는 대신 이벤트를 실행합니다.

    // Definite our Divider Event Emitter
    var events = require('events')
    var Divider = function(){
        events.EventEmitter.call(this)
    }
    require('util').inherits(Divider, events.EventEmitter)
    
    // Add the divide function
    Divider.prototype.divide = function(x,y){
        // if error condition?
        if ( y === 0 ) {
            // "throw" the error safely by emitting it
            var err = new Error("Can't divide by zero")
            this.emit('error', err)
        }
        else {
            // no error occured, continue on
            this.emit('divided', x, y, x/y)
        }
    
        // Chain
        return this;
    }
    
    // Create our divider and listen for errors
    var divider = new Divider()
    divider.on('error', function(err){
        // handle the error safely
        console.log(err)
    })
    divider.on('divided', function(x,y,result){
        console.log(x+'/'+y+'='+result)
    })
    
    // Divide
    divider.divide(4,2).divide(4,0)
    

안전하게 오류를 "획득"

그러나 때때로 우리가 안전하게 탐지하지 못할 경우 응용프로그램이 손상되고 탐지되지 않은 예외가 발생할 수 있는 오류를 어딘가에 발생시키는 코드가 여전히 존재할 수 있습니다.코드 아키텍처에 따라 다음 방법 중 하나를 사용하여 코드를 파악할 수 있습니다.

  • 오류가 발생하는 위치를 알면 해당 섹션을 node.js 도메인으로 래핑할 수 있습니다.

    var d = require('domain').create()
    d.on('error', function(err){
        // handle the error safely
        console.log(err)
    })
    
    // catch the uncaught errors in this asynchronous or synchronous code block
    d.run(function(){
        // the asynchronous or synchronous code that we want to catch thrown errors on
        var err = new Error('example')
        throw err
    })
    
  • 오류가 발생하는 위치가 동기식 코드이며 어떤 이유로 도메인(아마도 이전 버전의 노드)을 사용할 수 없는 경우 try catch 문을 사용할 수 있습니다.

    // catch the uncaught errors in this synchronous code block
    // try catch statements only work on synchronous code
    try {
        // the synchronous code that we want to catch thrown errors on
        var err = new Error('example')
        throw err
    } catch (err) {
        // handle the error safely
        console.log(err)
    }
    

    단, 사용하지 않도록 주의하십시오.try...catch비동기식 코드에서는 비동기식으로 던져진 오류가 발견되지 않습니다.

    try {
        setTimeout(function(){
            var err = new Error('example')
            throw err
        }, 1000)
    }
    catch (err) {
        // Example error won't be caught here... crashing our app
        // hence the need for domains
    }
    

    당신이 .try..catch코드와 7때 노드 7.4 이실 행때비코기함드사다있수습을 사용할 수 .async/await기본적으로 비동기 함수를 작성합니다.

    또 하나 주의할 점은try...catch을 료완콜 포위있험습다니이장할서내부에백을 .try다음과 같은 진술:

    var divide = function(x,y,next) {
        // if error condition?
        if ( y === 0 ) {
            // "throw" the error safely by calling the completion callback
            // with the first argument being the error
            next(new Error("Can't divide by zero"))
        }
        else {
            // no error occured, continue on
            next(null, x/y)
        }
    }
    
    var continueElsewhere = function(err, result){
            throw new Error('elsewhere has failed')
    }
    
    try {
            divide(4, 2, continueElsewhere)
            // ^ the execution of divide, and the execution of 
            //   continueElsewhere will be inside the try statement
    }
    catch (err) {
            console.log(err.stack)
            // ^ will output the "unexpected" result of: elsewhere has failed
    }
    

    코드가 복잡해짐에 따라 이 gotcha는 매우 쉽게 수행할 수 있습니다.따라서 도메인을 사용하거나 오류를 반환하여 (1) 비동기 코드에서 포착되지 않은 예외를 방지하는 것이 가장 좋습니다. (2) 시도 탐지 실행에서 원하지 않는 실행을 방지합니다.JavaScript의 비동기 이벤트 머신 스타일 대신 적절한 스레드를 허용하는 언어에서는 이 문제가 덜합니다.

  • 스테이트먼트에▁not,▁using▁happens▁finally▁in▁applic▁by▁our▁make▁we▁can▁that▁or▁in▁crash않,▁a수▁domain할▁statement▁a▁catch있중▁in▁anaught▁the▁place습록도▁unc▁try▁wasn▁error▁where▁case니▁a프마지다단되'지이uncaughtException수신기(그러나 이렇게 하면 응용 프로그램이 알 수 없는 상태가 될 수 있음):

    // catch the uncaught errors that weren't wrapped in a domain or try catch statement
    // do not use this in modules, but only in applications, as otherwise we could have multiple of these bound
    process.on('uncaughtException', function(err) {
        // handle the error safely
        console.log(err)
    })
    
    // the asynchronous or synchronous code that emits the otherwise uncaught error
    var err = new Error('example')
    throw err
    

다음은 코드 예제와 선택한 블로그 게시물의 인용문을 포함하여 이 주제에 대한 다양한 출처의 요약 및 큐레이션입니다.모범 사례의 전체 목록은 여기에서 확인할 수 있습니다.


노드의 모범 사례.JS 오류 처리


1번:비동기 오류 처리를 위한 약속 사용

TL;DR: 콜백 스타일로 비동기 오류를 처리하는 것이 아마도 지옥으로 가는 가장 빠른 방법일 것입니다(일명 종말의 피라미드).당신이 당신의 코드에 줄 수 있는 가장 좋은 선물은 대신에 try-catch와 같은 매우 작고 친숙한 코드 구문을 제공하는 평판이 좋은 약속 라이브러리를 사용하는 것입니다.

그렇지 않은 경우:Node.JS 콜백 스타일, 함수(err, response)는 일상적인 코드와 오류 처리, 과도한 중첩 및 어색한 코딩 패턴의 혼합으로 인해 유지할 수 없는 코드에 대한 유망한 방법입니다.

코드 예제 - 양호

doWork()
.then(doWork)
.then(doError)
.then(doWork)
.catch(errorHandler)
.then(verify);

코드 예제 안티 패턴 – 콜백 스타일 오류 처리

getData(someParameter, function(err, result){
    if(err != null)
      //do something like calling the given callback function and pass the error
    getMoreData(a, function(err, result){
          if(err != null)
            //do something like calling the given callback function and pass the error
        getMoreData(b, function(c){ 
                getMoreData(d, function(e){ 
                    ...
                });
            });
        });
    });
});

블로그 인용: "우리는 약속에 문제가 있습니다" (블로그 pouchdb에서, "노드 약속" 키워드 11위)

"…실제로 콜백은 훨씬 더 사악한 일을 합니다. 즉, 우리가 프로그래밍 언어에서 당연하게 여기는 스택을 빼앗는 것입니다.스택 없이 코드를 작성하는 것은 브레이크 페달을 밟지 않고 차를 운전하는 것과 매우 비슷합니다. 여러분은 그것이 얼마나 절실히 필요한지 깨닫지 못합니다. 손을 뻗어서 그것이 거기에 있지 않을 때까지 말입니다.약속의 요점은 우리가 비동기식으로 갔을 때 잃어버린 언어의 기초를 돌려주는 것입니다. 반환, 던지기, 그리고 스택. 하지만 약속을 이용하기 위해서는 약속을 올바르게 사용하는 방법을 알아야 합니다.


2번:기본 제공 오류 개체만 사용

TL;DR: 오류가 발생하는 코드를 문자열 또는 사용자 지정 유형으로 보는 것은 매우 일반적입니다. 이는 오류 처리 로직과 모듈 간의 상호 운용성을 복잡하게 만듭니다.약속을 거부하든, 예외를 던지거나 오류를 발생시키든 - 노드를 사용합니다.JS 내장 오류 개체는 일관성을 높이고 오류 정보의 손실을 방지합니다.

그렇지 않은 경우:일부 모듈을 실행할 때 어떤 유형의 오류가 반환되는지 불확실하기 때문에 향후 예외를 추론하고 처리하기가 훨씬 어렵습니다.사용자 지정 유형을 사용하여 오류를 설명하면 스택 추적과 같은 중요한 오류 정보가 손실될 수 있습니다.

코드 예제 - 올바르게 수행

    //throwing an Error from typical function, whether sync or async
 if(!productToAdd)
 throw new Error("How can I add new product when no value provided?");

//'throwing' an Error from EventEmitter
const myEmitter = new MyEmitter();
myEmitter.emit('error', new Error('whoops!'));

//'throwing' an Error from a Promise
 return new promise(function (resolve, reject) {
 DAL.getProduct(productToAdd.id).then((existingProduct) =>{
 if(existingProduct != null)
 return reject(new Error("Why fooling us and trying to add an existing product?"));

코드 예제 안티 패턴

//throwing a String lacks any stack trace information and other important properties
if(!productToAdd)
    throw ("How can I add new product when no value provided?");

블로그 인용: "문자열은 오류가 아닙니다." (블로그 개발 사상에서, "노드" 키워드로 6위를 차지했습니다.JS 오류 개체")

"…오류 대신 문자열을 지정하면 모듈 간의 상호 운용성이 저하됩니다. 오류 검사 인스턴스를 수행 중이거나 오류에 대해 자세히 알고자 하는 API와의 계약을 위반합니다.오류 개체는 생성자에게 전달된 메시지를 유지하는 것 외에도 현대 자바스크립트 엔진에서 매우 흥미로운 속성을 가집니다."


3번:운영 오류와 프로그래머 오류 구분

TL;DR: 작업 오류(예: 잘못된 입력을 받은 API)는 오류 영향을 완전히 이해하고 신중하게 처리할 수 있는 알려진 경우를 말합니다.반면에 프로그래머 오류(예: 정의되지 않은 변수를 읽으려 함)는 응용 프로그램을 정상적으로 다시 시작하도록 지시하는 알 수 없는 코드 오류를 의미합니다.

그렇지 않은 경우:오류가 발생하면 항상 애플리케이션을 다시 시작할 수 있지만, 사소한 오류(운영 오류)로 인해 최대 5,000명의 온라인 사용자가 다운되는 이유는 무엇입니까?그 반대도 이상적이지 않습니다. 알 수 없는 문제(프로그래머 오류)가 발생했을 때 응용 프로그램을 계속 가동시키면 예기치 않은 동작이 발생할 수 있습니다.두 가지를 구분하면 전술적으로 행동하고 주어진 맥락에 따라 균형 잡힌 접근 방식을 적용할 수 있습니다.

코드 예제 - 올바르게 수행

    //throwing an Error from typical function, whether sync or async
 if(!productToAdd)
 throw new Error("How can I add new product when no value provided?");

//'throwing' an Error from EventEmitter
const myEmitter = new MyEmitter();
myEmitter.emit('error', new Error('whoops!'));

//'throwing' an Error from a Promise
 return new promise(function (resolve, reject) {
 DAL.getProduct(productToAdd.id).then((existingProduct) =>{
 if(existingProduct != null)
 return reject(new Error("Why fooling us and trying to add an existing product?"));

코드 예제 - 오류를 작동 가능한 것으로 표시(경고)

//marking an error object as operational 
var myError = new Error("How can I add new product when no value provided?");
myError.isOperational = true;

//or if you're using some centralized error factory (see other examples at the bullet "Use only the built-in Error object")
function appError(commonType, description, isOperational) {
    Error.call(this);
    Error.captureStackTrace(this);
    this.commonType = commonType;
    this.description = description;
    this.isOperational = isOperational;
};

throw new appError(errorManagement.commonErrors.InvalidInput, "Describe here what happened", true);

//error handling code within middleware
process.on('uncaughtException', function(error) {
    if(!error.isOperational)
        process.exit(1);
});

블로그 인용: "그렇지 않으면 국가를 위험에 빠뜨릴 수 있습니다." (블로그 디버그 가능성에서, "노드" 키워드로 3위를 차지했습니다.JS 발견되지 않은 예외")

"…JavaScript에서 스로우가 작동하는 방식의 특성상 참조를 유출하거나 정의되지 않은 취약한 상태를 만들지 않고는 안전하게 "멈춘 위치에서 픽업"할 수 있는 방법이 거의 없습니다. 느려진 오류에 가장 안전하게 대응하는 방법은 프로세스를 종료하는 것입니다.물론 일반 웹 서버에서는 많은 연결이 열려 있을 수 있으며, 다른 사용자에 의해 오류가 트리거되었기 때문에 이러한 연결을 갑자기 종료하는 것은 합리적이지 않습니다.더 나은 방법은 오류를 트리거한 요청에 대해 오류 응답을 보내고 다른 작업자는 정상 시간에 완료하도록 한 후 해당 작업자의 새 요청 수신을 중지하는 것입니다."


4번:미들웨어 내부가 아닌 중앙 집중식으로 오류 처리

TL;DR: 관리자에게 메일 및 로깅과 같은 오류 처리 로직은 오류가 발생할 때 모든 엔드포인트(예: Express 미들웨어, cron 작업, 유닛 테스트)가 호출하는 전용 중앙 개체에 캡슐화되어야 합니다.

그렇지 않은 경우:한 곳에서 오류를 처리하지 않으면 코드가 중복되고 잘못 처리되는 오류가 발생할 수 있습니다.

코드 예제 - 일반적인 오류 흐름

//DAL layer, we don't handle errors here
DB.addDocument(newCustomer, (error, result) => {
    if (error)
        throw new Error("Great error explanation comes here", other useful parameters)
});

//API route code, we catch both sync and async errors and forward to the middleware
try {
    customerService.addNew(req.body).then(function (result) {
        res.status(200).json(result);
    }).catch((error) => {
        next(error)
    });
}
catch (error) {
    next(error);
}

//Error handling middleware, we delegate the handling to the centrzlied error handler
app.use(function (err, req, res, next) {
    errorHandler.handleError(err).then((isOperationalError) => {
        if (!isOperationalError)
            next(err);
    });
});

블로그 인용: "때때로 하위 레벨에서는 호출자에게 오류를 전파하는 것 외에는 유용한 일을 할 수 없습니다." (블로그 Joyent에서 "Node" 키워드 1위를 차지했습니다.)JS 오류 처리")

"…스택의 여러 수준에서 동일한 오류를 처리할 수 있습니다.이 문제는 하위 수준이 호출자에게 오류를 전파하는 등의 오류를 호출자에게 전파하는 것 외에는 유용한 작업을 수행할 수 없는 경우에 발생합니다.대부분의 경우 작업을 재시도하거나 사용자에게 오류를 보고하거나 다른 작업을 수행할 때 적절한 응답이 무엇인지는 최상위 호출자만 알고 있습니다.그러나 콜백 자체가 어떤 맥락에서 오류가 발생했는지 알 수 없기 때문에 모든 오류를 단일 최상위 콜백에 보고해야 한다는 의미는 아닙니다.


5번: Swagger를 사용하여 API 오류를 문서화합니다.

TL;DR: API 호출자에게 반환될 수 있는 오류를 알려주어 충돌하지 않고 신중하게 처리할 수 있도록 합니다.이 작업은 일반적으로 Swagger와 같은 REST API 문서 프레임워크에서 수행됩니다.

그렇지 않은 경우:API 클라이언트는 이해할 수 없는 오류를 다시 수신했기 때문에 충돌 후 다시 시작하기로 결정할 수 있습니다.참고: API의 호출자는 사용자일 수 있습니다(마이크로서비스 환경에서는 매우 일반적).

블로그 인용: "발신자에게 어떤 오류가 발생할 수 있는지 알려야 합니다." (Joyent 블로그에서, "Node" 키워드 1위)JS 로깅")

…오류를 처리하는 방법에 대해 이야기했습니다만, 새 함수를 작성할 때 함수를 호출한 코드에 오류를 전달하는 방법은 무엇입니까?…어떤 오류가 발생할 수 있는지 모르거나 그 의미를 모르는 경우, 실수가 아닌 한 프로그램이 정확할 수 없습니다.따라서 새 기능을 작성하는 경우 발신자에게 발생할 수 있는 오류와 해당 오류의 의미를 알려주어야 합니다.


6번:낯선 사람이 마을에 오면 프로세스를 우아하게 종료합니다.

TL;DR: 알 수 없는 오류(개발자 오류, 모범 사례 번호 #3 참조)가 발생하면 애플리케이션 상태에 대한 불확실성이 있습니다.일반적으로 Forever 및 PM2와 같은 '재시동' 도구를 사용하여 신중하게 프로세스를 다시 시작할 것을 권장합니다.

그렇지 않은 경우:익숙하지 않은 예외가 감지되면 일부 개체가 장애 상태(예: 전체적으로 사용되고 일부 내부 오류로 인해 더 이상 이벤트를 발생시키지 않는 이벤트 이미터)일 수 있으며 이후의 모든 요청이 실패하거나 미친 듯이 작동할 수 있습니다.

코드 예제 - 충돌 여부 결정

//deciding whether to crash when an uncaught exception arrives
//Assuming developers mark known operational errors with error.isOperational=true, read best practice #3
process.on('uncaughtException', function(error) {
 errorManagement.handler.handleError(error);
 if(!errorManagement.handler.isTrustedError(error))
 process.exit(1)
});


//centralized error handler encapsulates error-handling related logic 
function errorHandler(){
 this.handleError = function (error) {
 return logger.logError(err).then(sendMailToAdminIfCritical).then(saveInOpsQueueIfCritical).then(determineIfOperationalError);
 }

 this.isTrustedError = function(error)
 {
 return error.isOperational;
 }

블로그 인용: "오류 처리에 대한 세 가지 생각이 있습니다." (블로그 jscieces에서)

…오류 처리에 대한 생각은 크게 세 가지로 나눌 수 있습니다. 1.응용 프로그램이 중단된 후 다시 시작합니다. 2. 발생할 수 있는 모든 오류를 처리하고 절대 충돌하지 않습니다. 3. 사이의 균형 잡힌 접근법


7번:성숙한 로거를 사용하여 오류 가시성 향상

TL;DR: Winston, Bunyan 또는 Log4J와 같은 성숙한 로깅 도구 세트는 오류 검색 및 이해를 가속화합니다.console.log는 잊어버리세요.

그렇지 않은 경우:console.logs를 훑어보거나 도구나 적절한 로그 뷰어를 쿼리하지 않고 지저분한 텍스트 파일을 수동으로 훑어보는 것은 늦은 시간까지 작업을 계속하게 할 수 있습니다.

코드 예 - 윈스턴 로거 작동 중

//your centralized logger object
var logger = new winston.Logger({
 level: 'info',
 transports: [
 new (winston.transports.Console)(),
 new (winston.transports.File)({ filename: 'somefile.log' })
 ]
 });

//custom code somewhere using the logger
logger.log('info', 'Test Log Message with some parameter %s', 'some parameter', { anything: 'This is metadata' });

블로그 인용문: "(로거에 대한) 몇 가지 요구 사항을 확인합니다." (블로그 강력 블로그에서)

…로거에 대한 몇 가지 요구 사항을 식별합니다. 1.각 로그 라인의 타임스탬프입니다.이것은 매우 자명합니다 – 당신은 각 로그 항목이 언제 발생했는지 알 수 있어야 합니다. 2. 로깅 형식은 기계뿐만 아니라 사람도 쉽게 소화할 수 있어야 합니다. 3.구성 가능한 여러 대상 스트림을 허용합니다.예를 들어, 추적 로그를 한 파일에 기록하지만 오류가 발생하면 동일한 파일에 기록한 다음 오류 파일에 기록하고 동시에 이메일을 보냅니다.


8번:APM 제품을 사용하여 오류 및 다운타임 발견

TL;DR: 코드베이스 또는 API를 사전에 측정하여 누락된 오류, 충돌 및 느린 부분을 자동으로 강조 표시할 수 있도록 모니터링 및 성능 제품(APM)

그렇지 않은 경우:API 성능과 다운타임을 측정하는 데 많은 노력을 기울일 수 있지만, 실제 시나리오에서 가장 느린 코드 부분이 무엇인지, UX에 어떤 영향을 미치는지는 결코 알지 못할 것입니다.

블로그 인용: "APM 제품 세그먼트"(블로그 요니 골드버그에서)

"…APM 제품은 세 가지 주요 부문을 구성합니다. 1. 사이트 또는 API 모니터링 – HTTP 요청을 통해 지속적으로 가동 시간 및 성능을 모니터링하는 외부 서비스입니다.몇 분 안에 설정할 수 있습니다.다음은 Pingdom, Uptime Robot 및 New Relict 2와 같은 몇 안 되는 경쟁업체입니다. 코드 인스트루멘테이션 – 느린 코드 감지, 예외 통계, 성능 모니터링 등의 이점을 얻기 위해 애플리케이션 내에 에이전트를 포함시켜야 하는 제품군입니다.다음은 몇 가지 선택된 경쟁업체입니다.새로운 유물, 앱 다이내믹스 3. 운영 인텔리전스 대시보드 – 이러한 제품군은 애플리케이션 성능을 쉽게 극대화하는 데 도움이 되는 메트릭 및 선별된 콘텐츠를 통해 운영 팀을 지원하는 데 중점을 둡니다.여기에는 일반적으로 여러 정보 소스(응용프로그램 로그, DB 로그, 서버 로그 등)를 집계하고 대시보드 설계 작업을 수행해야 합니다.다음은 몇 가지 선택된 경쟁업체입니다. Datadog, Splunk"


위의 내용은 단축 버전입니다. 여기에서 모범 사례예제를 더 참조하십시오.

적발되지 않은 예외는 적발할 수 있지만, 활용도가 제한적입니다.http://debuggable.com/posts/node-js-dealing-with-uncaught-exceptions:4c933d54-1428-443c-928d-4e1ecbdd56cb 을 참조하십시오.

monit,forever또는upstart충돌 시 노드 프로세스를 다시 시작하는 데 사용할 수 있습니다.정상 종료가 가장 좋습니다(예: 모든 메모리 내 데이터를 감지되지 않은 예외 처리기에 저장).

nodejs 도메인은 nodejs에서 오류를 처리하는 가장 최신의 방법입니다.도메인은 오류/기타 이벤트뿐만 아니라 기존에 발생한 개체도 캡처할 수 있습니다.도메인은 또한 인터셉트 메서드를 통해 첫 번째 인수로 전달된 오류가 있는 콜백을 처리하는 기능을 제공합니다.

일반적인 시도/캐치 스타일의 오류 처리와 마찬가지로 오류가 발생할 때 오류를 던지고 오류를 분리하려는 영역을 차단하여 코드의 나머지 부분에 영향을 미치지 않도록 하는 것이 좋습니다.이러한 영역을 "차단"하는 방법은 격리된 코드 블록으로 함수를 사용하여 domain.run을 호출하는 것입니다.

동기식 코드에서는 위의 내용으로 충분합니다. 오류가 발생할 경우 오류를 처리하거나 오류를 발견하고 처리하여 복구해야 할 데이터를 되돌립니다.

try {  
  //something
} catch(e) {
  // handle data reversion
  // probably log too
}

비동기 콜백에서 오류가 발생하면 데이터 롤백(공유 상태, 데이터베이스 등의 외부 데이터)을 완전히 처리할 수 있어야 합니다.또는 예외가 발생했음을 나타내는 항목을 설정해야 합니다. 이 플래그에 관심이 있는 경우에는 콜백이 완료될 때까지 기다려야 합니다.

var err = null;
var d = require('domain').create();
d.on('error', function(e) {
  err = e;
  // any additional error handling
}
d.run(function() { Fiber(function() {
  // do stuff
  var future = somethingAsynchronous();
  // more stuff

  future.wait(); // here we care about the error
  if(err != null) {
    // handle data reversion
    // probably log too
  }

})});

위의 코드 중 일부는 못생겼지만 더 예쁘게 만들 수 있는 패턴을 만들 수 있습니다. 예:

var specialDomain = specialDomain(function() {
  // do stuff
  var future = somethingAsynchronous();
  // more stuff

  future.wait(); // here we care about the error
  if(specialDomain.error()) {
    // handle data reversion
    // probably log too
  } 
}, function() { // "catch"
  // any additional error handling
});

업데이트(2013-09):

위에서, 저는 섬유 의미론을 내포하는 미래를 사용하는데, 이것은 당신이 미래를 줄을 서서 기다릴 수 있게 해줍니다.이것은 모든 것에 전통적인 트라이캐치 블록을 사용할 수 있게 해줍니다. 저는 이것이 가장 좋은 방법이라고 생각합니다.그러나 항상 이 작업을 수행할 수는 없습니다(브라우저에서).

섬유 의미론이 필요 없는 미래도 있습니다(일반 브라우저 자바스크립트와 함께 작동).이것들은 선물, 약속, 또는 연기라고 할 수 있습니다. (나는 이제부터 미래에 대해서만 언급하겠습니다.)일반 오래된 JavaScript 미래 라이브러리를 사용하면 미래 간에 오류를 전파할 수 있습니다.이러한 도서관 중 일부만 던져진 미래를 올바르게 처리할 수 있으므로 주의하십시오.

예:

returnsAFuture().then(function() {
  console.log('1')
  return doSomething() // also returns a future

}).then(function() {
  console.log('2')
  throw Error("oops an error was thrown")

}).then(function() {
  console.log('3')

}).catch(function(exception) {
  console.log('handler')
  // handle the exception
}).done()

이것은 조각이 비동기적이지만 일반적인 시도 캐치를 모방합니다.다음과 같이 인쇄됩니다.

1
2
handler

해당 흐름을 방해하는 예외가 발생했기 때문에 '3'은 인쇄되지 않습니다.

파랑새의 약속을 살펴보십시오.

이러한 라이브러리 외에 던져진 예외를 제대로 처리하는 라이브러리를 많이 찾지 못했습니다.예를 들어, jQuery는 연기되었습니다. "실패" 처리자는 절대 예외를 '그때' 처리자에게 던지지 않을 것입니다. 제 생각에는 거래를 깨는 사람입니다.

저는 최근에 http://snmaynard.com/2012/12/21/node-error-handling/ 에 이것에 대해 썼습니다.버전 0.8의 노드의 새로운 기능은 도메인이며 모든 형식의 오류 처리를 하나의 더 쉬운 관리 양식으로 결합할 수 있습니다.당신은 제 게시물에서 그들에 대해 읽을 수 있습니다.

또한 Bugsnag와 같은 것을 사용하여 탐지되지 않은 예외를 추적하고 이메일, 채팅방을 통해 알림을 받거나 탐지되지 않은 예외에 대한 티켓을 만들 수 있습니다(저는 Bugsnag의 공동 설립자입니다).

Try-catch를 사용하는 것이 적절할 수 있는 한 가지 예는 for Each 루프를 사용하는 경우입니다.동기식이지만 동시에 내부 범위에서 반환문만 사용할 수는 없습니다.대신 시도 및 포착 접근 방식을 사용하여 적절한 범위의 오류 개체를 반환할 수 있습니다.고려 사항:

function processArray() {
    try { 
       [1, 2, 3].forEach(function() { throw new Error('exception'); }); 
    } catch (e) { 
       return e; 
    }
}

위의 @balupton에서 설명한 접근 방식의 조합입니다.

Step.js 라이브러리를 추가하면 예외를 다음 단계 함수로 항상 전달하여 처리할 수 있습니다.따라서 마지막 단계로 이전 단계의 오류를 확인하는 기능을 사용할 수 있습니다.이 방법을 사용하면 오류 처리를 크게 간소화할 수 있습니다.

다음은 github 페이지의 인용문입니다.

던져진 예외는 포착되어 다음 함수의 첫 번째 인수로 전달됩니다.콜백 함수를 주요 함수에 중첩하지 않는 한, 발견되지 않은 예외가 발생하는 것을 방지합니다.이는 장시간 실행 중인 노드에 매우 중요합니다.JS 서버는 탐지되지 않은 예외 하나로 인해 전체 서버가 다운될 수 있습니다.

또한 단계를 사용하여 스크립트 실행을 제어하여 정리 섹션을 마지막 단계로 사용할 수 있습니다.예를 들어 Node에서 빌드 스크립트를 작성하고 쓰기에 소요된 시간을 보고하려는 경우 마지막 단계에서 이를 수행할 수 있습니다(마지막 콜백을 캐내는 대신).

여기서는 오류 파악에 대해 잘 설명했지만, 오류를 확인하고 수정할 수 있도록 오류를 로그아웃하는 것을 기억할 가치가 있습니다.

Bunyan은 NodeJS에 널리 사용되는 로깅 프레임워크로, console.log를 사용하지 않는 한 로컬 디버깅에 유용한 여러 출력 위치에 쓰기를 지원합니다.도메인의 오류 처리기에서 로그 파일에 오류를 뱉을 수 있습니다.

var log = bunyan.createLogger({
  name: 'myapp',
  streams: [
    {
      level: 'error',
      path: '/var/tmp/myapp-error.log'  // log ERROR to this file
    }
  ]
});

이는 확인해야 할 오류 및/또는 서버가 많은 경우 시간이 많이 소요될 수 있으므로, Raygun(Raygun에서 근무하고 있음)과 같은 툴을 검토하여 오류를 함께 그룹화하거나 둘 다 사용하는 것이 좋습니다.Raygun을 도구로 사용하기로 결정했다면 설정도 매우 쉽습니다.

var raygunClient = new raygun.Client().init({ apiKey: 'your API key' });
raygunClient.send(theError);

PM2 또는 영원히 같은 도구를 사용하면 앱이 충돌하고, 발생한 일을 로그아웃하고, 큰 문제 없이 재부팅할 수 있습니다.

얼마 전 이 게시물을 읽고 api/function 수준에서 예외 처리를 위해 도메인을 사용하는 것이 안전한지 궁금했습니다.제가 작성한 각 비동기 함수의 예외 처리 코드를 단순화하기 위해 사용하고 싶었습니다.각 기능에 대해 새 도메인을 사용하면 상당한 오버헤드가 발생할 것이라는 우려가 있었습니다.제 숙제는 최소한의 오버헤드가 있으며 일부 상황에서 시도 캐치보다 도메인에서 성능이 더 낫다는 것을 나타내는 것 같습니다.

http://www.lighthouselogic.com/ #/새로운 도메인을 사용하는 것-각-domain-for-domain-function-in-node/

Ubuntu(Ubuntu)에서 서비스를 사용하려면 다음을 수행합니다.Ubuntu 11.04 서비스로서의 노드(upstart, monitor and forever.js 포함)

  getCountryRegionData: (countryName, stateName) => {
    let countryData, stateData

    try {
      countryData = countries.find(
        country => country.countryName === countryName
      )
    } catch (error) {
      console.log(error.message)
      return error.message
    }

    try {
      stateData = countryData.regions.find(state => state.name === stateName)
    } catch (error) {
      console.log(error.message)
      return error.message
    }

    return {
      countryName: countryData.countryName,
      countryCode: countryData.countryShortCode,
      stateName: stateData.name,
      stateCode: stateData.shortCode,
    }
  },

언급URL : https://stackoverflow.com/questions/7310521/node-js-best-practice-exception-handling

반응형