프로그래밍 언어/HTML,CSS,JS

Node.js 모범 사례 예외 처리

Rateye 2021. 7. 8. 10:21
728x90
반응형

 

질문 : 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)
    }
  • 콜백 기반 (예. 비동기) 코드의 경우, 콜백의 첫 번째 인수는 err 오류가 발생하는 경우, err 오류가 다음 발생하지 않을 경우, 오류입니다 err 이다 null . 다른 모든 인수는 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)
        }
    })
  • 오류가 발생할 수있는 이벤트가 많은 코드의 경우 오류를 발생시키는error 이벤트를 대신 발생시킵니다.
    // 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)// 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 로 작업하려면 Node 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
    }
    이 문제는 코드가 더 복잡 해짐에 따라 수행하기 매우 쉽습니다. 따라서 도메인을 사용하거나 오류를 반환하여 (1) 비동기 코드에서 포착되지 않은 예외를 피하고 (2) 원하지 않는 실행 포착 시도를 방지하는 것이 가장 좋습니다. JavaScript의 비동기 이벤트 머신 스타일 대신 적절한 스레딩을 허용하는 언어에서는 이는 문제가되지 않습니다.
  • 마지막으로, 도메인이나 try catch 문에 래핑되지 않은 위치에서 포착되지 않은 오류가 발생하는 경우 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

 

출처 : https://stackoverflow.com/questions/7310521/node-js-best-practice-exception-handling
728x90
반응형