Következő szintű eseménykatalógus-beállítás tervezése eseményvezérelt architektúrákhoz

Az EventCatalog nagyszerű! De még jobbá teheted – hadd mutassam meg, hogyan.

A David Boyne nyílt forráskódú projektje, az EventCatalog egy olyan nyílt forráskódú projekt, amely segít dokumentálni eseményeit, szolgáltatásait és domainjeit. Ez egy nagyszerű eszköz az eseménykörnyezet felfedezhetőségének megteremtésére. Szeretem!



Ezzel a „Markdown” használatával írja le eseményeit, szolgáltatásait és domainjeit – ez így néz ki:

---
name: UserSignedUp
version: 0.0.1
summary: |
  Tells us when the user has signed up
consumers:
    - Email Platform
producers:
    - User Service
---

Duis mollis quam enim, feugiat porta mi porta non. In lacus nulla, gravida nec sagittis vel, sagittis id
tellus. Vestibulum maximus velit eget massa pulvinar ornare. In vel libero nulla. Aliquam a leo risus.
Donec bibendum velit non nulla sollicitudin lacinia. Vestibulum imperdiet nunc eget
neque sagittis, eget volutpat purus ornare. Mauris malesuada finibus pretium.
Vestibulum suscipit tortor sit amet dolor tempor cursus. Nunc ac felis accumsan.

<Mermaid />

Az EventCatalog ezután képes megjeleníteni ezeket az információkat – és annak részleteit, metaadatait és kapcsolatait – egy olyan webhelyen, amely jól néz ki és könnyen navigálható. Sokan közülünk, akik eseményvezérelt rendszereket építünk, már régóta sürgetik az ilyesmit.

Mivel az EventCatalog csatlakoztatható és bővíthető, elkezdhetjük tervezni automatizálási igényeinket, mivel valószínűleg nem szeretné egy helyen építeni eseményvezérelt rendszereit és dokumentálni azokat. valahol máshol. Ezenkívül nem igazán ideális az EventCatalog „behúzása” a kódbázisba, mivel ez egy teljes projekt, és nem csak egy könyvtár. Röviden: valami más utat kell találnunk, és ez az egyik dolog, amit itt szeretnék megosztani veletek!

Bármennyire is jó az EventCatalog, vannak dolgok, amelyeket hozzá kell adnunk körülötte, hogy kiaknázzuk a benne rejlő lehetőségeket.

Amiben javítani szeretnénk

Íme, mit szeretnénk tenni:

  • Adjon hozzá támogatást az AsyncAPI-sémákhoz, és az eseménykatalógus események (dokumentumok) generálása ezekből ahelyett, hogy manuálisan, külsőenírná őket a tényleges kódbázisba, amelyet dokumentálunk. . Az igazság forrása végül a dokumentált rendszerek, így az EventCatalog egyszerűen megjelenítheti ezeket az információkat.
  • Javítson ki egy kisebb korlátozást, ami miatt nem lehet kikövetkeztetni a domaint az AsyncAPI-sémákból. A tartománykonstrukció egy okos kiegészítés az EventCatalogban, de nincs egyértelmű, szabványos módja ennek az információnak, ezért ki kell találnunk, hogyan tegyük ezt.
  • Tervezzen meg egy megoldást a központosított séma-nyilvántartáshoz, hogy elkülönítse azt bármely egyéni csapattól, és hogy az EventCatalog jobban használható legyen, mint egy platform.
  • Reprodukálható alapot biztosítunk megoldásunk állványozásához folyamatos integrációs környezetben.

Nemrég létrehoztam egy kis projektet, amely az EventCatalog létrehozási és felépítési fázisait tartalmazza, és elvégzi a fenti dolgok többségét. A tervezési rész kivételével az összes fenti probléma miatt megosztottam ezt a kódot egy nyilvános GitHub projektben:



Nem oldja meg az összes problémát, amit itt felvetettem, de alapvető része lesz a megoldáshoz való hozzáállásomnak és a cikk többi részének. Elmagyarázok néhányat, miért működik ez a kód és a megoldás is úgy, ahogyan működik.

Gyors indulás az állványzat megoldásához

Ha egy működő demómegoldást szeretne kapni, akkor az állványprojektem a 4-ből 3-at (többé-kevésbé) itt megold.

A tár klónozása

Feltételezve, hogy van "git", futtassa a git clone [email protected]:mikaelvesavuori/eventcatalog-scaffold-asyncapi.git parancsot.

Hozzon létre egy új eseménykatalógust

Futtassa a bash create-eventcatalog.sh.

Futtassa az eseménykatalógust

A build-eventcatalog.sh parancsfájlt aliasként npm start névre keresztelje, majd futtassa.

Most futnia kell:

Még ha az én projektemet is használja, az alábbiak sokkal mélyebben megértik, hogyan és miért működik úgy, ahogyan működik.

Kezdjük igazán!

Az AsyncAPI támogatásának hozzáadása

Az AsyncAPI a hibrid és eseményvezérelt API-k leírásának de facto szabványává válik. Az EventCatalog természetéből adódóan ennek a specifikációnak a támogatása nagyon értelmes.

Néhány példa séma szerepel a projektemben, hogy valami konkrétat dolgozhassunk.

Az AsyncAPI támogatása egyszerű! Szerencsére már rendelkezésre áll egy „AsyncAPI generátor”, így nem olyan nehéz valamit működésre bírni a dokumentumok kiadása terén, ahogy azt az EventCatalog elvárja az AsyncAPI sémafájljaiból.

A támogatás hozzáadásának alapkonfigurációja az EventCatalog alapértelmezett konfigurációja alapján a következő lehet:

const eventCatalogConfig = {
  title: 'EventCatalog',
  tagline: 'Discover, Explore and Document your Event Driven Architectures',
  organizationName: 'ACME Corp',
  projectName: 'Event Catalog',
  editUrl: 'https://www.acmecorp.xyz',
  trailingSlash: true,
  logo: {
    alt: 'ACME Corp Logo',
    src: 'logo.svg',
  },
  footerLinks: [
    { label: 'Events', href: '/events' },
    { label: 'Services', href: '/services' },
    { label: 'Domains', href: '/domains' },
    { label: 'Visualiser', href: '/visualiser' },
    { label: 'Node graph overview', href: '/overview' },
  ],
  generators: [
    '@eventcatalog/plugin-doc-generator-asyncapi',
    {
      versionEvents: true,
      renderMermaidDiagram: false,
      renderNodeGraph: true
    }
  ]
}

module.exports = eventCatalogConfig;

Amint látja, a generators tömb a generátorra és egy kis további konfigurációra utal, amely ténylegesen működik. Nyugodtan babrálj a beállításokkal.

Most a nehéz részről. Bár ez „papíron jó”, úgy tűnik, hogy vannak tisztázatlan és rossz problémák a Next.js-szal, amely az EventCatalogot futtatja a kód fordítása során.

Ezért kellett létrehoznom egy kis varázslatot a "projektemben", amely vált a építési idejű és a futásidejű konfiguráció között. Ennek működése kissé bonyolult, és összefügg bizonyos korlátozásokkal, amelyeket a Next.js esetében láttam, és hogyan kezeli a konfigurációkat. Tehát, bár csúnya, a működő megoldás az, hogy a konfigurációkat mindkét felhasználási esethez igazítjuk, és egyszerűen kicseréljük őket minden tevékenységre.

A tartomány automatikus kikövetkeztetése

A „build configuration”-ban a fenti megoldás kifejtését találjuk, és azt is, hogy a fájlnév szerkezete alapján adunk hozzá egy domainName-t.

return schemas.map((schemaName) => {
  return [
    // Use the AsyncAPI plugin to deal with this
    '@eventcatalog/plugin-doc-generator-asyncapi',
    // Config + produce the domain from the first part of the file name 
    {
      ...config,
      domainName: schemaName.split('.')[0],
      pathToSpec: path.join(__dirname, `${schemaFolder}/${schemaName}`),
    },
  ]
});

De miért kell így csinálni?

  • Az AsyncAPI sémában nincs domainfogalom. Bár használhatunk egyéni tulajdonságokat ("specifikációs kiterjesztések"), amelyek előtagja x-, magának a generátornak kell módosítania, hogy visszaolvassa ezeket a generálási fázis során. Tekintettel arra, hogy nem szabványos viselkedésről van szó, még csak nem is releváns változtatást kell hozzáadni a generátorprojekthez.
  • Minden bizonnyal készíthetsz egy helyi másolatot a változtatásokról, és másolhatod a fájlt a node_modules mappába és a helyi generátorkódba, de ez természetesen durva és nem megbízható. Amennyit megér, egy kicsit ezt csináltam, de ez a lehető legrosszabb megoldás. Nem azért lettünk szoftvermérnökök, hogy megelégedjünk ilyesmivel.
  • A fájlnév szerkezetének használata a legkönnyebben elképzelhető, feltéve, hogy hozzáfér néhány alapvető információhoz a fájlról. Bár nem egy elegáns megoldás (és csak akkor működik, ha az adott névvel rendelkező fájlok léteznek), ez az egyetlen lehetőség, amelyet vezérelhet, legalábbis egyelőre.
  • Később megvizsgáljuk, és egy sokkal jobb megoldás felé haladunk.

A fájlnév tehát valami ilyesmi lenne: Greetings.Hospitality.GreetService.json, amely a tartomány — rendszer — szolgáltatás hatókörére utal.

Ne feledje, hogy a JSON-ra nincs feltétlenül szükség, és a kódot saját céljaira szabadon módosíthatja. Valójában a JSON használatát javasolnám, amit a megadott beállítás elvár, mivel ez a formátum általában jobban hordozható, és könnyebben ellenőrizhető és felsorolható, mint a YAML-fájlok.

Most már teljes mértékben támogatnia kell az AsyncAPI sémákat, amelyek minden szükséges információt generálnak, beleértve azt is, hogy a séma által hivatkozott rendszer melyik tartományhoz tartozik.

A tervezésről szóló következő részben meglátjuk, hogyan tudjuk ezt később megismételni.

Központosított sémanyilvántartás tervezése

Ezen a ponton a kiegészítő funkcionális támogatás a helyén van.

Még mindig ki kell találnunk, hogyan állítsuk be a dolgokat, ha az EventCatalog-ot központosított erőforrásként szeretnénk használni. Nagyon könnyű elindítani a helyi fork-ot, ragaszkodni néhány sémához, elindítani a fejlesztői kiszolgálót, elégedettnek lenni, megépíteni, és valahol telepíteni. De ismét egy kicsit bonyolultabb lesz, ha több csapatod van, akik folyamatosan ezt akarják csinálni, és ahol az igazság forrása az EventCatalogon kívül található. Próbáljuk meg ezt megoldani!

A helyzet általános összefüggései:

  • Van valamilyen CI/CD-rendszerünk (GitHub, GitLab, CodeBuild, Azure DevOps, Harness…), amelyben rendszereinket teszteljük, megépítjük és üzembe helyezzük.
  • Meg kell osztanunk aforrásszolgáltatásokból (például háttérszolgáltatásokból) származó sémáinkat egy olyan helyre, ahol az EventCatalog építheti azokat a felépítés során.

A következőkhöz konkrét technológiákon alapuló javaslatokat teszek. Ezeket a koncepciókat hasonló termékekre is át kell tudni vinni, de hogy valami konkrétumot mutassak be, az AWS-re, mint felhőszolgáltatóra mutatok rá a háttérrendszer (a továbbiakban: a forrásrendszer) és a Cloudflare Pagesre a front-end rendszer esetében. végrész (azaz EventCatalog).

Nézzünk meg néhány ötletet, amelyek felmerülhetnek.

1. ötlet: Adja át a sémákat a CI-ből a blob-tárolóba

Valószínűleg sokan fognak ehhez nyúlni. Érezhető, hogy ez egyszerű, biztonságos, könnyű és egyszerű. A valóság azonban az, hogy ezek egyike sem – ezekkel rövidesen foglalkozom.

De leginkább a nagy kérdés az, hogy ha valami bekerül a tárolóba, hogyan tudjuk megbizonyosodni arról, hogy a front-end build rendszere tudja ezt? Még nincs teljes megoldásunk, de felismertük, hogy szükség van egy külső helyszínre a sémák számára.

2. ötlet: Használjon S3 objektum eseményeket egy második megmaradási területre való íráshoz

Mivel az S3 objektum eseményeket tud kibocsátani, a tárolóhoz hozzáadott fájlok hatására Lambda függvényeket is futtathatunk. Nyilvánvaló, hogy ez nem lehetséges a konkurens vagy hasonló szolgáltatásokban, de az AWS-ben ez valóban lehetséges. Létrehozhatjuk azt a függvényt, amely a séma tartalmát a vödörből kapja (mivel az objektum esemény nem tartalmazza az objektum tartalmát, csak a nevét és néhány metaadatot) és kiírja a content egy másik perzisztenciára, például a DynamoDB-re, más szolgáltatások eléréséhez.

CI-nk feladata két külön tevékenységből állna:

  1. A séma hozzáadása a vödörhöz.
  2. Hívja fel a front-end build rendszerünket (például a Cloudflare Pages-t), és kérje meg az építés megkezdését.

Bár ez a megoldás valamennyire „teljes”, legalábbis az első nagyon homályos koncepcióhoz képest, ez az egész tele van lyukakkal.

Az első probléma a biztonság kérdése: a GitHubnak hitelesítő adatokkal kell rendelkeznie ahhoz, hogy a fájlt az S3 tárolóba írhassa. Hasonlóképpen, a Pagesnek hitelesítő adatokkal kell rendelkeznie a DynamoDB meghívásához. Mivel ezek nem az AWS-en belüli tartoznak, fájdalmasabb vagy szegényebb (pl. állandó hitelesítési adatok és hosszú életű felhasználók) módszereket kell alkalmaznunk ennek megvalósítására.

Építészetileg bár ez a megoldás jó (és kevésbé jó) módon megvalósítható, ez alapvetően a szolgáltatási határok megsértése is. Jelenleg ez csak néhány szabadon lebegő infrastruktúra, amely akarva-akaratlanul hozzáfér külső, nem AWS-felekhez. Ez nem egy jó és tiszta szolgáltatás.

Elszomorító módon ez a konkrét megoldás sem ad egyértelműséget vagy betekintést abba, hogy a bevitel helyes-e vagy sem. És bár ebben a konkrét esetben nagyon valószínűtlen, a megoldás részben aszinkron jellegéből adódóan, a második hívás (a CF-oldalakra) a DynamoDB inkonzisztens állapotban lehet a front-end build indításakor, és nem használja a legfrissebb információk. Ennek az az oka, hogy a második hívás akkor történik, amikor a fájl a vödörbe kerül – még mindig sikeresen le kell futtatnia a Lambdát a tábla tartalmának eléréséhez, olvasásához és hozzáadásához.

Tovább rontja a helyzetet, ha nem rendelkezik egyértelmű hibakezeléssel, akkor is kezdeményezheti a második hívást, ha az első hívás (a fájl hozzáadása) sikertelen volt.

Pokolian rendetlen.

Sokkal kívánatos lenne egy egyértelműen meghatározott szolgáltatás, amely tartalmazza a szükséges infrastruktúrát és interfészeket mind a termelő, mind a fogyasztó fél számára.

3. ötlet: Építsen egy API-t

Az abszolút leghagyományosabb és legmegfelelőbb megoldás itt egy AWS-tartalmú API biztosítása, amelyet a külső CI-rendszer hívhat meg, például egy jól meghatározott alakzatot követő új séma POST-ozása, amely szintén ellenőrizhető. Ezután tárolhatjuk, a Cloudflare Pages pedig GET kérést tud küldeni, és triviálisan lekérheti az összes tárolt sémát.

Ez a megoldás sok, de nem az összes korábbi problémát javít. Bár nem „Supermax” biztonság, hozzáadhat egy API-kulcs követelményt, hogy egyszerű mechanizmust biztosítson annak biztosítására, hogy illetéktelen felek ne használják.

Ezután hozzuk ezt a célba.

4. ötlet: A felelősségi körök teljes körének viselése

A fenti megoldás jó, és megfelel általános igényeinknek. De még mindig létfontosságú javulást érhetünk el: eltávolíthatjuk a CI-végről még mindig szükséges tudás vagy szivárgó megvalósítás szükségességét. Miért kellett nekik elkezdeni az újjáépítést? Ehelyett DynamoDB adatfolyam-eseményeket fogunk használni, amelyek az INSERT eseményeknél egy Lambdát indítanak el, amely meghívja a Cloudflare Pages API-t ennek érdekében. Ez sem nem zavaros, sem nem nagyon nehéz megvalósítani.

A legjobb az egészben, hogy a CI-vég csak egy dolgot tud: meg kell hívnia a séma API-t a legújabb séma átadásához. A többiről a szerviz gondoskodik.

A streamelési események részletezéséhez érdeklődhet az „AWS outbox bemutató projektem” iránt.

Ebben az esetben természetesen meg kell adnia a séma-nyilvántartást/tárhelyet, de jó helyzetben lesz ahhoz, hogy az ilyen folyamatok nagy részét ezzel a projekttel automatizálja.

Egy ilyen szolgáltatásnak például:

  • API-kulcsra van szükség, amely az ilyen körülmények között elérhető néhány ésszerű engedélyezési lehetőség egyike.
  • Vegyünk egy objektumot, amely magát a sémát, valamint a szolgáltatás nevét és a domainjét tartalmazza.Így nem kell a fájlokat meghatározott formátumban tárolnunk, hanem közvetlen, valós tudást kaphatunk arról, hogy hol található a séma. tartozik.
  • Érvényesítse a bemenetet, és győződjön meg arról, hogy a séma érvényes JSON.
  • Tárolja az adatokat, például egy olyan mintával, mint például a PK, amely egy tág fogalomra van leképezve, mint például a SCHEMA, és a SK, amely a szolgáltatás nevére van leképezve. Így az összes sémát lekérhetjük úgy, hogy lekérdezzük a „tág” PK kifejezést – ez tökéletes a front-end összeállítási folyamatunkhoz.
  • Az adatoknak egyszerű, láncolt JSON-nak kell lenniük; már ellenőriztük, hogy ez érvényes JSON, így nem árt ezt megtenni. Ezenkívül adjon hozzá egy attribútumot a domain névhez. Talán adjon hozzá egy időbélyeg attribútumot is, hogy megértse az adatok frissségét.

A „StartRebuild” lambda

Ez nagyon könnyű. Csak meg kell hívnia a Cloudflare Pages API-t, és kérnie kell a folyamatot. A göndörítéssel ez így néz ki:

curl --request POST \
     --url "https://api.cloudflare.com/client/v4/accounts/$CLOUDFLARE_ACCOUNT_ID/pages/projects/$CLOUDFLARE_CATALOG_NAME/deployments" \
     --header "Authorization: Bearer $CLOUDFLARE_AUTH_TOKEN" \
     --header "Content-Type: application/json"

Szükség szerint alkalmazkodjon nyelvéhez.

Működőképes CI-ben

Ahhoz, hogy ezt a CI-hez csomagoljuk, azt akarjuk, hogy a struktúra determinisztikusan, megbízhatóan állványozható legyen minden alkalommal, amikor (például) új véglegesítés történik egy kódtárhoz. Maga az EventCatalog már jó néhány dolgot megtesz a „telepítéskor”, szóval ennek szkriptezése nem nagy dolog.

Az „állványprojekt” ismét ezt kínálja, mivel a két konfigurációt (a építési időt és a futási időt) ötvözi a fájlok telepítésével, előkészítésével és mozgatásával, valamint a nekünk nem szükséges alaplap törlésével. A tényleges projekt beállításának nagy részét a create-eventcatalog.sh Bash szkript tartalmazza.

Amivel foglalkoznia kell, az az, hogy néhány módosítást kell végrehajtania, hogy ne töltse be a példasémákat. Ehelyett vegye ki a sémákat a rendszerleíró adatbázisból. Ettől eltekintve nagyjából indulásra készen kell lennie. A körülményekhez igazítani kell.

A szkript kérni fogja a katalógus (mappa) nevét, és az EventCatalog segítségével generálja azt. A CI-nek csak egy statikus nevet adhatunk, amelyet mindig használunk, mivel a CI környezet átmeneti. A telepítés után hozzáadja az AsyncAPI generátort, és bemásolja a mellékelt konfigurációs fájlokat és példasémákat. Ez kell a legtöbb, amire szüksége van.

Végül felvázolom azokat a lépéseket, amelyeket a CI-folyamataiban végre kell hajtania.

A forrásrendszer CI lépései

  • Telepítsen, fordítson, építsen, teszteljen, és tegye meg azt, amit általában.
  • Tolja be a sémát a rendszerleíró adatbázisba.

Az EventCatalog CI lépései

  • Húzza ki a sémákat a rendszerleíró adatbázisból.
  • Az EventCatalog létrehozása a sémák használatával a konfigurációs bemenet részeként.
  • Telepítse a webhelyet, például:
npx wrangler pages publish "$DOCS_FOLDER" --project-name="$CLOUDFLARE_PROJECT_NAME"

Ennyi! Most már mindennek a helyére kell kerülnie! 🎉

összefoglalva

Remélem, sikerült meggyőzni arról, hogy érdemes és nem túl nehéz befektetés az EventCataloghoz hozzáadni némi húst és csontot, hogy nagyobb szervezetekben is tengerre alkalmassá tegyük. Nem magának a projektnek a hibája, de remélhetőleg ez a cikk legalább gyakorlati útmutatást ad, hogyan állítsa be eseménytárként.

Sok sikert az építkezéshez és a rendezvényekhez!