2012-11-05 15 views
14

chcę użyć node.js Domeny złapać wyjątki. Działa do tej pory, ale jest jedno miejsce, w którym nie mogę uzyskać domen, aby złapać wyjątek. wyjątek2 w wywołaniu zwrotnym jest przechwytywany i obsługiwany w procedurze obsługi domain.on ("błąd"), ale wyjątek 1 nie został przechwycony. Dziwne jest to, że gdy zostanie zgłoszony wyjątek1, nie wyłącza się węzła, tak jak się spodziewałem. Oto mój przykład aplikacja:stanie obsłużyć wyjątek z node.js domen przy użyciu express

var domain = require('domain'); 
var request = require('request'); 
var express = require('express'); 

var serverDomain = domain.create(); 
serverDomain.on('error', function(err) { 
    console.log("Server Domain Error: " + err); 
}); 

var app; 

serverDomain.run(function() { 
    app = express(); 
    app.listen(3000); 
}); 

app.use(function(req, res, next) { 

    var reqDomain = domain.create(); 
    reqDomain.add(req); 
    reqDomain.add(res); 
    reqDomain.on('error', function(err) { 
    console.log("Req Domain Error: " + err); 
    reqDomain.dispose(); 
    next(err); 
    }); 

    next(); 
}); 

app.get('/', function(req, res) { 
    var uri = "http://google.com"; 

    exception1.go(); 

    request.get({url:uri, json: {}}, 
    function (error, response, body) { 
     if(response.statusCode === 200) { 
     exception2.go(); 
     res.send('Success getting google response'); 
     } 
    }); 
}); 

Aby uzyskać exception2 wykonać, mogę wypowiedzieć się wyjątek 1.

Odpowiedz

18

Problemem jest to, że wyjątek dzieje podczas Connect's routing, który posiada zarówno try/catch blok around its execution, jak również domyślna procedura obsługi błędów, która drukuje szczegóły śledzenia stosu podczas pracy w trybie nieprodukcyjnym. Ponieważ wyjątek jest obsługiwany w Expressie, nigdy nie dociera do twojej zewnętrznej warstwy, aby domeny mogły sobie z nim poradzić.

czym różni się od exception2 jest to, że funkcja obsługi na trasie '/' jest wykonywany bezpośrednio przez które łączą bloku, w tym samym stosie jako pierwotnego połączenia, które przeszedł Express. Drugi wyjątek występuje w zwrotnego po kilka operacji I/O powrócił i dlatego jest wykonywany przez stos pochodzącej z pętli zdarzeń węzła I/O modułu obsługi, a więc try/catch z Express nie jest dostępny do pniaka ten wyjątek i zapisz serwer aplikacji. W rzeczywistości, jeśli skomentujesz wszystkie rzeczy związane z domeną i wyłączysz exception2, to zawiedzie Node.

Ponieważ tylko nieobsłużone wyjątki są kierowane do mechanizmu domeny, a od exception1 ma try/catch widoczne w jego stos wywołań nad nim, wyjątek jest obsługiwany, a nie przekazane do domeny.

+0

W związku z tym wyjątek zostanie przechwycony przez program obsługi domen w produkcji zgodnie z Twoim komentarzem? – user1007983

4

@ user1007983

Nie, w produkcji, obsługa try/catch nadal istnieje w Połącz/Express. Rozwiązaniem tego problemu jest dodanie własnego bloku try/catch w "root", który można następnie wykorzystać do emitowania zdarzenia "błąd" do domeny, zanim connect wyśle ​​odpowiedź błędu.

try { 
    // .. code here .. 
} catch (err) { 
    domain.emit('error', err); 
} 

Innym sposobem, aby ominąć to jest po prostu odłączyć się od uchwytu, jak owijając swój kod w bloku setImmediate

0

próbowałem try/catch bloków (które mogą nie działać tak, jak myśleć o async kod). Próbowałem węzła domen na kilka różnych sposobów. Ale nie byłem w stanie obsłużyć wyjątku wyrzuconego w bibliotece 3rd party (sequelize). Dlaczego otrzymałem wyjątek? Cóż, to dlatego, że wygenerowany SQL nie był dobrze uformowany. (Moja wina).

Anywho, rozwiązaniem, które najlepiej sprawdziło się dla mnie i mojego (małego) projektu było użycie forever. Pozwolić na wyjątki, ale ponownie uruchom węzeł, jeśli tak się stanie. Wątpię, czy to jest najbardziej eleganckie rozwiązanie, ale działa dla mnie i mojego małego projektu.

Przy większym projekcie domeny połączone z clustering API mogą być dobrym wyborem.

Winston to kolejny wybór. To może być fajne, aby połączyć Winston z forever, więc jeśli dostaniesz wyjątek, możesz mieć winston email you, abyś mógł naprawić kod. Tymczasem forever z przyjemnością uruchomi ponownie aplikację.

0

Natknąłem się na ten problem podczas testowania obsługi błędów w domenie.

Poszedłem z podejściem zaproponowanym tutaj przez Issaca, z kilkoma drobnymi zmianami: użyj 'domain.active', aby uzyskać aktualnie aktywną domenę i wyślij na tym zdarzenie błędu, a ja użyłem funkcji otoki, aby uniknąć modyfikowanie wszystkich moich funkcji Handler:

domainWrapper = function(func) { 
    return function(req, res) { 
     try { 
      return func(req, res); 
     } catch (err) { 
      domain.active.emit('error', err); 
     } 
    } 
} 

Potem zmienił tego rodzaju rzeczy:

app.get('/jobs', handlerFunc); 

do tego:

app.get('/jobs', domainWrapper(handlerFunc)); 
Powiązane problemy