Folyamat figyelő állapotváltozás-detektálással: dmon

A werkstatt sorozat kilencedik és utolsó része – egy process monitor ami YAML konfigból figyeli a futó folyamatokat és jelzi ha valami elindul vagy leáll.

Folyamat figyelő állapotváltozás-detektálással: dmon

A sorozat utolsó projektje a legegyszerűbb ötlettel indult: tudni akarom hogy a szerveremen futnak-e azok a folyamatok amiknek futniuk kell. Az sshd, a podman, a specifikus szolgáltatások. Ha valamelyik leáll, akarok róla tudni.

A dmon nem csinál bonyolult dolgot. Beolvas egy YAML konfigot a figyelt folyamatokkal, és egy végtelen ciklusban ellenőrzi őket. Az első futásnál kiírja az aktuális állapotot. Utána már csak a változásokat jelzi – ha valami elindul vagy leáll.

Állapotváltozás-detektálás

A legtöbb monitor tool minden ellenőrzésnél kiírja a teljes állapotot. A dmon csak a változásokat. Ehhez egy prev map tárolja az előző állapotot:

type StateChange struct {
    Name    string
    Running bool
    Changed bool
    First   bool
}

Három eset van: az első futás (First), amikor még nincs előzmény. Az állapotváltozás (Changed), amikor a jelenlegi állapot különbözik az előzőtől. És a változatlan állapot, amit nem kell kiírni.

Ez a minta a monitoring eszközök alapja – nem a pillanatnyi állapot a fontos, hanem a változás.

A –once flag

Az eredeti verzió csak folyamatosan futott. A production ready verzió kapott egy --once flag-et ami egyszer lefuttatja az ellenőrzést és kilép. Ez cron-ból vagy más scriptekből hasznos:

dmon -once --no-color || ntfy pub monitoring "dmon: process down"

Az --once az sshping exit code mintáját követi – a kimenet nem csak olvasható, hanem scriptelhető is.

A checker interface

A dmon a pgrep -x paranccsal ellenőrzi a folyamatokat. A tesztekben nem akarok valódi folyamatokat keresni, ezért a checker interface absztrahálja:

type checker interface {
    isRunning(name string) bool
}

A mockChecker egy map-ből olvassa hogy melyik folyamat “fut”:

chk := mockChecker{status: map[string]bool{
    "sshd":  true,
    "nginx": false,
}}

Ez lehetővé teszi hogy a teljes állapotváltozás-detektálást teszteljük: első futás, változás, leállás, változatlan állapot. Minden eset lefuttatható egy milliszekundum alatt, pgrep nélkül.

A checkAll függvény

A logika a checkAll függvényben van – megkapja a folyamatok listáját, az előző állapotot, és a checker-t. Visszaad egy StateChange slice-ot:

func checkAll(processes []string, prev map[string]bool, chk checker) []StateChange

Ez a sorozat tanulságainak összefoglalása: a logika egy tiszta függvényben van ami bemenetet kap és kimenetet ad. Nem olvas globális változót, nem hív meg közvetlenül külső parancsot, nem ír a konzolra. Tesztelhető, olvasható, cserélhető.

Kilenc projekt, egy minta

A dmon-nal a werkstatt sorozat véget ér. Kilenc projekt, mindegyik más Go koncepciót tanított:

Az envcheck a fájl I/O-t és a flag csomagot. A stackctl a HTTP szervert és a JSON struktúrákat. A netmapper a goroutine-okat és channel-eket. A deployer az interface-alapú dependency injection-t. A portspy a párhuzamos scanning mintát. Az sshping a dialer interface-t és az exit code-okat. A hookrelay a POST kezelést és a JSON Lines logolást. A kvault az RWMutex-et és a CRUD ciklust. A dmon az állapotváltozás-detektálást és a checker interface-t.

De az igazi tanulság nem az egyes koncepciók, hanem a minta ami ismétlődik: interface az absztrakcióhoz, flag a konfigurációhoz, tesztek a megbízhatósághoz. Ez a három elem teszi a scriptet eszközzé.

Hogyan próbáld ki?

git clone https://github.com/brtkcs/werkstatt-tools.git
cd werkstatt-tools/dmon
go mod tidy

Hozz létre egy dmon.yaml-t:

interval: 5
processes:
  - sshd
  - podman

Aztán:

go run main.go

Vagy egyszer futtatva:

go run main.go -once

A teljes forráskód a werkstatt-tools repóban.

Ez a werkstatt sorozat záró része. Kilenc Go projekt, kilenc blogposzt, kilenc valódi rendszergazda probléma. A dmon az utolsó darab – egy egyszerű, folyamatos figyelő ami az állapotváltozásokra koncentrál.