2012-11-05 9 views
14

Desidero utilizzare i domini Node.js per rilevare le eccezioni. Funziona così tanto, ma c'è un posto in cui non riesco a ottenere domini per catturare l'eccezione. exception2 nel callback viene catturato e gestito nel gestore domain.on ('error'), ma exception1 non viene catturato. La cosa strana è che quando viene lanciata l'eccezione1, non chiude Nodo come mi aspetterei. Ecco il mio esempio app:Impossibile gestire l'eccezione con i domini node.js utilizzando 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'); 
     } 
    }); 
}); 

Per arrivare exception2 da eseguire, io commento eccezione 1.

risposta

18

Il problema è che l'eccezione accade durante Connect's routing, che ha sia un blocco try/catcharound its execution, così come un gestore di errori predefinito che stampa i dettagli della traccia di stack quando è in esecuzione in una modalità non di produzione. Poiché l'eccezione è gestita all'interno di Express, non raggiunge mai il tuo livello esterno per i domini da gestire.

Come si differenzia da exception2 è che la funzione del gestore per il percorso '/' viene eseguito direttamente da quel blocco Connect, nella stessa pila come la chiamata originale che ha attraversato Express. La seconda eccezione si verifica in una callback , dopo che è stata restituita un'operazione I/O, e quindi viene eseguita da uno stack proveniente dal gestore I/O del loop eventi del nodo, pertanto lo try/catch di Express non è disponibile per limitare tale eccezione e salva il server dell'app. Infatti, se si commenta tutto il materiale del dominio e si esegue il trip exception2, si verifica un arresto anomalo del nodo.

Dal momento che solo le eccezioni non gestite vengono instradati al meccanismo di dominio, e dal momento che ha un exception1try/catch visibile in esso è chiamata stack di sopra di essa, l'eccezione viene gestita, e non trasmesso al dominio.

+0

Quindi l'eccezione verrà catturata dal gestore dominio in produzione in base al tuo commento? – user1007983

4

@ user1007983

No, nella produzione, la gestione try/catch esiste ancora in Connect/Express. Il modo per risolverlo è aggiungere il proprio try/catch block nella "root" che è possibile utilizzare per emettere un evento di "errore" nel dominio prima che connect invii la risposta all'errore.

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

Un altro modo per aggirare l'ostacolo è quello di staccare solo da parte del conduttore, come avvolgendo il codice in un blocco setImmediate

0

Ho provato try/catch blocchi (che non può funzionare il modo di pensare con async codice). Ho provato i domini del nodo in diversi modi. Ma non ero in grado di gestire un'eccezione generata in una lib di terze parti (sequelize). Perché ho ricevuto l'eccezione? Bene, era perché l'SQL che è stato generato non era ben formato. (Colpa mia).

Anywho, la soluzione che ha funzionato meglio per me e il mio (piccolo) progetto era di utilizzare forever. Lascia che si verifichino le eccezioni, ma attiva nuovamente il nodo se lo fanno. Dubito che sia la soluzione più elegante, ma funziona per me e per il mio piccolo progetto.

Con un progetto più ampio, domini combinati con lo clustering API potrebbero essere una buona scelta.

Winston è un'altra scelta. Potrebbe essere interessante combinare forever con winston in modo che se si ottiene un'eccezione, è possibile avere winston email you, in modo da poter correggere il codice. Nel frattempo, forever riavvierà felicemente l'app per te.

0

Mi sono imbattuto in questo problema durante il test della gestione degli errori basata su dominio.

Sono andato con l'approccio suggerito qui da Issac, con un paio di modifiche minori: utilizzare 'domain.active' per ottenere il dominio attualmente attivo ed emettere l'evento di errore su questo, e ho usato una funzione wrapper per evitare di avere di modificare tutte le mie funzioni di gestione:

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

poi cambiato questo genere di cose:

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

a questo:

app.get('/jobs', domainWrapper(handlerFunc)); 
Problemi correlati