So verhindern Sie, dass Ihr Node.js-Prozess abstürzt

Als ich einige Leute für Node.js Stellen interviewte, fand ich zwei Fragen, die niemand richtig beantwortete und die mir Angst machten:

  • Was passiert, wenn Sie ein abgelehntes Versprechen in Node.js nicht bearbeiten? Wie können Sie das debuggen?
  • Was passiert, wenn Sie das Fehlerereignis in einem Stream nicht behandeln?

Denk darüber nach. Kennst du die Antworten? Bist du sicher? Wenn nicht, kannst du dich mit diesem Typen vergleichen:

Was passiert, wenn Sie ein abgelehntes Versprechen in Node.js nicht bearbeiten? Wie können Sie das debuggen?

In den neuesten Versionen von Node.js (8.x, 9.x und wahrscheinlich auch früheren Versionen) erhalten Sie ein paar Warnungen, die wie folgt an den stderr ausgegeben werden:

(Knoten: 48446) UnhandledPromiseRejectionWarning: Dies ist in Ordnung
(Node: 48446) UnhandledPromiseRejectionWarning: Unhandled Promise Rejection. Dieser Fehler ist entweder darauf zurückzuführen, dass eine asynchrone Funktion ohne einen catch-Block ausgeführt wurde, oder dass ein Versprechen zurückgewiesen wurde, das nicht mit .catch () behandelt wurde. (Ablehnungs-ID: 1)
(Node: 48446) [DEP0018] DeprecationWarning: Nicht behandelte Versprechungsablehnungen sind veraltet. Zukünftig wird der Node.js-Prozess durch Ablehnungen von Versprechungen, die nicht behandelt werden, mit einem Exit-Code ungleich Null beendet.

Hier gibt es zwei wichtige Dinge:

  • Der Prozess stürzt nicht ab. Der Prozess läuft weiter. Aber du wirst bemerkt.
  • Dieses Verhalten wird sich jedoch in Zukunft ändern! In zukünftigen Versionen von Node.js wird der Prozess abstürzen.

Das ist gut zu wissen. Jetzt fragen Sie sich vielleicht, wie Sie programmgesteuert auf nicht bearbeitete Ablehnungen reagieren können. Beispielsweise könnten Sie daran interessiert sein, den Stack-Trace an einen Crash-Reporting-Service zu senden. Keine Sorge, Node.js hat etwas für Sie. Sie können das vom Prozess ausgegebene unhandledRejection-Ereignis abhören

process.on ('unhandledRejection', (Grund, Versprechen) => {
  console.log ('Unbehandelte Ablehnung bei:', reason.stack || reason)
  // Empfohlen: Sende die Informationen an sentry.io
  // oder welcher Crash-Reporting-Service auch immer verwendet wird
})

Bei Versprechungen, die mit einem Fehler abgelehnt wurden (z. B. Promise.reject (new Error ('This is fine'))), werden sowohl die Nachricht als auch die Stapelablaufverfolgung gedruckt. In allen anderen Fällen wird das übergebene Objekt gedruckt, um das Versprechen abzulehnen. Es ist also wichtig, immer ein Fehlerobjekt abzulehnen, um einen Stack-Trace zu erhalten!

Sie können auch das vom Prozess ausgegebene Warnereignis abhören und erhalten Informationen zu nicht bearbeiteten Ablehnungen und vielem mehr.

Was passiert, wenn Sie das Fehlerereignis in einem Stream nicht behandeln?

Erstellen Sie eine App mit dem folgenden Code:

const fs = require ('fs')
const stream = fs.createReadStream ('does-not-exist.txt')

Was geschieht? BOOM! Ihr Prozess wird mit einem Beendigungscode ungleich Null beendet und dies wird gedruckt:

events.js: 137
      werfen er; // Nicht behandeltes 'Fehler'-Ereignis
      ^
Fehler: ENOENT: keine solche Datei oder kein solches Verzeichnis, öffne 'do-not-exists.txt'

Stellen Sie sich vor, jemand lädt eine Datei auf Ihre Website hoch, Sie verarbeiten sie mit Streams, da es sich um eine große Datei handeln kann, der Benutzer dies vergisst und seinen Laptop schließt. Der Stream wird unerwartet geschlossen und… Ihr Node.js-Prozess stürzt ab und alle Benutzer Ihrer App erhalten Fehler. Das willst du doch nicht, oder? Vergessen Sie dann nicht, das Fehlerereignis in all Ihren Streams zu behandeln!

Extra Ball: JSON.parse ()

Diese scheinbar harmlose Funktion löst einen Fehler aus, wenn die Eingabezeichenfolge ungültig ist. Fügen Sie immer, immer, immer eine Try-Catch-Funktion hinzu oder hüllen Sie sie in ein Versprechen. Gleiches gilt für alle * Sync () - Methoden in der Node.js-API. Andernfalls wird so etwas Ihren Prozess beenden:

app.get ('/ foo', (req, res, next) => {
  const foo = JSON.parse (req.body.jsonString)
  // ...
})

Einfache und nette Tic-Tac-Bombe, die darauf wartet, Ihre App an einem Sonntag zum Absturz zu bringen.

Merken:

  • Behandeln Sie immer Versprechen Ablehnungen. Verfolgen Sie nicht behandelte Ablehnungsereignisse, um Absturzberichte zu erhalten. Und verwende immer Fehler, um Versprechungen abzulehnen, um Stapelspuren zu erhalten!
  • Behandle immer das Fehlerereignis für Streams!
  • Binden Sie JSON.parse () und eine beliebige * Sync () - Funktion in einen Try-Catch-Block oder in ein Promise ein. Nun, im Allgemeinen jede Funktion, die Fehler auslösen kann.