Skip to content

0030. Registry istanze connettore: N istanze per tipo, via lista env + registry generico

  • Stato: Accettata
  • Data: 2026-07-24
  • Decisori: Team BI/ETL

Contesto

Un'istanza ETL può realisticamente dover parlare con N istanze dello stesso tipo di connettore: più DB Postgres (sorgente + data warehouse), più workspace Noeva, più server FTP/SFTP, più bucket S3. Fino a oggi questo è risolto solo per Noeva: NOEVA_WORKSPACE_IDS elenca i workspace ammessi e buildWorkspaceRegistry (ADR-0022) li valida con fail-fast. Per Postgres, SQL Server, FTP, SFTP e S3, invece, la molteplicità esiste solo come convenzione: load*Config(prefix) legge una singola istanza da env e "più istanze" significa "chiama il loader con un prefisso diverso" (es. loadPgPoolConfig("DWH_")), senza alcun registro né validazione di quali istanze l'ETL può toccare.

ADR-0021 aveva esplicitamente rimandato la config per-istanza dei connettori sorgente/destinazione "a un ADR dedicato": questo è quell'ADR.

Un'alternativa discussa era definire le connessioni in un file JSON montato (vedi issue #63, poi superseded): scartata perché introduce un artefatto di segreti da mettere in sicurezza — che ADR-0021 aveva già rifiutato per i workspace — e una strategia segreti dedicata, mentre l'approccio a lista env resta dentro il modello .env già in uso e la regola "niente segreti in chiaro versionati" (CLAUDE.md).

Decisione

Ogni tipo di connettore dichiara le sue istanze con una lista env e le risolve attraverso un registry generico validato.

  • Core generico (src/connectors/shared/registry.ts): buildConnectorRegistry<T>(entries) costruisce una mappa id → T; get(id) lancia ConfigError fail-fast se l'id non è configurato — il messaggio elenca gli id ammessi, mai i segreti. buildWorkspaceRegistry diventa un wrapper sottile sopra questo core, a comportamento Noeva invariato.
  • Loader per-connettore load<Kind>Registry(env): parsa <PREFIX>_INSTANCES (lista separata da virgole; trim, no vuoti, no duplicati → fail-fast, come loadEtlWorkerConfigs) e per ogni id chiama load<Kind>Config("<PREFIX>_<ID>_"). Convenzione: PG_INSTANCES=src,dwhPG_SRC_* / PG_DWH_*; idem MSSQL_INSTANCES, FTP_INSTANCES, SFTP_INSTANCES, S3_INSTANCES. Noeva mantiene NOEVA_WORKSPACE_IDS (istanze a credenziali condivise: una sola API key, varia solo l'id).
  • Default implicito: se <PREFIX>_INSTANCES non è impostata ma esistono le variabili <PREFIX>_*, il loader registra un'unica istanza con id default. Il caso a istanza singola resta quindi ergonomico, ma passa comunque dal registry.
  • Registry obbligatorio (breaking): le pipeline non chiamano più load*Config(prefix) direttamente; risolvono i connettori con registry.get(id). load*Config resta come mattone per-istanza usato dal registry, non come API di composizione.
  • Selezione istanza: ogni pipeline dichiara l'id come costante nel proprio codice (es. const PG_INSTANCE = "langfuse"), risolto via registry.get(id). Un override via env per-pipeline resta un'aggiunta futura non necessaria ora.
  • Lifecycle: il registry è su config (get(id): TConfig); l'apertura/chiusura dei pool resta nella run() della pipeline (try/finally), come oggi. Per client stateless (Noeva/S3) il registry può esporre un factory client(id).
  • Descriptor: source/sink espongono l'id di istanza nel descriptor del nodo, così la UI (issue #64) può mostrarlo e mascherarne i valori sensibili.

Alternative considerate

  • File JSON di config (issue #63) — scartata: artefatto di segreti da proteggere e strategia segreti dedicata, contro la semplicità del modello .env esistente.
  • Config dal server via RunContext/API — rimandata: è il seam predisposto da ADR-0021 per il futuro (gestione centrale, override per-workspace), ma cross-repo e fuori dallo scope.
  • Mantenere la convenzione a prefisso singolo come fallback — scartata: lascerebbe due percorsi (registry per Noeva, prefisso ad-hoc per gli altri) e nessuna guardia uniforme su "quali istanze sono ammesse".

Conseguenze

  • Uniformità: qualunque connettore usa lo stesso registry e la stessa validazione fail-fast.
  • Breaking: le pipeline che usavano load*Config(prefix) diretto vanno migrate a registry.get(id) (oggi: solo langfuse-sessions-daily). .env.example, schede pipeline e tests/integration/* vanno aggiornati alla convenzione <PREFIX>_INSTANCES.
  • Nessun nuovo segreto e nessun nuovo artefatto: le credenziali restano in .env; i messaggi d'errore elencano solo gli id ammessi.
  • Abilita le issue #64 (masking della config nel dettaglio nodo) e chiude/supersede #63 nell'epic #66.

Noeva è un marchio registrato di 4D S.R.L.