Runtime e osservabilità con Aspire

Dopo che Lino genera servizi, web app e risorse di infrastruttura, Aspire aiuta a eseguire tutto localmente con visibilità. L'osservabilità non è un lusso: mostra se APIs, database, cache, messaggistica e worker sono sani.

Nelle applicazioni con eventi, Outbox, worker, Redis, RabbitMQ e più moduli, molti problemi non appaiono solo sullo schermo. Appaiono in log, code, jobs, migrations, parametri e risorse di runtime. Questa sezione mostra come guardare la soluzione come un sistema in esecuzione, non solo come file generati.

Esecuzione con Aspire

L'AppHost centralizza l'esecuzione locale della soluzione. Avvia servizi, web app e dipendenze come PostgreSQL, Redis, RabbitMQ e worker.

dotnet run --project src/Aspire/AppHost/<ProjectName>.AppHost.csproj

Usa il dashboard per verificare log, variabili, endpoint e stato delle risorse. Se un servizio non riesce ad avviarsi, parti dall'AppHost e dalle dipendenze che inietta.

Aspire rende visibile la topologia locale: APIs, web app, database, cache, message broker e worker appaiono come risorse correlate. Questa vista aiuta a trovare errori di configurazione che resterebbero nascosti in un'esecuzione manuale, come una connection string errata, un parametro mancante, un servizio senza endpoint o una dipendenza che non è ancora partita.

  • Log: segui errori di inizializzazione, errori di autenticazione, problemi di migrations e messaggi dei worker.
  • Endpoint: conferma porte, URL, health checks e link a web app e APIs.
  • Parametri: valida secrets e variabili propagate a ogni servizio.
  • Dipendenze: verifica che Redis, RabbitMQ e il database siano stati provisionati prima di diagnosticare l'applicazione.

Risorse di database

I servizi generati da Lino normalmente hanno DbContexts, migrations e connection strings propri. Nei sistemi modulari, valida che ogni modulo usi il database/schema previsto e che le migrations siano state applicate nel posto corretto.

  • Conferma le connection strings per ambiente.
  • Esegui le migrations prima di testare flussi che dipendono da un nuovo schema.
  • Monitora errori di connessione e tempi di query.
  • Evita di usare un database di produzione durante l'esecuzione locale.

In un servizio semplice, il database segue il servizio. In un servizio modulare, il database appartiene al servizio, ma ogni modulo può avere il proprio schema, DbContext, migrations e script. Questa separazione deve comparire anche nelle operazioni: quando applichi migrations, conferma servizio, modulo, provider e ambiente prima di eseguire.

Gli errori di database spesso appaiono come errori di API, ma la causa può essere nell'AppHost, nella connection string, in una migration pendente, in uno schema inesistente o in una credenziale locale. Per questo la diagnosi deve iniziare dalla catena completa: parametro in Aspire, risorsa database attiva, migration applicata, DbContext corretto ed endpoint che chiama il modulo previsto.

Redis e cache

Redis può essere usato per cache, stato temporaneo, token, rate limiting o altre risorse in base ai template abilitati. La cache migliora le prestazioni, ma introduce invalidazione e consistenza eventuale.

Documenta chiavi, tempo di scadenza e origine dei dati. Non memorizzare mai secrets sensibili in cache senza comprendere cifratura, scadenza e accesso.

Quando il progetto usa cache distribuita, più istanze possono condividere valori, cosa utile per la scalabilità orizzontale. Quando usa solo cache locale in memoria, ogni processo mantiene la propria copia. Questa differenza influisce sul comportamento in produzione, sui test di carico e sull'invalidazione dei dati.

DomandaPerché è importante
Qual è l'origine del dato in cache?Definisce come ricalcolare il valore quando scade o viene invalidato.
Quale TTL è accettabile?Determina per quanto tempo il sistema tollera dati potenzialmente vecchi.
La cache è per tenant, utente o globale?Evita perdite di dati tra contesti e chiavi modellate male.

RabbitMQ e messaggistica

La messaggistica sostiene eventi di integrazione e comunicazione asincrona. Con Outbox, l'applicazione non dipende dalla pubblicazione del messaggio nello stesso istante della transazione; il worker può riprovare.

  • Verifica exchanges, code e bindings generati.
  • Monitora messaggi bloccati e consumer inattivi.
  • Progetta handlers idempotenti.
  • Usa log di correlazione per seguire il percorso del messaggio.

Gli eventi di integrazione sono utili proprio perché il producer non deve attendere tutti i consumer. Ma questo sposta parte della complessità sulle operazioni: i messaggi possono ritardare, i consumer possono fallire, i payloads possono cambiare e gli handlers possono essere eseguiti più di una volta. La documentazione del flusso deve chiarire quale evento viene pubblicato, chi lo consuma e quale stato locale viene aggiornato.

Le Shadow Entities dipendono da questa osservabilità. Se un'entità di tenant o utente viene replicata in altri moduli tramite evento, un errore nel consumer può lasciare la copia locale non aggiornata. Il sistema deve permettere di diagnosticare evento, messaggio, handler e aggiornamento eseguito nel database del modulo consumer.

Hangfire Dashboard

Quando i background jobs sono abilitati, l'Hangfire Dashboard aiuta a ispezionare jobs ricorrenti, errori, retries ed esecuzione del processamento Outbox.

Proteggi il dashboard negli ambienti condivisi. Espone informazioni operative rilevanti e non deve essere pubblico senza autenticazione e autorizzazione.

Usa il dashboard come strumento di diagnosi, non come sostituto di log e metriche. Mostra code, tentativi e storico di esecuzione, ma l'indagine completa richiede ancora correlation id, log strutturati e contesto di business per capire perché un job è fallito.

  • Retries: verifica se l'errore è transitorio o se il job continuerà a fallire indefinitamente.
  • Jobs ricorrenti: conferma intervallo, batch e durata media di esecuzione.
  • Outbox: osserva messaggi bloccati, riprocessamento e handlers con eccezione.
  • Sicurezza: limita l'accesso, perché payloads ed errori possono rivelare dati sensibili.

Worker e processamento in background

I worker eseguono attività che non devono bloccare richieste HTTP: invio di messaggi, processamento Outbox, pulizia, sincronizzazione e integrazioni esterne.

  • Usa batch adeguati al volume.
  • Definisci retries e gestione degli errori.
  • Registra errori con contesto sufficiente per riprocessare.
  • Non nascondere errori permanenti in log generici.

Quando aggiungi un worker, definisci anche frequenza, dimensione del batch, comportamento in caso di errore e impatto sul dominio. Un worker che legge 100 record ogni pochi secondi ha un comportamento operativo diverso da un job giornaliero; entrambi devono essere osservati e dimensionati secondo il volume reale.

Non eseguire in background ciò che deve rispondere immediatamente all'utente. Usa un worker per attività successive, integrazioni, notifiche, riprocessamento e manutenzione. Se il caso d'uso dipende dal risultato per completare la transazione, trattalo come flusso sincrono o modella uno stato intermedio visibile all'utente.

Si è verificato un errore non gestito. Ricarica 🗙