>_ DevTrendspl

Język

Strona główna

Języki

Sekcje

Frontend Backend Mobilne DevOps AI / ML GameDev Blockchain Systemy wbudowane Bezpieczeństwo
TypeScript

Cordis i architektura wtyczek w TypeScript bez bólu głowy

Jeśli kiedykolwiek pisałeś rozszerzalną aplikację w Node.js lub TypeScript, prawdopodobnie natknąłeś się na te same pułapki. Użytkownik lub system podłącza wtyczkę. Wtyczka rejestruje pięć nasłuchiwaczy zdarzeń, uruchamia kilka timerów, rejestruje swoje trasy i wstrzykuje usługę. A potem wtyczka jest wyłączana lub aktualizowana w locie.

Co się dzieje dalej? Wycieki pamięci. Nasłuchiwacze nadal działają, timery tykają w tle, a odwołania do kontekstu uniemożliwiają garbage collectorowi oczyszczanie pamięci. W Node.js zarządzanie cyklem życia zależności często przeradza się w ręczną harówkę.

Jakiś czas temu programiści frameworka do czatów Koishi stanęli dokładnie przed tym problemem. Potrzebowali stworzyć rdzeń, w którym setki wtyczek zewnętrznych mogłyby się uruchamiać, izolować, zastępować nawzajem i wyładowywać bez restartu procesu. Tak narodził się framework Cordis.

Czym w ogóle jest Cordis

Twórcy nazywają swój projekt „meta-frameworkiem kompozycji czasoprzestrzennej”. Brzmi mądrze i pretensjonalnie, ale istota jest w gruncie rzeczy pragmatyczna.

Cordis łączy kontener wstrzykiwania zależności (IoC), magistralę zdarzeń i hierarchiczne drzewo kontekstów. Każda wtyczka lub usługa żyje we własnym kontekście. Jeśli ten kontekst zostanie zniszczony, Cordis automatycznie oczyszcza absolutnie wszystkie zasoby dla niego: usuwa procedury obsługi zdarzeń, zabija timery i usuwa utworzone usługi.

Nie ma tu magii, ale jest jasna dyscyplina: jeśli wtyczka używa metod [object Object], [object Object] lub [object Object], framework sam dba o czyszczenie efektów ubocznych.

Jak działa model kontekstów

Centralną koncepcją w bibliotece jest [object Object]. To nie jest po prostu płaski obiekt z ustawieniami, ale rozgałęzione drzewo.

Gdy wywołujesz [object Object], framework tworzy potomny kontekst (fork). Kontekst potomny dziedziczy usługi rodzica, ale przechowuje własne referencje do zarejestrowanych zasobów.

Jeśli wyłączysz Wtyczkę A, jej kontekst potomny się zapada. Procedura obsługi [object Object] jest usuwana ze współdzielonej magistrali zdarzeń, podczas gdy Usługa Bazodanowa i Wtyczka B nadal spokojnie działają.

Usługi i typowanie w TypeScript

Usługi w Cordis deklaruje się poprzez dziedziczenie klasy bazowej [object Object]. Dzięki temu są dostępne bezpośrednio przez właściwości kontekstu, zachowując ścisłe typowanie:

Konstrukcja [object Object] rozwiązuje problem kolejności ładowania modułów. Jeśli usługa bazodanowa inicjalizuje się asynchronicznie lub łączy się później, zależna wtyczka poczeka na jej gotowość i aktywuje się.

Precyzyjne dostrajanie widoczności zakresów

W prawdziwych programach moduły często nie powinny reagować na wszystko. Na przykład jeden handler jest potrzebny tylko dla wiadomości z określonego kanału lub żądań z konkretnym nagłówkiem.

Cordis wprowadza koncepcję filtrów poprzez wywołanie [object Object] i właściwości kontekstu. Możesz ograniczyć widoczność usługi do określonej gałęzi drzewa lub ustawić predykat filtrujący niechciane zdarzenia:

Do jakich zadań ten sposób pasuje

Biblioteka została stworzona dla określonej klasy aplikacji. Nie powinieneś wciągać jej do zwykłego CRUD API na Fastify czy Express, gdzie tworzyłaby dodatkową warstwę abstrakcji.

Ale Cordis idealnie pasuje do następujących scenariuszy:

  1. Modułowe narzędzia CLI i generatory. Gdy użytkownicy mogą dostarczać pakiety npm rozszerzające polecenia lub potoki budowania.
  2. Aplikacje desktopowe na Electron/Tauri. Do organizacji systemu dodatków i motywów, które można włączać i wyłączać w locie bez przeładowywania okna.
  3. Boty i huby integracyjne. Gdy usługa komunikuje się z tuzinem różnych platform (Telegram, Discord, Slack), a każdy adapter potrzebuje żyć w izolacji.
  4. Narzędzia automatyzacji. Gdzie procesy są konfigurowane przez użytkowników dynamicznie przez interfejs webowy lub pliki YAML.

Pułapki i wady

Nie ma idealnych narzędzi i Cordis ma wiele specyficznych niuansów:

  • Stroma krzywa uczenia się. Dokumentacja jest napisana suchym językiem z obfitością specyficznych terminów. Aby przebrnąć przez koncepcje scalania zakresów i efektów ubocznych, musisz uważnie przeczytać kod źródłowy.
  • Nieznane API. Wiązanie usług z obiektem kontekstu poprzez scalanie typów TypeScript może początkowo dezorientować osoby przyzwyczajone do klasycznego NestJS czy InversifyJS z ich dekoratorami.
  • Przywiązanie do modelu mentalnego. Jeśli architektura twojego projektu nie obejmuje częstego dynamicznego wyładowywania kodu, korzyści z wbudowanego menedżera efektów są niwelowane przez złożoność kodu.

Czy warto spróbować

Cordis to interesujący projekt inżynieryjny skupiony na zarządzaniu cyklem życia komponentów. Elegancko rozwiązuje problem wycieków zasobów przy tworzeniu rozszerzalnych systemów.

Jeśli projektujesz system z rozbudowanym ekosystemem wtyczek i chcesz niezawodnego mechanizmu śledzenia efektów ubocznych out of the box, zrób forka repozytorium [object Object] i przestudiuj przykłady w testach. To świetny przykład tego, jak można zbudować architekturę mikropjatra w czystym TypeScript.

Powiązane projekty