Cette documentation a été traduite automatiquement par IA.
Dans un environnement à nœud unique, les plugins peuvent généralement répondre aux besoins via des états, des événements ou des tâches au sein du processus. Cependant, en mode cluster, le même plugin peut s'exécuter simultanément sur plusieurs instances, ce qui soulève les problèmes typiques suivants :
Le cœur de NocoBase intègre diverses interfaces middleware au niveau de la couche applicative pour aider les plugins à réutiliser des fonctionnalités unifiées dans un environnement cluster. Les sections suivantes présenteront l'utilisation et les meilleures pratiques en matière de mise en cache, de messagerie synchrone, de files d'attente de messages et de verrous distribués, avec des références au code source.
Pour les données qui doivent être stockées en mémoire, il est recommandé d'utiliser le composant de cache intégré au système pour leur gestion.
app.cache.Cache offre des opérations de base comme set/get/del/reset, et prend également en charge wrap et wrapWithCondition pour encapsuler la logique de mise en cache, ainsi que des méthodes de traitement par lots comme mset/mget/mdel.ttl (durée de vie) raisonnable pour éviter la perte de cache en cas de redémarrage de l'instance.Exemple : Initialisation et utilisation du cache dans le plugin-auth
Si l'état en mémoire ne peut pas être géré avec un cache distribué (par exemple, s'il ne peut pas être sérialisé), alors lorsque l'état change suite à des actions utilisateur, cette modification doit être notifiée aux autres instances via un signal synchrone pour maintenir la cohérence de l'état.
sendSyncMessage, qui appelle en interne app.syncMessageManager.publish et ajoute automatiquement un préfixe au niveau de l'application au canal pour éviter les conflits.publish peut spécifier une transaction ; le message sera alors envoyé après la validation de la transaction de base de données, garantissant ainsi la synchronisation de l'état et du message.handleSyncMessage pour traiter les messages provenant d'autres instances. La souscription pendant la phase beforeLoad est très appropriée pour des scénarios tels que les modifications de configuration et la synchronisation de schéma.La diffusion de messages est le composant sous-jacent des signaux synchrones et peut également être utilisée directement. Lorsque vous avez besoin de diffuser des messages entre les instances, vous pouvez le faire via ce composant.
app.pubSubManager.subscribe(channel, handler, { debounce }) permet de s'abonner à un canal entre les instances ; l'option debounce est utilisée pour éviter les rappels fréquents causés par des diffusions répétées.publish prend en charge skipSelf (vrai par défaut) et onlySelf pour contrôler si le message est renvoyé à l'instance actuelle.Exemple : plugin-async-task-manager utilise PubSub pour diffuser les événements d'annulation de tâche
La file d'attente de messages est utilisée pour planifier des tâches asynchrones, ce qui convient aux opérations de longue durée ou aux opérations pouvant être retentées.
app.eventQueue.subscribe(channel, { idle, process, concurrency }). process renvoie une Promise, et vous pouvez utiliser AbortSignal.timeout pour contrôler les délais d'attente.publish ajoute automatiquement le préfixe du nom de l'application et prend en charge des options comme timeout et maxRetries. Il utilise par défaut un adaptateur de file d'attente en mémoire, mais peut être basculé vers des adaptateurs étendus comme RabbitMQ si nécessaire.Exemple : plugin-async-task-manager utilise EventQueue pour planifier des tâches
Lorsque vous devez éviter les conditions de concurrence, vous pouvez utiliser un verrou distribué pour sérialiser l'accès à une ressource.
local basé sur le processus est fourni. Vous pouvez enregistrer des implémentations distribuées comme Redis. Utilisez app.lockManager.runExclusive(key, fn, ttl) ou acquire/tryAcquire pour contrôler la concurrence.ttl (durée de vie) est utilisé comme mesure de sécurité pour libérer le verrou, l'empêchant d'être détenu indéfiniment dans des cas exceptionnels.app.cache et app.syncMessageManager pour éviter de réimplémenter la logique de communication inter-nœuds dans vos plugins.transaction.afterCommit (intégré à syncMessageManager.publish) pour garantir la cohérence des données et des messages.timeout, maxRetries et debounce afin d'éviter de nouveaux pics de trafic dans des situations exceptionnelles.Grâce à ces capacités, les plugins peuvent partager en toute sécurité l'état, synchroniser les configurations et planifier les tâches entre différentes instances, répondant ainsi aux exigences de stabilité et de cohérence des scénarios de déploiement en cluster.