Runtime et observabilité avec Aspire
Après que Lino a généré des services, des web apps et des ressources d'infrastructure, Aspire aide à tout exécuter localement avec de la visibilité. L'observabilité n'est pas un luxe : elle montre si les APIs, les bases de données, le cache, la messagerie et les workers sont sains.
Dans les applications avec événements, Outbox, workers, Redis, RabbitMQ et plusieurs modules, beaucoup de problèmes n'apparaissent pas seulement à l'écran. Ils apparaissent dans les logs, les files, les jobs, les migrations, les paramètres et les ressources de runtime. Cette section montre comment regarder la solution comme un système en cours d'exécution, et pas seulement comme des fichiers générés.
Exécution avec Aspire
L'AppHost centralise l'exécution locale de la solution. Il démarre les services, les applications web et les dépendances comme PostgreSQL, Redis, RabbitMQ et les workers.
dotnet run --project src/Aspire/AppHost/<ProjectName>.AppHost.csproj
Utilisez le dashboard pour vérifier les logs, les variables, les endpoints et l'état des ressources. Si un service échoue au démarrage, commencez par l'AppHost et par les dépendances qu'il injecte.
Aspire rend visible la topologie locale : APIs, web apps, bases de données, cache, broker de messages et workers apparaissent comme des ressources liées. Cette vue aide à trouver des erreurs de configuration qui resteraient cachées dans une exécution manuelle, comme une connection string incorrecte, un paramètre manquant, un service sans endpoint ou une dépendance qui n'a pas encore démarré.
- Logs : suivez les erreurs d'initialisation, les échecs d'authentification, les problèmes de migrations et les messages des workers.
- Endpoints : confirmez les ports, les URLs, les health checks et les liens vers les web apps et les APIs.
- Paramètres : validez les secrets et les variables propagés vers chaque service.
- Dépendances : vérifiez que Redis, RabbitMQ et la base de données ont été provisionnés avant de diagnostiquer l'application.
Ressources de base de données
Les services générés par Lino ont généralement leurs propres DbContexts, migrations et connection strings. Dans les systèmes modulaires, vérifiez que chaque module utilise la base de données/le schema attendu et que les migrations ont été appliquées au bon endroit.
- Confirmez les connection strings par environnement.
- Exécutez les migrations avant de tester les flux qui dépendent d'un nouveau schema.
- Surveillez les échecs de connexion et le temps de query.
- Évitez d'utiliser une base de données de production en exécution locale.
Dans un service simple, la base de données accompagne le service. Dans un service modulaire, la base de données appartient au service, mais chaque module peut avoir son propre schema, DbContext, ses migrations et ses scripts. Cette séparation doit aussi apparaître dans l'exploitation : lors de l'application des migrations, confirmez le service, le module, le provider et l'environnement avant d'exécuter.
Les erreurs de base de données apparaissent souvent comme une erreur d'API, mais la cause peut se trouver dans l'AppHost, la connection string, une migration en attente, un schema inexistant ou un identifiant local. Le diagnostic doit donc commencer par toute la chaîne : paramètre dans Aspire, ressource de base de données active, migration appliquée, DbContext correct et endpoint appelant le module attendu.
Redis et cache
Redis peut être utilisé pour le cache, l'état temporaire, les tokens, le rate limiting ou d'autres ressources selon les templates activés. Le cache améliore les performances, mais introduit l'invalidation et la cohérence éventuelle.
Documentez les clés, le temps d'expiration et l'origine des données. Ne stockez jamais de secrets sensibles en cache sans comprendre le chiffrement, l'expiration et l'accès.
Lorsque le projet utilise un cache distribué, plusieurs instances peuvent partager des valeurs, ce qui est utile pour la mise à l'échelle horizontale. Lorsqu'il utilise seulement un cache local en mémoire, chaque processus conserve sa propre copie. Cette différence affecte le comportement en production, les tests de charge et l'invalidation des données.
| Question | Pourquoi c'est important |
|---|---|
| Quelle est l'origine de la donnée en cache ? | Définit comment recalculer la valeur lorsqu'elle expire ou est invalidée. |
| Quel TTL est acceptable ? | Détermine combien de temps le système tolère des données potentiellement anciennes. |
| Le cache est-il par tenant, par utilisateur ou global ? | Évite les fuites de données entre contextes et les clés mal modélisées. |
RabbitMQ et messagerie
La messagerie soutient les événements d'intégration et la communication asynchrone. Avec Outbox, l'application ne dépend pas de la publication du message au même instant que la transaction ; le worker peut réessayer.
- Vérifiez les exchanges, files et bindings générés.
- Surveillez les messages bloqués et les consommateurs inactifs.
- Concevez des handlers idempotents.
- Utilisez des logs de corrélation pour suivre le chemin du message.
Les événements d'intégration sont utiles précisément parce que le producteur n'a pas besoin d'attendre tous les consommateurs. Mais cela déplace une partie de la complexité vers l'exploitation : les messages peuvent être retardés, les consommateurs peuvent échouer, les payloads peuvent changer et les handlers peuvent être exécutés plusieurs fois. La documentation du flux doit indiquer clairement quel événement est publié, qui le consomme et quel état local est mis à jour.
Les Shadow Entities dépendent de cette observabilité. Si une entité de tenant ou d'utilisateur est répliquée vers d'autres modules par événement, un échec du consommateur peut laisser la copie locale obsolète. Le système doit permettre de diagnostiquer l'événement, le message, le handler et la mise à jour réalisée dans la base de données du module consommateur.
Hangfire Dashboard
Lorsque les background jobs sont activés, le Hangfire Dashboard aide à inspecter les jobs récurrents, les échecs, les retries et l'exécution du traitement Outbox.
Protégez le dashboard dans les environnements partagés. Il expose des informations opérationnelles importantes et ne doit pas être public sans authentification et autorisation.
Utilisez le dashboard comme outil de diagnostic, pas comme substitut aux logs et aux métriques. Il montre les files, les tentatives et l'historique d'exécution, mais une investigation complète nécessite encore un correlation id, des logs structurés et du contexte métier pour comprendre pourquoi un job a échoué.
- Retries : vérifiez si l'échec est transitoire ou si le job continuera à échouer indéfiniment.
- Jobs récurrents : confirmez l'intervalle, le lot et la durée moyenne d'exécution.
- Outbox : observez les messages bloqués, le retraitement et les handlers avec exception.
- Sécurité : restreignez l'accès, car les payloads et les erreurs peuvent révéler des données sensibles.
Workers et traitement en arrière-plan
Les workers exécutent des tâches qui ne doivent pas bloquer les requêtes HTTP : envoi de messages, traitement Outbox, nettoyage, synchronisation et intégrations externes.
- Utilisez des lots adaptés au volume.
- Définissez les retries et la gestion des échecs.
- Journalisez les erreurs avec suffisamment de contexte pour retraiter.
- Ne masquez pas les échecs permanents dans des logs génériques.
Lors de l'ajout d'un worker, définissez aussi la fréquence, la taille du lot, le comportement en cas d'échec et l'impact sur le domaine. Un worker qui lit 100 enregistrements toutes les quelques secondes a un comportement opérationnel différent d'un job quotidien ; les deux doivent être observés et dimensionnés selon le volume réel.
N'exécutez pas en arrière-plan ce qui doit répondre immédiatement à l'utilisateur. Utilisez un worker pour les tâches ultérieures, les intégrations, les notifications, le retraitement et la maintenance. Si le cas d'utilisation dépend du résultat pour compléter la transaction, traitez-le comme un flux synchrone ou modélisez un état intermédiaire visible pour l'utilisateur.
