Галоўная / Артыкулы / 12 прыткіх правіл для надзеяных API на Node.js

12 прыткіх правіл для надзеяных API на Node.js

Практычныя правілы надзержання над адрысамі API Node.js: таймауты, ідэмпотентнасць, транзакціі, анвалідаванне кэша, логаванне і затрымкі у залежнасцях — прытаму до старонкі за 3 гадзіны ночы.

906 слоў

Дзеяныя наследства з абыякласнасцю частаўляюцца толькі пасля перыву службы. Дванаццаць пунктав, прыведзеных нижэй, з’яўляюцца дастатнь часта ў разных службах на базе Node.js, таму яснае ўказванне іх дешэўша, чым прабава зноў іх аднаходзіць пад тым пяснем, калі трэба негайна дзеяць. Спрыймайце іх як стандартныя правілы пад час проектавання працоўнікаў обробкі запытав, а не як дапаможныя элементы пасля запуску.

1. Запытавы, якія можна перадаць знову, будуць пераданы зноў.

Не «можа буць». Кліенты выкананяюць тайма-аут, з’язні рываюцца ў момант адпаведзі, а люди натыкаюць на кнопку выканання. Балансірывачы навантажэння і мобайльныя сеті ствараюць дадатковыя копіі дадзеных. Кожны працоўнік, який стварае або мяняе стан дадзеных, патрэбуе чыстаю адпаведзь на запыт «што, як такі ж пакет дадзеных прыйдзе зноў», таму што за дастатнь адлеглы час гэта не будзе экстремальны случай — гэта немінучае. Проектаваўцы патрэбуе разам праектаваць як шлях успеху, так і шлях дублікацыі.

2. Кожнам выходзячым запытаву паказваць тайма-аут.

Запыты даўеджніка, HTTP-звязі з трэцімі сторонамі, платежныя прыемнікі — якщо вы не вказаеце канечную дату, праця якога-небудзь компонента можа застацца з ачытым сокетам на неакранічаны час. Простае выкліканне fetch(url) не ўможлівляе «тэрпячка на певны час»; гэта неакранічана адліквідацыя, і такая адліквідацыя можа змусіць сповольнюючы компонент заморозіць усё, што знаходзится вышэй у ланцугу. Лепей выбіраць стандартныя настройкі бібліятак, якіе встановляюць ліміт, і пры невыпанні задачі спрацоўваць з явнымі паведамленнямі пра адпрацоўку зноў чы ў форме паведамленняў для корыстніка, а не працаваць без жадных сігналоў.

3. Перакананні браузера — це частка UX, а не захоўні мур.

Корыстнікі можу праігнораваць ваш SPA і звяжыцца з API за дапамогою будзь-каго JSON, выкарыстоўваючы curl, Postman чы компрометаваны скрыпт. Правіла, якія маюць значэнне — правільна сформаваны электронны паштовы адрес, ненегатыўная цэна, обав’язковыя поля — павінны зноў быць перакананы на сервере з той жа строгосцю, якую вы бы застосавалі да ворагоўскага трафіку. Перакананні на боку кліента дапамагаюць толькі савершэнна супрацоўным корыстнікам, якія і так не нарушылі б умовы.

4. Кэш без процедуры анулювання — это затриманный баг.

Кэшаванне стварае другую копію дадзейнаў, і гэтыя копіі пачынаюць разлікваваць. Калі вы вводзіце кэш, неабходна адначасова выбраць, які запіс, вебхук чыя TTL-падзея яго анулюе, і задокументаваць гэты выбор пры самай ключ-значэння кэша. Палежнасць ад ідеі, што “яны выгораюць калі-небудзь”, часта означае “дольшы тымчас, чым кліянты зможуць вытрымаць некоректныя балансы”, особаўска калі TTL-вырахоўванні ведаецца за гадзіны пад прэтэкстом “парадку”.

5. Запісы, якія выкананы адночасна, патрабуюць транзакцыі, а не оптымізма.

await update1(); await update2(); выглядае як атамічны запіс, але такім не ёсць. У перыяд между await-амі крах, паталогія чы працоўная памятка можу заставіць выканацца толькі адні запіс, і самэ гэта прыводзіць да розніцы между інвентаром і счытанням. Толькі рэальная транзакцыя базы дадзеных — або явна сага з компенсуючымі дзеяннямі — можа закрыць гэты перыяд з гарантіямі, пра якія можна рассуждаваць.

6. Апарат для інцыдэту, які вы ўсё ўтолькі не бачылі.

Калі ўсё зламваецца, вельмі пазнела дадаць рэкорд, який мог бы ўсё це поясніць. Структураваныя логі, ідэнтыфікаторы кореляцыі, якія пераходзяць межаў разных служб, і достатні контэкст для реканструкцыі запиту, які надаўся прычынай адказу, перамагаюць нават самыя хітрыя сеансы дэбаггіну пасля аналізу прычын. Лог-даны, якія можна без апасцерагаў заставіць, рэзультаты дзеянняў і зволікання ў выкарыстоўванні ресурсаў, калі система працуе нормальна.

7. Памяць процэса — це кеш, а не система зберагчыка даных.

Значэнне, якое існуе толькі ў процэсе Node, зникае пасля перзапуску, є невидальным для іншых экземпляраў таго ж процэса і ніколі не є стойкім. Флагі функцый, якія зберагваюцца ў RAM, лічыльнікі чы “тэмпаратарныя” кашы, усе яны маюць такую ж долю. Якщо ўжо трэба, каб даны перазсталі пасля аплыву, збою чы балансавання навантажэння без стойкіх сесый, то іх трэба зберагваць у базе дадзеных чы іншам стойкім сховішчы, а не ў випадковай ячэйцы RAM.

8. Планавайце так, каб кожны сяброўскі вызов з часам не выканаўся.

Корыстны вопыт — не «чы гэта зазвычай работае?», а «што будзе ў рэдкім случаю неудачы?» Таймауты, частковыя адпаведзі і спады кода 5xx таксама маюць значэнне. Якшто чыстая адпаведзь — «незрозумела», запыніце гэтыя проблемы за дапамою безпечных пракатанняў, прыемнікаў на выключэнне цяга або сценарыёў з паслабленым функціянаванням, прычаму ўжо па-ранейшаму не з’яўіцца проблемы.

9. Чарга перапланавае работу; яна яе не вычыраюць.

Даўленне элемента ў чаргу створвае вражанне, што работа завершылася. Рабочы элемент працюе ўсё той самы час, з тымі ж можлівымі неудачамі, проста ў іншы момант. Якшо рабочыя элементы запазджаюць, кількасць незавершаных задач расте, хоця API застаецца адпаведным — гэта краща, чым блакуванне запытоў, але не значыць, што работа будзе дешавей. Размір спожывачаў і шляхоў для некоректных паведамленняў трэба нарабатываць так жа рэтельна, як і размір HTTP-слоя.

10. Давайце назвы для чытачаў, якія будуць актуальныя шасць месцаў, а не для трымкі сьогоднішняго спрытку.

data, temp і handleStuff застаюцься точнымі толькі пакуль тры ўсё іншыя панявы таксама не будуць атрыбутаваны як “data”. Назвы, зв’язаныя з бізнес-ідеяй, застаюцься разумнымі для чытачаў без жаднага контексту — укладзецца ў тое, каб будучыя версіі вас на незнайомай службе таксама моглі іх зрозумець. Лепш выбіраць іменнікі, які апісваюць сутнасць, чым механічныя дзеяння, які описваюць першыя деталі рэалізацыі.

11. Стваральнікі будуць вызываны два разы.

Нестабільныя сеткі, агрэсыўныя кліенты для павторных спроб, нетерплівыя дзве клікі — гэта можа быць што-небудзь з гэтага. Запыты POST для стварэння трэба обрабоцваць так, каб усунуцца ризык дуплікацыі, зазвычай за дапамою ключа ідэмпотентнасці, які зберагаецца разам з рэзультатным ресурсам; інакш могуць выйсці подвойныя платежы і дуплікаты замовленняў, якія будуць вызваны разніцай у часе. Калі ўсё вже створана, трэба вярнуць первісны результат, а не які-небудзь новы пасляэфект.

12. Затрымка на канцы ўзьязку залежыць ад найпамедлівейшай залежнасці.

Ўтылкі, які адпрацоўваюць запыткі, якія не ў індэксе, або удаленыя API без тайма-ауту, все равно працуюць медленна. Аналіз своих власных кодавых ліній, ігнаруючы параметры, якія надаюцься ззовні, дае некоректныя рэшты. Памеры па параметрамі p95 і p99 трэба атрымваць для всіх элементаў карто гэтаў, а пасля — выправіць проблемы з індэксамі, групаванням задач і тайма-аутамі там, дзе насправды витрачаецца час.

Ніякі з эых саветаў не є выказной, і самэ гэта і є сутніцэю: сторанкі, якія працуюць у трох адночы, рэдка калі бываюць выказнымі. Яны зазвычай належаюць да адных з гэтых дванаццаці категорый і застаюць без уваги, пакуль не перестануць казацца справай нявыбаглівай. Ствараюце простыя захоўнікі ў момент, калі сервіс яшчэ достатна маленькі, ўбачлівы для змян.