Грациозно изключване в NodeJS

В тази статия ще ви покажа как да направите грациозно изключване в приложението NodeJS, но първо нека опишем какво означава „грациозно изключване“и защо трябва да правим това в нашето приложение и какви са ползите.

Грациозно изключване

Нека си представим, че имате HTTP сървър с NodeJS, който е свързан с база данни, и всеки път, когато сървърът бъде извикан, той изпраща заявка до базата данни за получаване/задаване на данни, които също ще бъдат изпратени на клиента чрез отговора.
Представете си, че трябва да изключите сървъра, най-лесният начин да направите това е <Ctrl>+C и сървърът ще бъде убит, но изчакайте, какво ще стане, ако вашият сървър не завърши всички заявки, какво ще стане, ако някои клиентски връзки бъдат затворени, защото сървърът е убит и не може да се справи със заявките.

-Това ви дава повод да се замислите, нали?

Както може би се досещате, трябва да обработите всички заявки и да затворите всички ресурси, които обработват данни (напр. връзки към бази данни) и да не приемате други заявки и след това можете да изключите сървъра си със спокойна съвест.

Благоприятно изключване означава, когато всички ваши заявки към сървъра са отговорили и не е останала никаква работа по обработката на данни.

Много е важно да създадете грациозно изключване и да изключите сървъра си правилно, защото не можете да знаете какво може да се случи със заявките, които са били направени към сървъра, ако изключите сървъра незабавно, можете да направите грешка и да убиете другия процес ( byPID), които са предоставени на NodeJS сървъра или някои други неща могат да се случат, което може да е лошо за вашето приложение.

Как работи това

Ето четирите стъпки за това как можете да направите елегантно изключване по лесен начин.

  1. Обработване на сигнал за спиране на процеса
  2. Спрете нови заявки от клиента
  3. Затворете целия процес на данни
  4. Изход от процеса

Първо трябва да обработим в сървъра, който някой иска да изключи, след това трябва да завършим всички заявки и да спрем да приемаме нови заявки от потребители към сървъра, така че да сме сигурни, че няма чакащи заявки от потребители към сървъра, преди да изключим сървъра, след това трябва да затворим цялата обработка на данни (т.е. бази данни, някои работници на файловата система и т.н.), зависи от това какво правите в сървъра и накрая можем да излезем от процеса.

Нека създадем прост NodeJS сървър и изпълним всички стъпки, които споменах по-горе, което ще направи грациозно изключване, когато искаме да затворим сървъра и да разберем как работи.

Ето прост пример за сървър на NodeJS, използващ ExpressJS

Тук имаме прост сървър, който има маршрут, който създава потребител в MongoDB.

Можем да тестваме сървъра и да създадем потребител в базата данни с помощта на тази команда

curl -d ‘{ “username”: “Narek” }’ -H “Content-Type: application/json” -X POST http://localhost:3000/user

Ако получите Success! съобщение, тогава можете да погледнете JSON данните в MongoDB.

Сега нека преминем през четирите стъпки и да напишем подходящ код за това.

1. Обработка на сигнал за спиране на процеса

Първо, нека разберем какво е процесен сигнал.

Сигналът е асинхронно известие, изпратено до процес или до конкретна нишка, за да уведоми за настъпило събитие.

Сигналните събития ще бъдат излъчвани, когато NodeJS процесът получи сигнал.
Всеки сигнал има име (т.е. 'SIGINT', 'SIGTERM' и т.н.), повече за това в NodeJS тук.

  • 'SIGINT' генериран с <Ctrl>+C в терминала.
  • Сигналът 'SIGTERM' е общ сигнал, използван за спиране на програмата. За разлика от 'SIGKILL' този сигнал може да бъде блокиран, обработен и игнориран. Това е нормалният начин да помолите учтиво програмата да прекрати работа.
  • Командата на обвивката kill генерира 'SIGTERM' по подразбиране.

Можете да прочетете повече за сигналите за прекратяване тук.

Както предполагате, трябва да добавим манипулатор, който ще получи 'SIGTERM' сигнал.

Ето следващия пример, изграден върху предишния пример, който обработва сигнала.

Сега нека опитаме и да го тестваме.
Стартирайте сървъра, след това трябва да получите PID номер, получавате го с помощта на команда ps, така че сега имате номера и можете да опитате да убиете сървъра, като използвате тази команда kill [PID_number] или просто killall node, което ще изпрати сигнал до всички сървъри на възли, след изпълнение на тази команда ще получите този журнал от изходите на възлите

SIGTERM signal recived.

Ако опитате отново, ще получите същия дневник

SIGTERM signal recived.

-Хм, защо процесът не е убит?

Защото сте се справили със сигнала и сте го игнорирали.

И така, първата стъпка е направена, нека преминем към следващата стъпка.

2. Спрете нови заявки от клиента

Сега трябва да спрем http сървъра и да спрем приемането на нови заявки.
Може да се направи с помощта на функцията server.close, за да получите повече информация за това, можете да погледнете и в NodeJS doc.

И така, кодът ще изглежда така

Той ще спре да приема нови връзки към сървъра и ако се опитате да се обадите на сървъра, вашата заявка ще бъде неуспешна.

3. Затворете целия процес на данни

В този пример целта е да затворите връзката MongoDB, тъй като към базата данни не са останали никакви заявки.

Така че може да се направи с този код

-Хммммм, защо сървърът на възел излиза след затваряне на връзката с DB.

Това е много интересен въпрос, можете да се опитате да разберете тази точка сами, но ако не можете или не искате, ще го опиша в следващата глава.

4. Затворете целия процес на данни

Както видяхте, нашето приложение излиза от тясна връзка с база данни.

Каква е причината? -EventLoop

Както знаем, NodeJS ще излезе, когато опашката на EventLoop е празна и няма какво да се направи.

Но понякога вашето приложение може да има повече функции и няма да излезе автоматично, в тази точка идва последната ни работа.
Трябва да излезем от процеса с помощта на функцията process.exit.

И последният пример за грациозно изключване на сървъра ще изглежда така

Аргумент 0 означава излизане с код „успех“.
За излизане с код „неуспех“ използвайте 1.

За да получите този код за изход след изключване, изпълнете тази команда в терминала, където стартирате вашия възлов сървър.

echo $?

По подразбиране NodeJS излиза с код на процес 0, ако EventLoop е празен.

Това е!

Резюме

Това не е единственият начин за правилно изключване на сървъра, това ще работи добре при малки проекти и може да се напише лесно, но не казвам, че при големи проекти не е необходимо. В големи проекти, които по-вероятно използват балансиране на сървър (т.е. Nginx), можете да балансирате натоварването и да не изпращате заявка до този сървър и да го изключвате.

Благодаря ви, че прочетохте тази статия, не се колебайте да задавате въпроси или да ми пишете в Twitter @nairihar.

Моята статия за „Проверки на изправността на NodeJS и защита от претоварване“
https://medium.com/@nairihar/nodejs-health-checks-and-overload-protection-368a132a725e