Receptek
Három minta lefedi majdnem mindazt, amire egy éles projektnek szüksége van az Áttekintés oldal alap Load/MustLoad hívásán túl: egy root config összeállítása több modul configjából, ugyanannak a formának a többszöri betöltése különböző prefixekkel, és a konfigurációt olvasó kód tesztelése.
Root Config összeállítása modul-configokból
Minden gp-system modul, amelynek konfigurációra van szüksége, exportálja a saját Config structját, a saját mezőnevein tagelve, anélkül, hogy véleménye lenne arról, mi (ha egyáltalán bármi) prefixeli őket. Egy generált gpsystem projekt ezeket a structokat egyetlen, alkalmazás-szintű Config-ba komponálja, mezőkként beágyazva és envPrefix-szel prefixet választva mezőnként:
package config
import (
"github.com/gp-system/dbx"
"github.com/gp-system/events/outbox"
"github.com/gp-system/framework/server"
"github.com/gp-system/framework/worker"
)
type Config struct {
Server server.Config
DB dbx.Config `envPrefix:"DB_"`
Worker worker.Config
Outbox outbox.Config `envPrefix:"OUTBOX_"`
}
cfg := envconf.MustLoad[config.Config]()
Egyetlen envconf.Load[AppConfig]() (vagy MustLoad) hívás a main() elején mindaz, amire egy folyamatnak szüksége van: minden modul beállítása egyetlen structban érkezik, teljesen típusosan, és a kódbázis semelyik más pontján nem parseol semmit tovább. A szabály egyszerű: egy modul a saját mezőit nevezi el, a beágyazó dönti el a prefixet. A dbx.Config saját tagjei HOST, PORT, USER, ...; a envPrefix:"DB_" alatt beágyazva DB_HOST, DB_PORT, DB_USER lesz belőlük. Egy prefix nélkül beágyazott struct (mint a fenti server.Config) a saját, prefix nélküli neveik alatt olvassa a változóit. A beágyazás tetszőlegesen mélyre mehet: a server.Config maga is beágyaz egy telemetry.Config-ot, prefix nélkül, mert a változói (OTEL_SERVICE_NAME, SENTRY_DSN, LOG_LEVEL) már iparági szabvány nevek, amiket minden OTel/Sentry-tudatos eszköz úgy vár, ahogy vannak. Lásd a Konfiguráció oldalt a teljes prefix-táblázatért, amibe a gpsystem saját moduljai rendeződnek.
Prefixelt multi-instance betöltések
Az envPrefix egy beágyazott mezőn csak akkor segít, ha a struct egyszer van beágyazva. Amikor egy folyamatnak valóban két független példányra van szüksége ugyanabból a konfig-formából (két Valkey-kapcsolat: egy a cache-hez, egy a queue-hoz), a LoadPrefixed ugyanazt a típust kétszer tölti be, két különböző felső szintű prefix alatt, struct-beágyazás nélkül:
type ValkeyConfig struct {
Addr string `env:"ADDR,required"`
Password string `env:"PASSWORD"`
DB int `env:"DB" envDefault:"0"`
}
cache, err := envconf.LoadPrefixed[ValkeyConfig]("CACHE_VALKEY_") // CACHE_VALKEY_ADDR, CACHE_VALKEY_PASSWORD, CACHE_VALKEY_DB
queue, err := envconf.LoadPrefixed[ValkeyConfig]("QUEUE_VALKEY_") // QUEUE_VALKEY_ADDR, QUEUE_VALKEY_PASSWORD, QUEUE_VALKEY_DB
CACHE_VALKEY_ADDR=localhost:6379
QUEUE_VALKEY_ADDR=localhost:6380
QUEUE_VALKEY_DB=1
Minden hívás független: egy hiányzó required mező az egyik prefix alatt csak azt a hívást buktatja el, a másikat nem. A LoadPrefixed-hez akkor nyúlj, ha a két példány valóban külön kapcsolat, egymástól függetlenül változó beállításokkal; ha mindig ugyanazt az értéket osztanák meg, egy egyszerű, prefix nélküli Config mező egyszerűbb.
Tesztelés t.Setenv-vel
Mivel a Load/MustLoad a valódi folyamat-környezetet olvassa, a konfigurációtól függő kódot gyakorló tesztek közvetlenül a t.Setenv-vel állítják be, amit a Go automatikusan visszaállít a teszt után (és elbukik, ha a teszt párhuzamos, ami a helyes bukás: a környezeti változók folyamat-globális állapot):
func TestLoad_defaults(t *testing.T) {
t.Setenv("DB_HOST", "localhost")
t.Setenv("DB_USER", "test")
cfg := envconf.MustLoad[config.Config]()
if cfg.DB.Host != "localhost" {
t.Errorf("DB.Host = %q, want %q", cfg.DB.Host, "localhost")
}
}
func TestLoad_missingRequired(t *testing.T) {
// a DB_HOST szándékosan nincs beállítva
_, err := envconf.Load[config.Config]()
if err == nil {
t.Fatal("expected an error for missing required DB_HOST")
}
}
Itt nincs szó .env fájlról: a t.Setenv valódi folyamat-környezeti változókat állít be a teszt idejére, pontosan azt, amit a Load először olvas (mielőtt bármilyen .env-értékre visszaesne), így a teszt determinisztikus, függetlenül attól, hogy létezik-e épp .env fájl a munkakönyvtárban.
A frameworkkel
Egy generált gpsystem projekt internal/platform/config csomagja pontosan a fenti kompozíciós minta, egyszer generálva és az add surface/add db/add worker által bővítve, ahogy modulok kerülnek a projektbe. Lásd a Konfiguráció oldalt a koncepció-szintű nézetért (miért explicit, csak boot-időben létező függőség a konfiguráció gpsystemben), és a Konfigurációs referenciát a teljes, generált-projektenkénti változótáblázatért.
Kapcsolódó oldalak
- envconf: Áttekintés:
Load/MustLoad/LoadPrefixed, tagek,.env-betöltés. - Konfiguráció: a kompozíciós elv és a gp-system modulok közti prefix-konvenciók.
- Konfigurációs referencia: minden env-változó, modulonként.