programing

node.js 스트림을 사용한 오류 처리

kingscode 2023. 8. 9. 22:20
반응형

node.js 스트림을 사용한 오류 처리

스트림의 오류를 처리하는 올바른 방법은 무엇입니까?여러분이 들을 수 있는 '오류' 이벤트가 있다는 것은 이미 알고 있지만, 저는 임의로 복잡한 상황에 대해 좀 더 자세히 알고 싶습니다.

우선 간단한 파이프 체인을 수행하려면 어떻게 해야 합니까?

input.pipe(transformA).pipe(transformB).pipe(transformC)...

그리고 오류가 올바르게 처리되도록 이러한 변환 중 하나를 올바르게 생성하는 방법은 무엇입니까?

더 많은 관련 질문:

  • 오류가 발생하면 '종료' 이벤트는 어떻게 됩니까?절대 발사되지 않나요?가끔 불이 나요?변환/스트림에 따라 달라집니까?여기는 기준이 무엇입니까?
  • 파이프를 통해 오류를 전파하는 메커니즘이 있습니까?
  • 도메인은 이 문제를 효과적으로 해결합니까?예를 들면 좋을 것 같습니다.
  • '오류' 이벤트에서 발생하는 오류에 스택 추적이 있습니까?가끔은?한 번도?그들에게서 하나를 얻을 수 있는 방법이 있습니까?

변형시키다

변환 스트림은 읽기와 쓰기가 모두 가능하므로 '중간' 스트림이 매우 좋습니다.이러한 이유로, 그들은 때때로 다음과 같이 언급됩니다.through하는 것이 할 수 있는 합니다.데이터를 전송하는 것이 아니라 데이터를 조작할 수 있는 훌륭한 인터페이스를 제공한다는 점을 제외하면 이러한 점에서 이중 스트림과 유사합니다.변환 스트림의 목적은 데이터가 스트림을 통과할 때 데이터를 조작하는 것입니다.예를 들어 비동기 호출을 수행하거나 두 개의 필드를 도출하거나 일부 항목을 다시 매핑하는 등의 작업을 수행할 수 있습니다.


Where you might put a transform stream


변환 스트림을 만드는 방법은 여기 및 여기를 참조하십시오.당신이 해야 할 일은 다음과 같습니다.

  1. 스트림 모듈 포함
  2. 변환 클래스를 인스턴스화(또는 상속)합니다.
  3. 을합니다를 _transform을 취하는 (chunk, encoding, callback).

청크가 데이터입니다.대부분의 경우 작업 중인 경우 인코딩에 대해 걱정할 필요가 없습니다.objectMode = true청크 처리가 완료되면 콜백이 호출됩니다.그런 다음 이 청크는 다음 스트림으로 푸시됩니다.

스트림을 정말 쉽게 통과할 수 있는 멋진 도우미 모듈을 원한다면 2를 통해 제안합니다.

오류 처리에 대해서는 계속 읽으십시오.

피리를

파이프 체인에서 오류를 처리하는 것은 실제로 간단하지 않습니다. 스레드에 따르면 .pipe()는 오류를 전달하도록 빌드되지 않습니다.그러니까...

var a = createStream();
a.pipe(b).pipe(c).on('error', function(e){handleError(e)});

합니다.c에서 에러 a그것은 전해지지 않을 것이고, 사실, 던질 것입니다.이 작업을 올바르게 수행하는 방법:

var a = createStream();
a.on('error', function(e){handleError(e)})
.pipe(b)
.on('error', function(e){handleError(e)})
.pipe(c)
.on('error', function(e){handleError(e)});

두 번째 방법은 더 장황하지만 적어도 오류가 발생하는 상황은 유지할 수 있습니다.이것은 보통 좋은 것입니다.

그러나 목적지의 오류만 캡처하고 발생한 위치에 대해 크게 신경 쓰지 않는 경우에 도움이 되는 라이브러리가 하나 있습니다.

끝.

오류 이벤트가 발생하면 종료 이벤트가 발생하지 않습니다(명시적으로).오류 이벤트가 발생하면 스트림이 종료됩니다.

도메인

제 경험상 도메인은 대부분의 시간 동안 정말 잘 작동합니다.처리되지 않은 오류 이벤트(즉, 수신기가 없는 스트림에서 오류 발생)가 있는 경우 서버가 충돌할 수 있습니다.이제 위의 기사에서 지적한 것처럼 모든 오류를 제대로 감지할 수 있는 도메인으로 스트림을 래핑할 수 있습니다.

var d = domain.create();
 d.on('error', handleAllErrors);
 d.run(function() {
     fs.createReadStream(tarball)
       .pipe(gzip.Gunzip())
       .pipe(tar.Extract({ path: targetPath }))
       .on('close', cb);
 });
  • 위의 코드 샘플은 이 게시물에서 온 것입니다.

도메인의 장점은 스택 추적을 보존한다는 것입니다.이벤트 스트림도 이 작업을 잘 수행합니다.

자세한 내용은 스트림1 핸드북을 참조하십시오.깊이는 있지만 매우 유용하고 많은 유용한 모듈에 대한 훌륭한 링크를 제공합니다.

1: 참고: 링크는 원래 GitHub repo가 2022년 8월경에 삭제되었기 때문에 archive.org 을 가리킵니다.

node >= v10.0.0을 사용하는 경우 stream.sys stream사용할 수 있습니다.완성된

예:

const { pipeline, finished } = require('stream');

pipeline(
  input, 
  transformA, 
  transformB, 
  transformC, 
  (err) => {
    if (err) {
      console.error('Pipeline failed', err);
    } else {
      console.log('Pipeline succeeded');
    }
});


finished(input, (err) => {
  if (err) {
    console.error('Stream failed', err);
  } else {
    console.log('Stream is done reading');
  }
});

자세한 내용은 이 Github PR을 참조하십시오.

도메인이 더 이상 사용되지 않습니다.당신은 그것들이 필요하지 않습니다.

이 질문에서는 변환 또는 쓰기 가능 여부를 구분하는 것이 그다지 중요하지 않습니다.

mshell_http의 답변은 좋지만, 오류가 발생할 수 있다고 생각되는 각 스트림의 오류 이벤트를 명시적으로 청취하고 원하는 경우 핸들러 기능을 다시 사용할 수도 있습니다.

var a = createReadableStream()
var b = anotherTypeOfStream()
var c = createWriteStream()

a.on('error', handler)
b.on('error', handler)
c.on('error', handler)

a.pipe(b).pipe(c)

function handler (err) { console.log(err) }

그렇게 함으로써 스트림 중 하나가 오류 이벤트를 발생시킬 경우 악명 높은 잡히지 않은 예외를 방지합니다.

전체 체인의 오류는 간단한 함수를 사용하여 맨 오른쪽 스트림으로 전파될 수 있습니다.

function safePipe (readable, transforms) {
    while (transforms.length > 0) {
        var new_readable = transforms.shift();
        readable.on("error", function(e) { new_readable.emit("error", e); });
        readable.pipe(new_readable);
        readable = new_readable;
    }
    return readable;
}

다음과 같이 사용할 수 있습니다.

safePipe(readable, [ transform1, transform2, ... ]);

.on("error", handler)스트림 오류만 처리하지만 사용자 지정 변환 스트림을 사용하는 경우.on("error", handler)내부에서 발생하는 오류를 감지하지 마십시오._transform기능.애플리케이션 흐름을 제어하기 위해 다음과 같은 작업을 수행할 수 있습니다.

this의 키워드._transform함수는 다음과 같습니다.Stream그 자체, 즉EventEmitter사용할 수 있습니다.try catch오류를 발견하고 나중에 사용자 지정 이벤트 처리기에 전달하려면 아래와 같이 하십시오.

// CustomTransform.js
CustomTransformStream.prototype._transform = function (data, enc, done) {
  var stream = this
  try {
    // Do your transform code
  } catch (e) {
    // Now based on the error type, with an if or switch statement
    stream.emit("CTError1", e)
    stream.emit("CTError2", e)
  }
  done()
}

// StreamImplementation.js
someReadStream
  .pipe(CustomTransformStream)
  .on("CTError1", function (e) { console.log(e) })
  .on("CTError2", function (e) { /*Lets do something else*/ })
  .pipe(someWriteStream)

이렇게 하면 논리 및 오류 처리기를 별도로 유지할 수 있습니다.또한 일부 오류만 처리하고 다른 오류는 무시하도록 선택할 수 있습니다.

갱신하다
대안: RXJS 관찰 가능

다중 파이프 패키지를 사용하여 여러 스트림을 하나의 이중 스트림으로 결합합니다.한 곳에서 오류를 처리할 수 있습니다.

const pipe = require('multipipe')

// pipe streams
const stream = pipe(streamA, streamB, streamC) 


// centralized error handling
stream.on('error', fn)

Transform stream mechanics를 생성하고 콜백을 호출하여 Node.js 패턴 사용done오류를 전파하기 위한 인수 포함:

var transformStream1 = new stream.Transform(/*{objectMode: true}*/);

transformStream1.prototype._transform = function (chunk, encoding, done) {
  //var stream = this;

  try {
    // Do your transform code
    /* ... */
  } catch (error) {
    // nodejs style for propagating an error
    return done(error);
  }

  // Here, everything went well
  done();
}

// Let's use the transform stream, assuming `someReadStream`
// and `someWriteStream` have been defined before
someReadStream
  .pipe(transformStream1)
  .on('error', function (error) {
    console.error('Error in transformStream1:');
    console.error(error);
    process.exit(-1);
   })
  .pipe(someWriteStream)
  .on('close', function () {
    console.log('OK.');
    process.exit();
  })
  .on('error', function (error) {
    console.error(error);
    process.exit(-1);
   });
const http = require('http');
const fs = require('fs');
const server = http.createServer();

server.on('request',(req,res)=>{
    const readableStream = fs.createReadStream(__dirname+'/README.md');
    const writeableStream = fs.createWriteStream(__dirname+'/assets/test.txt');
    readableStream
    .on('error',()=>{
        res.end("File not found")
    })
    .pipe(writeableStream)
    .on('error',(error)=>{
        console.log(error)
        res.end("Something went to wrong!")
    })
    .on('finish',()=>{
        res.end("Done!")
    })
})

server.listen(8000,()=>{
    console.log("Server is running in 8000 port")
})

호출 코드가 이미 종료된 후에 발생하기 때문에 스트림에서 발생한 오류는 캡처되지 않습니다.다음 문서를 참조할 수 있습니다.

https://nodejs.org/dist/latest-v10.x/docs/api/errors.html

언급URL : https://stackoverflow.com/questions/21771220/error-handling-with-node-js-streams

반응형