OUVERTURE
Mettre en cache, ou ne pas mettre en cache, c’est la question :
Si c’est l’utilisateur dans l’esprit de souffrir
Les échasses et les rangées d’attente scandaleuse,
Ou de prendre les armes contre une mer de rangées
Et en s’opposant à les cacher. Mourir, dormir; ou pas.
VUE D’ENSEMBLE
Je suis fasciné par les caches depuis le milieu des années 2000 lorsque je travaillais sur un grand projet d’intergiciel qui a subi une UX insupportable en raison d’un pilote ODBC très lent. C’était bien sûr avant l’avènement des applications cloud. La solution conçue était d’introduire une couche de cache dans l’intergiciel pour se trouver entre l’application cliente et le serveur de base de données. Nous sommes passés du temps de réponse de plusieurs secondes à des dizaines de millisecondes, une amélioration centuple. Le cache utilisé (ehcache); et les intergiciels qui l’utilisent, sont encore utilisés aujourd’hui.
Lorsque je parle de mise en cache, je ne fais pas référence à l’utilisation normale de PXCache utilisé dans les graphiques, mais plutôt au soi-disant mécanisme de mise en cache slot trouvé dans la classe PX. Data.PXDatabase. Si vous parlez à certains développeurs, beaucoup diront: « ne faites jamais cela » ou « que ce n’est pas recommandé ». Je ne suis pas d’accord avec ces affirmations, d’autant plus que le code Acumatica hors de la boîte utilise beaucoup de ces stratégies de mise en cache. C’est encore plus souvent le cas avec l’utilisation du PXSelectorAttribute.
CE QU’IL FAUT METTRE EN CACHE ET CE QU’IL NE FAUT PAS METTRE EN CACHE
Il est important avant de penser à la mise en cache des données, qu’il soit approprié de le faire ou non. Les lignes de données ne sont pas toutes les mêmes. Par conséquent, discutons de ce qu’ils sont et s’ils sont de bons candidats pour être mis en cache. Voici quelques types de données auxquelles nous pourrions penser :
RAISONS DE METTRE EN CACHE
- Les données sont souvent nécessaires et ne changent pas beaucoup
- Un petit sous-ensemble de champs est nécessaire pour toutes les lignes d’une grande table
- Une grande liste de classes (types) sont recherchées dans la liste des assemblages et ne changeront pas après le démarrage du système. Ergo: la liste des PXGraphs ou une liste de processeurs mettant en œuvre une interface particulière
- Pas d’accès facile à un graphique ou trop coûteux pour le faire pour lire les données
- Lorsque plusieurs lectures seraient nécessaires pour trouver une correspondance appropriée (basée sur un mappage multi-champs)
- Lorsque de petits ensembles de données sont nécessaires dans le traitement de millisecondes à haut débit.
CADRE B2B/EDI
Au cours du développement d’un framework B2B/EDI pour l’un de nos clients Acumatica, nous avons fini par trouver de nombreuses zones appropriées qui bénéficieraient de la mise en cache. Le cadre que nous avons développé est utilisé pour synchroniser les données et les documents de sources externes vers Acumatica ou vice versa. Il utilise de nombreuses données de configuration qui, une fois configurées, ne changeront probablement pas avant longtemps. L’approche que nous avons adoptée nous a permis de créer de nombreux petits processeurs de messages / données tous appelés dans une séquence donnée et ces nombreux processeurs sont généralement spécialisés dans la fabrication d’une chose et d’une seule chose, semblable aux chefs dans une cuisine, où l’un est responsable des grillades, l’autre de la sauce, un pour les salades, un pour les pâtisseries, un pour couper la viande, etc. Les processeurs sont sans état et sont installés (à l’aide de la découverte Reflection) lors de la publication de la personnalisation et sont liés à une petite ligne de configuration. Dans le contexte du traitement des messages, nous utilisons également de nombreuses transformations et mécanismes de conversion de données qui sont tous configurables par l’utilisateur.
Compte tenu du volume de transactions et de transformations, nous avions besoin d’un moyen d’appeler ces processeurs / conversions en succession rapide sans encourir le coût des requêtes de base de données. De plus, pour les définitions de modèles de messages sortants, nous devions extraire les différents tableaux et champs utilisés par les graphiques système pour nous permettre de les lire rapidement pour générer un modèle sortant qui est le principal moteur des transactions sortantes.
LE MÉCANISME DE FENTE
Le mécanisme de mise en cache dans ce cas est celui trouvé dans le PX. Data.PXDatabase , classe. Ce qui est si spécial à propos du mécanisme de mise en cache des fentes:
- Stocke vos données dans des dictionnaires de thread sécurisés
- Srèmètre les données par votre clé définie afin que vous puissiez restreindre qui accède à vos données mises en cache
- Peut stocker et récupérer des données de manière sélective à l’aide d’un paramètre (une classe/type pour représenter et accéder à un sous-ensemble des données)
- Stocke les données par entreprise (chacune a son propre cache)
- Appelle automatiquement un délégué Prefetch lors du premier accès aux données mises en cache
- Surveille automatiquement les tables dépendantes (que vous configurez) et réinitialise le cache lorsque quelqu’un a mis à jour l’une des tables dépendantes
- Gère automatiquement le mode de cluster (utilisations de tables dépendantes entre les clusters).
Jetons un coup d’œil aux différentes méthodes utilisées dans ce cas particulier dans notre code:
GIST : https://gist.github.com/ste-bel/45a9e58f89054a70a76520137e825322
TABLES IMPLIQUÉES
Dans la section suivante, nous examinerons certains des tableaux impliqués dans la mise en cache du cadre B2B.
LE CODE
Un POCO pour stocker/organiser mes données
First, I create a POCO to store my cached data. Acumatica does not recommend creating constructors in DACs and they are quite heavy in nature. Therefore, I prefer to use my own lightweight POCOs. I also implement IEquatable<> and override GetHashCode() so that my searches are more efficient.
GIST : https://gist.github.com/ste-bel/cd07f0bc9810b11ead1aafa818606765
Une classe d’assistance pour stocker et rechercher des données
Deuxièmement, je crée une classe d’assistance pour simplifier le chargement du code et la recherche des données. Je peux également encapsuler et améliorer mon algorithme de recherche sans déranger les autres codes. Vous pouvez voir ce morceau de code comme un compartiment de données. Vous pouvez également utiliser une hiérarchie d’aides / seaux afin de faire des bulles de recherches et de réduire votre couplage global du code à l’aide de l’aide initiale.
GIST : https://gist.github.com/ste-bel/26088249b9b584fce94af07631c7393c
Le chargeur de données d’emplacement
Le dernier morceau de code que vous créez une classe implifiant IPrefetchable pour lire les données en utilisant les méthodes PXDatabase sans avoir besoin d’un graphique. J’utilise également un dictionnaire pour stocker mes aides / compartiments et subdiviser mes données dans ce cas par une clé telle qu’un ConversionID ou un ClassID.
Dans ma méthode Prefetch , j’efface mon dictionnaire d’aide puis je lis les données et je remplis mon dictionnaire avec toutes les aides.
Ensuite, je fournis des méthodes statiques pour récupérer les aides par leur ID et j’utilise l’aide pour rechercher des données.
GIST: https://gist.github.com/ste-bel/c3d8a380c88d5ff71fbc6102d4d9539a
L’utilisation du chargeur de données
Pour utiliser le chargeur de données, il vous suffit de parler à votre chargeur pour obtenir l’aide, puis vous utilisez l’aide pour convertir les données.
GIST : https://gist.github.com/ste-bel/96f6b77a93c14ed8cd70db21b4bfab92
CONCLUSION
Au début, il peut sembler beaucoup de travail pour mettre en cache et récupérer des données. Cependant, une fois que vous vous y êtes habitué, vous pouvez faire ce type de code en une demi-heure et l’amélioration de la vitesse est considérable. En utilisant les classes Yaql (Encore une autre langue de requête), vous pouvez également lire plus d’une table et utiliser des conditions compliquées.
Voir ce GIST pour plus de détails: https://gist.github.com/ste-bel/a27c51dd4234d88c7d098b161b3d9386
Je vous souhaite bonne chance dans vos efforts de mise en cache et un codage heureux!