Version minimum | Date de mise à jour |
---|---|
5.4 | 18/05/2021 |
Résumé
Nous avons identifié qu'un important problème de performance était lié au filtrage des tiers mis en place dans la version Winter'20(5.3). C'est pourquoi nous avons revu notre moyen de filtrer l'accès aux tiers.
Comment ça fonctionnait avant
Le script Global.OnLogin
(à chaque fois que l'on fait F5) exécutait la fonction suivante getCustomerGlobalSyncActionAsync()
.
Cette fonction (obsolète) exécutait le datasource syncAction.customer.sql
pour alimenter la variable de session syncAction.customer.Global
avec l'ensemble des tiers accessibles par l'utilisateur connecté.
Note : syncAction.customer.sql est une copie adaptée de la requête de synchro de la table sw_data_customer
(liste des tiers).
Avec un nombre important de tiers accessibles (>50 000) nous avions les problèmes suivants:
- les requêtes filtrées avec la variable
syncAction.customer.Global
qui intègrent la totalité du contenu de la variable, et donc elles deviennent très longues - le filtrage était effectué comme suit
[..] AND c.customer_ID IN ({{syncAction.customer.Global}})
et il est déconseillé d'utiliser l'opérateur IN avec un grand volume (pour des raisons de performance)
Comment ça fonctionne maintenant
Après une étroite collaboration avec l'équipe Divalto One, nous décidons d'appliquer une solution de filtrage en stockant la liste des tiers accessible par compte d'accès (device). Cette solution correspond à une fonctionnalité du Framework SFK qui devrait être disponible au prochain cycle (Winter'21).
Le Framework SFK va permettre en ajoutant de la sémantique aux requêtes de s'affranchir de jointure permettant le filtrage de données. Cette fonctionnalité va aussi permettre de gérer le multi-société avec le Framework.
Normalement prévue de la forme suivante
SELECT c.name FROM {{TABLE(customer, c)}}
Toutefois cette solution n'étant pas disponible pour notre correction, nous avons appliqué une correction similaire.
Au lieu d'avoir le code suivant :
INNER JOIN sw_data_customer AS c ON c.customer_ID = vr.customer_ID INNER JOIN sw_data_customer AS customerFilter ON customerFilter.customer_ID = c.customer_ID AND customerFilter.customer_ID IN ({{syncAction.customer.Global}})
Nous avons maintenant le code suivant :
INNER JOIN sw_data_customer AS c INNER JOIN ( SELECT customer_ID AS c_rowaccess_customer_ID FROM sw_data_customer INNER JOIN sw_sys_rowaccess ON sw_sys_rowaccess.device_ID = {{deviceID}} AND sw_sys_rowaccess.metatable_ID = {{customerMetatableID}} AND sw_sys_rowaccess.rowID = customer_ID ) AS c_rowaccess ON c_rowaccess.c_rowaccess_customer_ID = c.customer_ID ON c.customer_ID = vr.customer_ID
- {{deviceID}} : variable system correspondant au device_ID de l'utilisateur connecté
- {{customerMetatableID}} : variable de session initialisée dans le script Global.onLogin et contenant le metatable_ID correspondant à la table sw_data_customer
Comme dit précédemment nous disposons de la table sw_sys_rowaccess
pour identifier les tiers accessibles par un compte.
Cette table est alimentée avec la fonction setByDatasourceAsync(datasourceName: string, forceUpdate: boolean)
du service $rowAccess
.
- datasourceName : nom du datasource de type rowaccess qui va permettre de lister les éléments (dans notre cas des customer_ID)
- forceUpdate : une option qui permet d'obliger le recalcul, sinon SFK a mis en place un mécanisme horodaté pour éviter de demander un recalcul trop fréquemment
On retrouve cette fonction dans :
- Global.OnLogin avec
forceUpdate
àfalse
(valeur par défaut) pour éviter que F5 lance systématiquement le recalcul des tiers accessibles - customer.new.crudComponent.AfterInsert avec
forceUpdate
àtrue
pour demander un recalcul des tiers accessibles et intégrer le tiers qui vient d'être créé
Attention : la position de la fonction est importante dans le script (il faut avoir l'ajout dans la table sw_data_customeruser avant et il faut mettre tous les SELECT avec un filtrage de tiers après) - customer.id.updateFromSirene.Click avec
forceUpdate
àtrue
lorsque l'on veut mettre à jour les informations d'un tiers à partir de la base Sirene, il y a une création d'un tiers temporaire pour engager une fusion, c'est pour donner l'accès à ce tiers que l'on demande un recalcul
Je suis en version 5.3.0.0.X que dois-je faire
Il y a 4 cas possibles, veuillez identifier le cas qui concerne votre projet.
1. Global.OnLogin n'est pas surchargé et aucune surcharge contenant syncAction.customer.Global
Rien à faire, vous n'avez pas d'erreur liée au filtrage des tiers.
2. Global.OnLogin n'est pas surchargé et une ou plusieurs surcharge(s) contenant syncAction.customer.Global
Correction temporaire juste pour ne plus avoir d'erreur
La correction qui suit va vous permettre de faire cohabiter les 2 mécanismes, mais il ne s'agit que d'une correction temporaire.
Surcharger le fichier .\DeviceTypes\Default\#scriptLibrary\entity\onLoginOverload
.
Il faut modifier le contenu de la fonction afterAsync
comme suit :
async afterAsync() { const helperCustomer = await $library.getLibraryAsync('customer'); await helperCustomer.getCustomerGlobalSyncActionAsync(); return; }
Correction finale
Retirer la correction temporaire.
Il faut reprendre tous les fichiers surchargés contenant syncAction.customer.Global
et utiliser la jointure avec la table sw_sys_rowaccess
.
3. Global.OnLogin est surchargé et aucune surcharge contenant syncAction.customer.Global
Modifier le script Global.OnLogin.
Remplacer
const helperCustomer = await $library.getLibraryAsync('customer'); await helperCustomer.getCustomerGlobalSyncActionAsync();
Par
const helperSysMetaTable = await $library.getLibraryAsync('helper.sysMetaTable'); const customerMetatableID = await helperSysMetaTable.getMetatableBySchemaTableAsync('sw_data_customer'); await $session.setAsync('customerMetatableID', customerMetatableID); await $rowAccess.setByDatasourceAsync('customer.rowaccess');
4. Global.OnLogin est surchargé et une ou plusieurs surcharge(s) contenant syncAction.customer.Global
Correction temporaire juste pour ne plus avoir d'erreur
La correction qui suit va vous permettre de faire cohabiter les 2 mécanismes, mais il ne s'agit que d'une correction temporaire.
Modifier le script Global.OnLogin.
Remplacer
const helperCustomer = await $library.getLibraryAsync('customer'); await helperCustomer.getCustomerGlobalSyncActionAsync();
Par
const helperCustomer = await $library.getLibraryAsync('customer'); await helperCustomer.getCustomerGlobalSyncActionAsync(); const helperSysMetaTable = await $library.getLibraryAsync('helper.sysMetaTable'); const customerMetatableID = await helperSysMetaTable.getMetatableBySchemaTableAsync('sw_data_customer'); await $session.setAsync('customerMetatableID', customerMetatableID); await $rowAccess.setByDatasourceAsync('customer.rowaccess');
Correction finale
Modifier le script Global.OnLogin.
Retirer le code suivant
const helperCustomer = await $library.getLibraryAsync('customer'); await helperCustomer.getCustomerGlobalSyncActionAsync();
S'assurer que le script contient bien le code suivant à la place de celui supprimé précédemment
const helperSysMetaTable = await $library.getLibraryAsync('helper.sysMetaTable'); const customerMetatableID = await helperSysMetaTable.getMetatableBySchemaTableAsync('sw_data_customer'); await $session.setAsync('customerMetatableID', customerMetatableID); await $rowAccess.setByDatasourceAsync('customer.rowaccess');
Il faut reprendre tous les fichiers surchargés contenant syncAction.customer.Global
et utiliser la jointure avec la table sw_sys_rowaccess
.