Węzeł.Obsługa wyjątków w zakresie najlepszych praktyk js

Właśnie zacząłem wypróbowywać node.js kilka dni temu. Zdałem sobie sprawę, że węzeł jest zakończony, gdy mam nieobsługiwany wyjątek w moim programie. Jest to inne niż zwykły kontener serwerowy, na który byłem narażony, gdzie tylko wątek roboczy umiera, gdy występują nieobsługiwane wyjątki i kontener nadal będzie mógł otrzymać żądanie. To rodzi kilka pytań:

  • czy process.on('uncaughtException') jest jedynym skutecznym sposobem ochrony przed nim?
  • will process.on('uncaughtException') catch the nieobsługiwany wyjątek również podczas wykonywania procesów asynchronicznych?
  • czy istnieje moduł, który jest już zbudowany (np. wysyłanie wiadomości e-mail lub pisanie do pliku), który mógłbym wykorzystać w przypadku nieprzewidzianych WYJĄTKÓW?

Byłbym wdzięczny za każdy wskaźnik / artykuł, który pokazałby mi wspólne najlepsze praktyki obsługi nieobciążonych WYJĄTKÓW w node.js

Author: Rakesh Sankar, 2011-09-05

10 answers

Aktualizacja: Joyent ma teraz swój własny przewodnik wspomniany w tej odpowiedzi . Poniższe informacje są bardziej podsumowaniem:

Bezpiecznie "rzucać" błędy

W idealnej sytuacji chcielibyśmy jak najwięcej uniknąć nieprzewidzianych błędów, jako takich, zamiast dosłownie rzucać błąd, możemy zamiast tego bezpiecznie "rzucać" błąd za pomocą jednej z następujących metod w zależności od naszej architektury kodu:]}

  • Dla kodu synchronicznego, jeśli wystąpi błąd, zwróć błąd:

    // 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)
    }
    
  • Dla połączeń zwrotnych (tj. asynchroniczny) kod, pierwszym argumentem wywołania zwrotnego jest err, jeśli wystąpi błąd err jest błędem, jeśli błąd nie wystąpi to err jest null. Wszelkie inne argumenty następują po argumencie 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)
        }
    })
    
  • Dla kodu, gdzie błąd może się zdarzyć w dowolnym miejscu, zamiast rzucać błąd, odpal error Zdarzenie zamiast :

    // 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)
    

Bezpiecznie " łapać" błędy

Czasami jednak nadal może istnieć kod, który wyrzuca gdzieś błąd, który może prowadzić do nieużywanego wyjątku i potencjalnej awarii naszej aplikacji, Jeśli nie złapiemy go bezpiecznie. W zależności od naszej architektury kodu możemy użyć jednej z następujących metod, aby go złapać:

  • Kiedy wiemy, gdzie występuje błąd, możemy zawinąć tę sekcję w węzeł .domena 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
    })
    
  • Jeśli wiemy, gdzie występuje błąd jest kod synchroniczny i z jakiegokolwiek powodu nie może używać domen (być może starej wersji node), możemy użyć instrukcji 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)
    }
    
    W kodzie asynchronicznie wyrzucony błąd nie zostanie wychwycony.]}
    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
    }
    

    Jeśli chcesz pracować z try..catch w połączeniu z kodem asynchronicznym, podczas uruchamiania Node 7.4 lub nowszego możesz użyć async/await natywnie do pisania funkcji asynchronicznych.

    Kolejna rzecz, na którą należy uważać o z {[14] } jest ryzyko zawijania zwrotnego zakończenia wewnątrz try oświadczenie tak:

    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
    }
    

    To gotcha jest bardzo łatwe do zrobienia, ponieważ twój kod staje się bardziej złożony. W związku z tym najlepiej jest użyć domen lub zwrócić błędy, aby uniknąć (1) nieobciążonych WYJĄTKÓW w kodzie asynchronicznym (2) try catch przechwytywania wykonania, którego nie chcesz. W językach, które pozwalają na prawidłowe threadowanie zamiast asynchronicznego stylu event-machine JavaScript, jest to mniej problem.

  • Wreszcie, w przypadku, gdy błąd wystąpi w miejscu, które nie było zawinięte w domenę lub instrukcję try catch, możemy sprawić, że nasza aplikacja nie ulegnie awarii za pomocą uncaughtException listener (jednak w ten sposób może umieścić aplikację w nieznanym stanie ):

    // 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
    
 656
Author: balupton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-29 13:13:39

Poniżej znajduje się podsumowanie i podsumowanie z wielu różnych źródeł na ten temat, w tym przykład kodu i cytaty z wybranych postów na blogu. Pełna lista najlepszych praktyk znajduje się tutaj


Najlepsze praktyki Node.Obsługa błędów JS


Number1: użyj obietnic do obsługi błędów asynchronicznych

TL; DR: Obsługa błędów asynchronicznych w stylu callback jest prawdopodobnie najszybszą drogą do piekła (a.k.a piramida zagłady). Na najlepszym prezentem, jaki możesz dać swojemu kodowi, jest użycie renomowanej biblioteki promise, która zapewnia znacznie zwartą i znajomą składnię kodu, taką jak try-catch {]}

W Przeciwnym Razie: Węzeł.Js callback style, function (err, response), jest obiecującym sposobem na nie-utrzymanie kodu ze względu na mieszankę obsługi błędów z przypadkowym kodem, nadmierne zagnieżdżanie i niezręczne wzorce kodowania

Przykład kodu-dobry

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

Przykład kodu anty pattern-błąd stylu wywołania zwrotnego obsługa

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){ 
                    ...
                });
            });
        });
    });
});

Cytat na blogu: "mamy problem z obietnicami" (Z bloga pouchdb, w rankingu 11 dla słów kluczowych "obietnice węzła")

"...a w rzeczywistości wywołania zwrotne robią coś jeszcze bardziej złowrogiego: pozbawiają nas stosu, co jest czymś, co zwykle uważamy za oczywiste w językach programowania. Pisanie kodu bez stosu jest jak jazda samochodem bez pedału hamulca: nie zdajesz sobie sprawy, jak bardzo go potrzebujesz, dopóki nie sięgniesz po niego i nie jest tam. całym celem obietnic jest zwrócenie nam podstaw językowych, które straciliśmy, gdy zaczęliśmy asynchronizować: return, throw, and the stack. Ale musisz wiedzieć, jak prawidłowo korzystać z obietnic, aby je wykorzystać."


Number2: używaj tylko wbudowanego obiektu błędu

TL; DR: dość często widzi się kod, który wyrzuca błędy jako ciąg znaków lub jako niestandardowy typ – komplikuje to logikę obsługi błędów i interoperacyjność między Moduły. Niezależnie od tego, czy odrzucasz obietnicę, wyrzucasz wyjątek, czy emitujesz błąd-używając węzła.JS wbudowany obiekt błędu zwiększa jednolitość i zapobiega utracie informacji o błędzie

W Przeciwnym Razie: podczas wykonywania jakiegoś modułu, niepewność, jaki typ błędów przychodzi w zamian-znacznie utrudnia rozumowanie o nadchodzącym wyjątku i obsługę go. Nawet warto, używanie niestandardowych typów do opisywania błędów może prowadzić do utraty krytycznych informacji o błędach, takich jak stos trace!

Przykład kodu-doing it right

    //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?"));

Przykład kodu anty pattern

//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?");

Cytat z bloga: "ciąg nie jest błędem" (Z bloga devthought, w rankingu 6 za słowa kluczowe " węzeł.Js error object")

"...przekazywanie ciągu znaków zamiast błędu skutkuje zmniejszoną interoperacyjnością między modułami. Łamie umowy z API, które mogą wykonywać instanceof kontroli błędów, lub które chcą wiedzieć więcej o błąd . Obiekty błędów, jak zobaczymy, mają bardzo ciekawe właściwości we współczesnych silnikach JavaScript poza utrzymaniem komunikatu przekazanego do konstruktora.."


Number3: rozróżnienie błędów operacyjnych i programistycznych

TL; DR: błędy operacyjne (np. API otrzymało nieprawidłowe dane wejściowe) odnoszą się do znanych przypadków, w których wpływ błędu jest w pełni zrozumiały i może być obsługiwany w sposób przemyślany. Z drugiej Strony błąd programisty (np. próba odczytania undefined zmienna) odnosi się do nieznanych błędów kodu, które nakazują ponowne uruchomienie aplikacji

W Przeciwnym Razie: zawsze możesz ponownie uruchomić aplikację, gdy pojawi się błąd, ale po co pozwalać ~5000 użytkownikom online z powodu niewielkiego i przewidywanego błędu (błędu operacyjnego)? przeciwieństwo nie jest również idealne – utrzymanie aplikacji, gdy wystąpił nieznany problem (błąd programisty), może prowadzić do nieprzewidywalnego zachowania. Rozróżnienie tych dwóch pozwala na taktyczne działanie i zastosowanie zrównoważone podejście oparte na danym kontekście

Przykład kodu-doing it right

    //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?"));

Przykład kodu-oznaczenie błędu jako operacyjny (zaufany)

//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);
});

Cytat na blogu: "inaczej ryzykujesz Państwo" (Z bloga debugable, w rankingu 3 dla słów kluczowych " węzeł.Js uncaught exception")

"...ze względu na to, jak throw działa w JavaScript, prawie nigdy nie ma sposobu, aby bezpiecznie " zacząć od miejsca, w którym skończyłeś", bez wycieków odniesień, czy tworzenia innego rodzaju nieokreślonego stanu kruchości. Najbezpieczniejszym sposobem odpowiedzi na wyrzucony błąd jest zamknięcie procesu . Oczywiście na normalnym serwerze internetowym możesz mieć wiele otwartych połączeń i nie jest rozsądne, aby je nagle wyłączyć, ponieważ błąd został wywołany przez kogoś innego. Lepszym podejściem jest wysłanie odpowiedzi błędu na żądanie, które wywołało błąd, pozwalając innym zakończyć w swoim normalnym czasie i zatrzymać słuchanie nowych próśb u tego pracownika "


Number4: obsługuje błędy centralnie, ale nie wewnątrz middleware

TL; DR: logika obsługi błędów, taka jak Poczta do administratora i logowanie, powinna być zamknięta w dedykowanym i scentralizowanym obiekcie, który wszystkie punkty końcowe (np.

W Przeciwnym Razie: Nie obsługa błędów w jednym miejscu doprowadzi do duplikacji kodu i prawdopodobnie do błędów, które są obsługiwane niewłaściwie

Przykład kodu-typowy przepływ błędów

//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);
    });
});

Cytat z bloga: "czasami niższe poziomy nie mogą zrobić nic użytecznego, poza propagowaniem błędu u rozmówcy" (Z bloga Joyent, w rankingu 1 za słowa kluczowe " węzeł.Obsługa błędów JS")

" ... możesz skończyć obsługi tego samego błędu na kilku poziomach stosu. Dzieje się tak, gdy niższe poziomy nie mogą zrobić nic użytecznego, z wyjątkiem propagacji błędu do ich rozmówcy, który propaguje błąd do rozmówcy, i tak dalej. Często tylko rozmówca najwyższego poziomu wie, jaka jest odpowiednia odpowiedź, czy to ponowna próba operacji, zgłoszenie błędu użytkownikowi, czy coś innego. Ale to nie znaczy, że należy próbować zgłaszać wszystkie błędy do jednego najwyższego poziomu callback, ponieważ to callback sam nie może wiedzieć, w jakim kontekście wystąpił błąd "


Number5: Document API errors using Swagger

TL; DR: niech Twoi rozmówcy API wiedzą, które błędy mogą przyjść w zamian, aby mogli sobie z nimi poradzić bez awarii. Zwykle odbywa się to za pomocą frameworków dokumentacji REST API, takich jak Swagger

W Przeciwnym Razie: klient API może zdecydować się na awarię i ponowne uruchomienie tylko dlatego, że otrzymał z powrotem błąd, którego nie mógł zrozumieć. Uwaga: wywołującym API może być ty (bardzo typowy w środowisku mikrousług)

Cytat z bloga: " musisz powiedzieć swoim rozmówcom jakie błędy może się zdarzyć" (Z bloga Joyent, w rankingu 1 za słowa kluczowe " węzeł.Js logging")

...rozmawialiśmy o tym, jak radzić sobie z błędami, ale kiedy piszesz nową funkcję, jak dostarczasz błędy do kodu, który wywołał twoją funkcję? ... Jeśli nie wiesz, jakie błędy mogą się zdarzyć lub nie wiesz, co one oznaczają, to twój program nie może być poprawny, chyba że przez przypadek. Więc jeśli piszesz nową funkcję, musisz powiedzieć swoim rozmówcom, jakie błędy mogą się zdarzyć i jakie są mea


Numer 6: Zamknij proces z wdziękiem, gdy obcy przychodzi do miasta

TL; DR: gdy wystąpi nieznany błąd (błąd programisty, patrz najlepsza praktyka numer # 3) - istnieje niepewność co do zdrowotności aplikacji. Powszechnie stosowana praktyka sugeruje ostrożne ponowne uruchomienie procesu za pomocą narzędzia "restarter", takiego jak Forever i PM2

W Przeciwnym Razie: gdy przechwycony zostanie nieznany wyjątek, jakiś obiekt może być w stanie wadliwym (np. Zdarzenie emiter, który jest używany globalnie i nie uruchamia już zdarzeń z powodu jakiejś wewnętrznej awarii) i wszystkie przyszłe żądania mogą zawieść lub zachowywać się szalenie

Przykład kodu-decydowanie o awarii

//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;
 }

Cytat z bloga: " istnieją trzy szkoły myślenia o obsłudze błędów" (Z bloga jsrecipes)

... istnieją przede wszystkim trzy szkoły myślenia o obsłudze błędów: 1. Pozwól aplikacji się zawiesić i uruchom ją ponownie. 2. Obsługa wszystkich możliwych błędów i nigdy się nie Rozbij. 3. Zrównoważone podejście między tymi dwoma


Number7: użyj dojrzałego rejestratora, aby zwiększyć widoczność błędów

TL; DR: zestaw dojrzałych narzędzi rejestrujących, takich jak Winston, Bunyan lub Log4J, przyspieszy wykrywanie i zrozumienie błędów. Więc zapomnij o konsoli.log.

W Przeciwnym Razie: dzienniki lub ręcznie za pomocą niechlujnego pliku tekstowego bez narzędzi do zapytań lub przyzwoitej przeglądarki dziennika mogą Cię zająć w pracy do późna

Przykład kodu-Winston logger w akcji

//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' });

Cytat z bloga: "pozwala określić kilka wymagań (dla loggera):" (Z bloga strongblog)

...pozwala określić kilka wymagań (dla REJESTRATORA): 1. Znacznik czasu każdej linii dziennika. Ten jest dość oczywisty – powinieneś być w stanie stwierdzić, kiedy wystąpił każdy wpis w dzienniku. 2. Format logowania powinien być łatwo przyswajalny zarówno przez ludzi, jak i maszyny. 3. Pozwala na wielokrotne konfigurowalne strumienie docelowe. Na przykład możesz zapisywać dzienniki śledzenia do jednego pliku, ale gdy wystąpi błąd, Zapisz do tego samego pliku, a następnie do pliku błędu i wyślij e-mail w tym samym czasie...


Number8: wykrywanie błędów i przestojów przy użyciu produktów APM

TL; DR: produkty do monitorowania i wydajności (aka APM) proaktywnie sprawdzają twoją bazę kodową lub API, dzięki czemu mogą automatycznie wyróżniać błędy, awarie i wolne części, które były brak

W Przeciwnym Razie: możesz poświęcić wiele wysiłku na mierzenie wydajności API i przestojów, prawdopodobnie nigdy nie będziesz świadomy, które są Twoje najwolniejsze części kodu w rzeczywistym scenariuszu i jak wpływają one na UX

Cytat z bloga: " segmenty produktów APM" (Z bloga Yoni Goldberg)

"...produkty APM stanowią 3 główne segmenty: 1. Monitorowanie witryny lub API- zewnętrzne usługi, które stale monitorują czas pracy i wydajność poprzez żądania HTTP. Można go skonfigurować w kilka minut. Oto kilka wybranych pretendentów: Pingdom, uptime Robot i New Relic 2. Oprzyrządowanie kodowe-rodzina produktów, które wymagają osadzenia agenta w aplikacji, aby skorzystać z funkcji powolnego wykrywania kodu,statystyk WYJĄTKÓW, monitorowania wydajności i wielu innych. Oto kilka wybranych kandydatów: New Relic, App Dynamics 3. Operational intelligence dashboard- Ta linia produktów koncentruje się na ułatwianie zespołu ops dzięki metrykom i wyselekcjonowanym treściom, które pomagają w łatwym utrzymaniu wydajności aplikacji. Zwykle wiąże się to z agregacją wielu źródeł informacji (Dzienniki aplikacji, dzienniki DB, dzienniki serwerów itp.) i pracami projektowymi z góry. Poniżej znajduje się kilka wybranych pretendentów: Datadog, Splunk "


powyższa wersja jest skrócona- zobacz tutaj więcej najlepszych praktyk i przykładów

 62
Author: Yonatan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-18 20:21:04

Można wyłapywać nieprzewidziane wyjątki, ale mają ograniczone zastosowanie. Zobacz też http://debuggable.com/posts/node-js-dealing-with-uncaught-exceptions:4c933d54-1428-443c-928d-4e1ecbdd56cb

monit, forever lub upstart może być użyty do ponownego uruchomienia procesu węzła, gdy ulega awarii. Najlepsze jest pełne wdzięku zamknięcie (np. zapisz wszystkie dane w pamięci w nieobciążonym programie obsługi wyjątków).

 27
Author: nponeccop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-10 22:13:56

Domeny Nodejs to najbardziej aktualny sposób obsługi błędów w nodejs. Domeny mogą przechwytywać zarówno błędy/inne zdarzenia, jak i tradycyjnie rzucane obiekty. Domeny zapewniają również funkcjonalność obsługi wywołań zwrotnych z błędem przekazywanym jako pierwszy argument za pomocą metody intercept.

Podobnie jak w przypadku normalnej obsługi błędów w stylu try/catch, zwykle najlepiej jest wyrzucać błędy, gdy występują, i blokować obszary, w których chcesz odizolować błędy od wpływu na resztę kod. Sposobem na "zablokowanie" tych obszarów jest wywołanie domeny.Uruchom z funkcją jako blok izolowanego kodu.

W kodzie synchronicznym, powyższe wystarczy - gdy wystąpi błąd, pozwalasz mu zostać wyrzuconym, lub łapiesz go i obsługujesz tam, przywracając wszystkie dane, które musisz przywrócić.

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

Gdy błąd występuje w asynchronicznym wywołaniu zwrotnym, musisz być w stanie w pełni obsłużyć wycofanie danych (stan współdzielony, dane zewnętrzne, takie jak bazy danych, itp.). Albo musisz Ustaw coś, aby wskazać, że wystąpił wyjątek-jeśli kiedykolwiek zależy ci na tej fladze, musisz poczekać na zakończenie połączenia zwrotnego.

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
  }

})});

Część z tego powyższego kodu jest brzydka, ale można tworzyć szablony dla siebie, aby było ładniej, np:

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
});

Aktualizacja (2013-09):

Powyżej używam przyszłości, która implikuje semantykę włókien , która pozwala czekać na futures in-line. Pozwala to na korzystanie z tradycyjnego try-catch bloki na Wszystko - co uważam za najlepszą drogę. Jednak nie zawsze można to zrobić(np. w przeglądarce)...

Istnieją również futures, które nie wymagają semantyki włókien (które następnie działają z normalnym, przeglądarkowym JavaScript). Mogą one być nazywane futures, obietnice, lub deferreds(będę tylko odnosić się do futures od teraz). Biblioteki futures Plain-old-JavaScript pozwalają propagować błędy między futuresami. Tylko niektóre z tych bibliotek pozwalają na dowolną przyszłość prawidłowo obsługiwane, więc uważaj.

Przykład:

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()
To imituje normalny chwyt próbny, mimo że elementy są asynchroniczne. Wydrukuje:
1
2
handler

Zauważ, że nie wyświetla "3", ponieważ został wyrzucony wyjątek, który przerywa ten przepływ.

Spójrz na obietnice bluebird:

Zauważ, że nie znalazłem wielu innych bibliotek poza tymi, które poprawnie obsługują rzucane wyjątki. jQuery odroczony, na przykład, nie - "fail" handler nigdy nie dostać wyjątek rzucony a' then ' handler, który moim zdaniem jest deal breaker.

 15
Author: B T,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-02 22:36:36

Pisałam o tym ostatnio na http://snmaynard.com/2012/12/21/node-error-handling / . nowością w node w wersji 0.8 są domeny i pozwalają połączyć wszystkie formy obsługi błędów w jeden łatwiejszy formularz zarządzania. Możecie o nich przeczytać w moim poście.

Możesz również użyć czegoś w rodzaju Bugsnag, aby śledzić swoje nieobciążone wyjątki i być powiadamianym przez e-mail, czatroom lub mieć bilet utworzony dla nieobciążonego wyjątku(jestem współzałożycielem Bugsnag).

 11
Author: Simon Maynard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-10 00:16:11

Jednym z przykładów, w którym użycie try-catch może być właściwe, jest użycie pętli forEach. Jest synchroniczny, ale jednocześnie nie można po prostu użyć instrukcji return w wewnętrznym zakresie. Zamiast tego można użyć metody try and catch, aby zwrócić obiekt błędu w odpowiednim zakresie. Consider:

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

Jest to kombinacja podejść opisanych przez @balupton powyżej.

 4
Author: Michael Yagudaev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-11 14:26:39

Chciałbym tylko dodać, że Krok.biblioteka js pomaga obsługiwać wyjątki, przekazując je zawsze do funkcji następnego kroku. Dlatego możesz mieć jako ostatni krok funkcję, która sprawdza błędy w którymkolwiek z poprzednich kroków. Takie podejście może znacznie uprościć obsługę błędów.

Poniżej cytat ze strony github:

Wszelkie wyjątki rzucone są przechwytywane i przekazywane jako pierwszy argument do następna funkcja. Dopóki nie zagnieżdżesz się funkcje inline Twoje główne funkcje zapobiegają temu, że nigdy nie będzie żadnych nieobciążonych wyjątki. Jest to bardzo ważne w przypadku długich węzłów.Serwery JS ponieważ pojedynczy wyjątek może doprowadzić do awarii całego serwera.

Ponadto możesz użyć Step do kontrolowania wykonywania skryptów, aby mieć sekcję czyszczenia jako ostatni krok. Na przykład, jeśli chcesz napisać skrypt kompilacji w Node i zgłosić, jak długo trwało pisanie, ostatni krok może to zrobić (zamiast próbować kopać out the last callback).

 3
Author: Michael Yagudaev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-12 17:47:14

Po przeczytaniu tego postu jakiś czas temu zastanawiałem się, czy używanie domen do obsługi wyjątków na poziomie api / funkcji jest bezpieczne. Chciałem ich użyć do uproszczenia kodu obsługi wyjątków w każdej funkcji asynchronicznej, którą napisałem. Moim zmartwieniem było to, że użycie nowej domeny dla każdej funkcji wprowadziłoby znaczny narzut. Moja praca domowa wydaje się wskazywać, że jest minimalny narzut i że wydajność jest rzeczywiście lepsza z domen niż z try catch w niektórych sytuacje.

Http://www.lighthouselogic.com/#/using-a-new-domain-for-each-async-function-in-node/

 2
Author: Sudsy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-10 04:15:57

Jeśli chcesz korzystać z usług w Ubuntu(Upstart): Node jako usługa w Ubuntu 11.04 z upstart, monit i forever.js

 1
Author: Cap,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-19 13:22:53

Wyłapywanie błędów zostało tutaj bardzo dobrze omówione, ale warto pamiętać, aby gdzieś je wylogować, aby móc je przeglądać i naprawiać.

Bunyan jest popularnym frameworkiem logowania dla NodeJS - wspiera zapisywanie do kilku różnych miejsc wyjściowych, co czyni go użytecznym do lokalnego debugowania, o ile unikasz konsoli.log. ​ W programie obsługi błędów Twojej domeny możesz wypluć błąd do pliku dziennika.

var log = bunyan.createLogger({
  name: 'myapp',
  streams: [
    {
      level: 'error',
      path: '/var/tmp/myapp-error.log'  // log ERROR to this file
    }
  ]
});
To może być czasochłonne, jeśli masz wiele błędy i / lub serwery do sprawdzenia, więc może warto zajrzeć do narzędzia takiego jak Raygun (zastrzeżenie, pracuję w Raygun), aby grupować błędy razem - lub używać ich razem. ​ Jeśli zdecydowałeś się użyć Raygun jako narzędzia, to jest to dość łatwe do skonfigurowania zbyt
var raygunClient = new raygun.Client().init({ apiKey: 'your API key' });
raygunClient.send(theError);

​ Skrzyżowane z użyciem narzędzia takiego jak PM2 lub forever, Twoja aplikacja powinna być w stanie się zawiesić, wylogować, co się stało i ponownie uruchomić bez większych problemów.

 1
Author: K. Craven,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-29 19:51:58