node.js serverseitig - arbeiten Sie an Fehlern. Teil 1

Guten Tag.

Dieser Artikel richtet sich an Entwickler, die mit node.js vertraut sind.

Kürzlich habe ich in unserem Büro Material zu Fakten vorbereitet, die für Entwickler unter node.js nützlich sind. Die Projekte, an denen wir arbeiten, sind API-Services, die das Express-Modul node.js als Webserver verwenden. Das Material basiert auf realen Fällen, in denen der Code falsch funktioniert hat oder die darin enthaltene Logik sorgfältig ausgeblendet wurde oder während der Erweiterung Fehler hervorgerufen wurden. Basierend auf diesem Material wurde ein Workshop zur Personalentwicklung abgehalten.

Also habe ich beschlossen zu teilen. Bisher beträgt nur der erste Teil etwa 30%. Bei Interesse geht es weiter!

Ich habe versucht, eine Gelegenheit für eine schnelle Einarbeitung zu bieten, also habe ich die Beispiele, Argumente und Kommentare in den Spoilern versteckt. Wenn die Aussagen offensichtlich sind, können Sie das „Wasser“ überspringen. Obwohl unser "Rechen" in den Spoilern auch interessant sein kann.

Ein Kollege während des Seminars stellte mir eine Frage, warum ich darüber sprechen sollte, wenn alles bereits in dieser oder jener Dokumentation enthalten ist. Meine Antwort war die folgende. Trotz der Tatsache, dass die Botschaft wahr ist, alles wirklich in der Dokumentation enthalten ist, machen wir immer noch nervige Fehler im Zusammenhang mit Missverständnissen oder Unkenntnis grundlegender Dinge.

Fangen wir an!

Virtuelle Maschine von Node.j.



Single Threading



Im Gegensatz zu javavm ist nodejs-vm Single-Threaded ** .



Quelle

Weitere Details
Gleichzeitig gibt es einen Pool von Hilfsthreads, die von der virtuellen Maschine selbst beispielsweise zum Organisieren von E / A verwendet werden. Der gesamte Benutzercode wird jedoch nur in einem "Haupt" -Thread ausgeführt.

Dies vereinfacht das Leben erheblich, da es keine Konkurrenz gibt. Die Codeausführung kann nicht an einem beliebigen Ort unterbrochen und an einem anderen fortgesetzt werden. Der Code wird einfach ausgeführt, bis auf etwas gewartet werden muss, z. B. auf die Datenbereitschaft beim Lesen aus einer Datei. Während des Wartens kann ein anderer Handler ausgeführt werden, entweder bis die Arbeit beendet ist oder bis er ebenfalls auf etwas wartet.

Das heißt, wenn es eine interne Datenstruktur gibt, müssen Sie sich keine Gedanken über die Synchronisierung des Zugriffs darauf machen!

Was tun, wenn der "Haupt" -Thread keine Zeit hat, die Daten zu verarbeiten?

Die Skalierung erfolgt durch Starten eines anderen node.js-Prozesses oder, wenn die Serverressourcen zu Ende gehen, durch Starten eines anderen Servers.

Folgen und unser "Rechen"
Auch hier ist alles klar. Sie sollten immer darauf vorbereitet sein, dass es mehr als einen node.js-Prozess geben kann (und höchstwahrscheinlich auch geben wird). Und manchmal kann es auch mehrere Server geben.

Der "Rechen", der versteckt war , befindet sich in unserem Code


Parallele Linien schneiden sich im Unendlichen. Es ist unmöglich zu beweisen, aber ich habe gesehen.
Jean Effel, "Der Roman von Adam und Eva."
Es wurde versucht, die Eindeutigkeit von Entitätsinstanzen in der Datenbank ausschließlich durch die Anwendung sicherzustellen. Im Allgemeinen sieht dies und isoliert vom Kontext nicht sehr gut aus, aber in dieser Situation umso mehr. Ohne die Inanspruchnahme eines Drittanbieters scheint mir diese Aufgabe keine Lösung zu haben.

Der Kollege, der damit beschäftigt war, wollte dies wirklich wirklich implementieren, ohne die eigentliche Datenbank einzubeziehen. Am Ende wurde es nach einigen "Annäherungen an das Projektil" realisiert ... unter Einbeziehung von SharePoint.


** Multithreading oder "wenn du wirklich willst"



Ab Version 10.5.0 bietet node.js experimentelle Unterstützung für Multithreading .


Quelle

Das Paradigma bleibt jedoch dasselbe
  • Jeder neue Workflow erstellt eine eigene isolierte Instanz der Umgebung der virtuellen Maschine node.js.
  • In Workflows fehlen gemeinsame veränderbare Daten. (Es gibt ein paar Vorbehalte, aber im Grunde ist die Aussage fair.)
  • Die Kommunikation erfolgt über Nachrichten und SharedArrayBuffer.

Daher funktioniert der alte Code bei Verwendung von Workflows weiterhin.
Lesen Sie hier mehr.


Anwendungslebenszyklus



Das Herzstück von nodejs-vm ist die Ereignisschleife. Wenn die Codeausführung ausgesetzt werden soll oder der Code anscheinend beendet ist, wird die Kontrolle an ihn übergeben.

Versteckter Text
Die Ereignisschleife prüft, ob (oh) die Ereignisse aufgetreten sind, für die wir die Handler registriert haben. Wenn etwas passiert, werden die Handler aufgerufen. Wenn nicht, wird geprüft, ob es "Generatoren" von Ereignissen gibt, für die wir Handler registriert haben. Eine offene TCP-Verbindung oder ein Timer können solche Generatoren sein. Wenn sie nicht gefunden werden konnten, wird das Programm beendet. Andernfalls wird eines dieser Ereignisse erwartet, Handler werden aufgerufen und alles wird wiederholt.

Die Konsequenz dieses Verhaltens ist die Tatsache, dass, wenn der Code zu Ende zu sein scheint, der Exit von nodejs-vm nicht erfolgt, zum Beispiel weil wir einen Timer-Handler registriert haben, der nach einiger Zeit aufgerufen werden sollte.

Dies wird im folgenden Beispiel gezeigt.

console.log('registering timer callbacks'); setTimeout( function() { console.log('Timer Event 1'); }, 1000); console.log('Is it the end?'); 


Ergebnis:
 registering timer callbacks Is it the end? Timer Event 1 


Lesen Sie hier mehr.

Ein weiterer "Rechen" in unserem Code



Jeder kann den Staat verwalten!
Das Vorzeichen, ob der Benutzer ein Administrator ist, wurde in einer globalen Variablen gespeichert. Diese Variable wurde zu Beginn des Programms mit false initialisiert. Später, als sich der Administrator registrierte, wurde diese Variable auf true gesetzt.

Wenn der Administrator das System besuchte, wurde jeder Benutzer, der auf diese Instanz des Dienstes zugegriffen hat, als Administrator wahrgenommen.

Es hat mich einige Mühe gekostet, meinem Kollegen zu zeigen, dass ein Fehler in der Logik vorliegt. Ein Kollege war sich sicher, dass für jede http-Anfrage eine völlig neue Umgebung erstellt wird.


package.json - Felder, die es wert sind, ausgefüllt zu werden



package.json ist die Beschreibungsdatei für unser Paket. In diesem Zusammenhang geht es um unsere Anwendung und nicht um Abhängigkeiten. Die unten aufgeführten Felder und Erklärungen sind der Grund, warum es sich lohnt, sie trotzdem auszufüllen.

Versteckter Text

Name


Bis wir das Paket im Repository veröffentlichen, kann das Feld ebenfalls bewertet werden. Die Frage ist, dass dieses Feld bequem zum Benennen der Installationsdatei oder zum Anzeigen des Produktnamens auf seiner Webseite verwendet werden kann. Im Allgemeinen "wie nennt man eine Yacht, .."

Version


Die Hauptidee ist nicht zu vergessen, die Versionsnummer zu erhöhen und gleichzeitig die Funktionalität zu erweitern, Fehler zu beheben, ... Leider finden Sie in unserem Büro immer noch Produkte mit der unveränderten Version 0.0.0. Und dann raten Sie mal, welche Art von Funktionalität für den Client funktioniert ...

Haupt


Dieses Feld gibt an , welche Datei beim Start unserer Anwendung gestartet wird (`npm start`). Wenn das Paket als Abhängigkeit verwendet wird, welche Datei wird dann importiert, wenn unser Modul von einer anderen Anwendung verwendet wird. Das aktuelle Verzeichnis ist das Verzeichnis, in dem sich die Datei "package.json" befindet.

Wenn wir beispielsweise vscode verwenden , wird die in diesem Feld angegebene Datei gestartet, wenn der Debugger aufgerufen wird oder wenn der Befehl "execute" ausgeführt wird.

Die Erweiterung ".js" kann weggelassen werden. Es ist eher eine Folge aller möglichen Anwendungsfälle, daher wird es nicht direkt in der Dokumentation dargelegt.

Motoren


Dieses Feld enthält das Tupel: {"node": version , "npm": version , ...}.

Ich kenne die Felder "Knoten" und "npm". Sie bestimmen die Versionen von node.js und npm, die für die Funktion unserer Anwendung erforderlich sind. Versionen werden durch Ausführen des Befehls npm install überprüft.

Die Standardsyntax zum Bestimmen von Versionen von Abhängigkeitspaketen wird unterstützt: Ohne Präfix (einzelne Version) müssen das Präfix "~" (die ersten beiden Nummern der Version müssen übereinstimmen) und das Präfix "^" (nur die erste Nummer der Version muss übereinstimmen). Wenn ein Präfix vorhanden ist, muss die Version größer oder gleich der in diesem Feld angegebenen sein. Nur eine Liste von Versionen; explizite Angabe mehr, weniger, ... etc. funktioniert auch.

Haftungsausschluss "Npm install" überprüft die in den "Engines" angegebenen Versionen nur, wenn der "Engine-Strict" -Modus aktiviert ist. Wir fügen es für jedes Projekt hinzu und fügen die .npmrc-Datei mit der Zeile hinzu: "engine-strict = true". Es war einmal, dass "npm install" diese Prüfung standardmäßig durchführte.

Einige Container, zumindest in der Dokumentation, schreiben, dass standardmäßig geeignete Versionen verwendet werden. In diesem Fall handelt es sich um Azure.

Ein Beispiel:
 "engines": { "node": "~8.11", // require node version 8.11.* starting from 8.11.0 "npm": "^6.0.1" // require npm version 6.* starting from 6.0.1 }, 


regelmäßiger "Rechen"



Und der König ist nackt!

Mit dem Client wurde wiederholt vereinbart, dass die erforderliche Version von "node.js" mindestens 8 sein sollte. Als die ersten Versionen der Anwendung ausgeliefert wurden, funktionierte alles. "Einen Tag" nach der Lieferung der neuen Version auf dem Client wurde die Anwendung nicht mehr ausgeführt. Bei unseren Tests hat alles funktioniert.

Das Problem war, dass wir in dieser Version Funktionen verwendeten, die nur von Version 8 node.js unterstützt wurden. Das Feld "Engines" war nicht ausgefüllt, sodass niemand zuvor bemerkt hatte, dass der Client eine alte Version von node.js hatte. (Standardeinstellung für Azure-Webdienste).

Skripte


Das Feld enthält ein Tupel der Form: {"script1": script1 , "script2": script2 , ...}.

Es gibt Standardskripte, die in einer bestimmten Situation ausgeführt werden. Beispielsweise wird das Skript "install" ausgeführt, nachdem "npm install" ausgeführt wurde. Es ist beispielsweise sehr praktisch, die Verfügbarkeit von Programmen zu überprüfen, die für das Funktionieren der Anwendung erforderlich sind. Oder um beispielsweise alle statischen Dateien zu komprimieren, die über unseren Webdienst verfügbar sind, damit sie nicht im laufenden Betrieb komprimiert werden müssen.

In diesem Fall können Sie nicht nur auf Standardnamen beschränkt werden. Um ein beliebiges Skript auszuführen, müssen Sie "npm run script-name " ausführen.

Es ist praktisch, alle verwendeten Skripte an einem Ort zu sammeln.

Ein Beispiel:
  "scripts": { "install": "node scripts/install-extras", "start": "node src/well/hidden/main/server extra_param_1 extra_param_2", "another-script": "node scripts/another-script" } 


PS Die Erweiterung ".js" kann in den meisten Fällen weggelassen werden.


package-lock.json - hilft bei der Installation bestimmter Versionen von Abhängigkeiten, nicht der "neuesten"



Versteckter Text
Zu git oder nicht zu git? ..


Diese Datei erschien vor relativ kurzer Zeit in npm. Ihr Zweck ist es, die Wiederholbarkeit der Baugruppe zu organisieren.

und noch ein "Rechen"


Aber ich habe nichts an meinem Programm geändert! Gestern hat sie gearbeitet!


Auf einem Peer-Computer funktionierte die Anwendung hervorragend. Auf einem anderen Computer in einer identischen Umgebung, in einer Anwendung, die von git in ein neues Verzeichnis gestellt wurde, traten nach dem Ausführen von 'npm install' bisher 'npm start' auf.

Das Problem wurde durch die Tatsache verursacht, dass die Datei 'package-lock.json' im Git-Repository fehlte. Daher wurden während der Installation von Paketen alle Abhängigkeiten der zweiten oder mehr Ebenen (natürlich nicht in package.json geschrieben) so frisch wie möglich installiert. Auf dem Computer eines Kollegen war alles in Ordnung. Auf dem getesteten Computer wurde ein inkompatibler Satz von Versionen ausgewählt.

package-lock.json - zu git!



Rückkehr vom Exkurs. Die Datei 'package-lock.json' enthält eine Liste aller lokal für unsere Anwendung installierten Module. Das Vorhandensein dieser Datei ermöglicht es Ihnen, eine Eins-zu-Eins-Gruppe von Modulversionen neu zu erstellen.

Zusammenfassung: Vergessen Sie nicht, git einzutragen und in die Lieferdatei (Installationsdatei) der Anwendung aufzunehmen!

Nützlich: Wenn die Datei 'package-lock.json' fehlt, aber ein Verzeichnis 'node_modules' mit allen erforderlichen Modulen vorhanden ist, kann die Datei 'package-lock.json' neu erstellt werden:
 npm shrinkwrap rename npm-shrinkwrap.json package-lock.json 



Sie können dem vorerst ein Ende setzen. Die nicht enthaltenen Informationen sind die von unserem Team verwendete Code-Vereinfachungstechnik.

Wenn Fehler entdeckt werden, werde ich versuchen, sie schnell zu beheben!

Source: https://habr.com/ru/post/de430972/


All Articles