Optimisation des temps d'affichage de liste

Bonjour,

sur l’application des gestion des ressources, j’ai ce message qui bloque l’affichage des agendas :

Service error
    java.lang.NullPointerException
     at com.simplicite.util.GrantCore.getVisibility(GrantCore.java:2263)
     at com.simplicite.util.ObjectDB.isActionEnable(ObjectDB.java:1655)
     at com.simplicite.util.ScriptedObjectDB.isActionEnable(ScriptedObjectDB.java:786)
     at com.simplicite.util.ObjectContext.enable(ObjectContext.java:486)
     at com.simplicite.util.ObjectContext.apply(ObjectContext.java:434)
     at com.simplicite.webapp.ObjectContextWeb.apply(ObjectContextWeb.java:312)
     at com.simplicite.util.tools.JSONTool.initWebService(JSONTool.java:1012)
     at com.simplicite.util.tools.JSONTool.rowMetaDataToJson(JSONTool.java:1650)
     at com.simplicite.util.tools.JSONTool.listToJson(JSONTool.java:2237)
     at com.simplicite.util.tools.JSONTool.list(JSONTool.java:2595)
     at com.simplicite.webapp.tools.JSONServletTool.search(JSONServletTool.java:710)
     at com.simplicite.webapp.ObjectJson.search(ObjectJson.java:219)
     at com.simplicite.webapp.ObjectJson.search(ObjectJson.java:195)
     at com.simplicite.webapp.tools.JSONServletTool.businessObjectService(JSONServletTool.java:540)
     at com.simplicite.webapp.servlets.AbstractJSONServlet.service(AbstractJSONServlet.java:68)
     at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
     at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
     at com.simplicite.webapp.filters.RewriteFilter.doFilter(RewriteFilter.java:77)
     at com.simplicite.webapp.filters.AbstractFilter.doFilter(AbstractFilter.java:37)
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
     at com.simplicite.webapp.filters.AuthMethodFilter.doFilter(AuthMethodFilter.java:136)
     at com.simplicite.webapp.filters.AbstractFilter.doFilter(AbstractFilter.java:37)
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
     at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
     at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
     at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
     at com.simplicite.tomcat.valves.APISessionValve.invoke(APISessionValve.java:187)
     at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
     at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
     at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
     at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
     at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
     at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)
     at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
     at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
     at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)
     at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
     at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
     at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
     at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
     at java.base/java.lang.Thread.run(Thread.java:830)

et aussi ce message de façon aléatoire :

2020-05-15 10:51:49,061 ERROR [com.simplicite.util.engine.ObjectManager] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.ObjectManager|makeFrom||Evénement: Configuration error SocialPost: unable to find the parent field of pstUserId.usr_image_id

2020-05-15 10:51:49,061 ERROR [com.simplicite.util.engine.ObjectManager] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.ObjectManager|makeFrom||Evénement: Configuration error SocialPost: unable to find the parent field of pstUserId.usr_email

2020-05-15 10:51:49,061 ERROR [com.simplicite.util.engine.ObjectManager] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.ObjectManager|makeFrom||Evénement: Configuration error SocialPost: unable to find the parent field of pstUserId.usr_last_name

2020-05-15 10:51:49,061 ERROR [com.simplicite.util.engine.ObjectManager] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.ObjectManager|makeFrom||Evénement: Configuration error SocialPost: unable to find the parent field of pstUserId.usr_first_name

2020-05-15 10:51:49,060 ERROR [com.simplicite.util.engine.ObjectManager] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.ObjectManager|makeFrom||Evénement: Configuration error SocialPost: unable to find the parent field of pstUserId.usr_login

2020-05-15 10:51:48,952 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.CoreCache|getField||Evénement: Language FRA not found for field rlg_object

2020-05-15 10:51:48,947 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.CoreCache|getField||Evénement: Language FRA not found for field mdi_target

2020-05-15 10:51:48,944 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.CoreCache|getField||Evénement: Language FRA not found for field ALMTestCaseObject

2020-05-15 10:51:48,941 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.CoreCache|getField||Evénement: Language FRA not found for field ALMImplObject

2020-05-15 10:51:48,914 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.CoreCache|getField||Evénement: Language FRA not found for field pstObject

2020-05-15 10:51:48,904 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.CoreCache|getField||Evénement: Language FRA not found for field pstLevel

2020-05-15 10:51:48,900 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.CoreCache|getField||Evénement: Language FRA not found for field pstStatus

2020-05-15 10:51:48,891 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.CoreCache|getField||Evénement: Language FRA not found for field pstFollowersOnly

2020-05-15 10:51:48,887 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.CoreCache|getField||Evénement: Language FRA not found for field pstMessage

2020-05-15 10:51:48,882 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.CoreCache|getField||Evénement: Language FRA not found for field pstDate

2020-05-15 10:51:48,879 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.CoreCache|getField||Evénement: Language FRA not found for field usr_image_id

2020-05-15 10:51:48,876 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.CoreCache|getField||Evénement: Language FRA not found for field usr_email

2020-05-15 10:51:48,867 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.CoreCache|getField||Evénement: Language FRA not found for field usr_last_name

2020-05-15 10:51:48,858 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.CoreCache|getField||Evénement: Language FRA not found for field usr_first_name

2020-05-15 10:51:48,855 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.CoreCache|getField||Evénement: Language FRA not found for field usr_login

2020-05-15 10:51:48,852 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.CoreCache|getField||Evénement: Language FRA not found for field pstUserId

2020-05-15 10:51:48,845 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.CoreCache|getField||Evénement: Language FRA not found for field updated_by

2020-05-15 10:51:48,843 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.CoreCache|getField||Evénement: Language FRA not found for field updated_dt

2020-05-15 10:51:48,839 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.CoreCache|getField||Evénement: Language FRA not found for field created_by

2020-05-15 10:51:48,837 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.CoreCache|getField||Evénement: Language FRA not found for field created_dt

2020-05-15 10:51:48,833 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.CoreCache|getField||Evénement: Language FRA not found for field row_id

2020-05-15 10:51:48,827 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|https://Prod-sim-3:10038/gdr|/gdr|ERROR|system|com.simplicite.util.engine.CoreCache|getField||Evénement: Language FRA not found for field row_id

Un stack trace sans context n’est pas exploitable.

Le premier message indique un pointeur null dans les visibilités de l’objet (hook isActionEnable par défaut). Cette HashMap n’est jamais null, ni le nom d’un l’objet correctement instancié. Ca sent un problème de clear-cache, ou de cas particulier, ou d’instance cassée.

L’autre trace est une erreur connue sans incidence, certains objets continuent de travailler alors qu’un clear-cache ou démarrage serveur est en cours : il y un problème de paramétrage (en amont de ces traces), Simplicité essaye de le loguer dans un SocialPost (pour audit du designer), mais le cache n’est pas encore prêt… Le problème disparaîtra de lui-même s’il n’y a pas d’erreur de paramétrage.

Avez vous du code sur le isActionEnable ? des fonctions avec visibilités ?

j’ai modifié les agendas : le search fait maintenant appel à des objets plus petits, ne contenant que certains attributs nécessaires à l’affichage en liste. C’est ce que j’avais aussi mis en place sur Karta en V3 pour des pb de performance. Du coup, ça fonctionne, je n’ai plus de blocage ni de message. Et les temps de réponse sont corrects.

Globalement, je remarque que les temps de réponse pour l’affichage d’objets avec beaucoup d’attributs, et des objets liés sont très longs …

est-ce-que vous préconiser de créer des objets plus petits pour les listes ?

En V4, les listes sont déjà optimisées pour ne retourner que les champs visibles en liste, ou en recherche ou présents dans des contraintes (pour appliquer les visibilités dynamiques en fonction de la ligne). Il faut donc déjà essayer de limiter le nombre de champs visibles en liste ou en recherche.

  • Combien d’attributs reste-t-il sur votre objet ?

  • En première analyse en combien temps la liste s’affiche, quelle est la taille du flux obj?action=metadata et obj?action=search dans la console du navigateur :

  • En 2eme analyse : vous pouvez aussi le voir avec le monitoring front (rôle ADMIN ou OPERATOR avec LOG_UI=yes dans les paramètres de l’utilisateur pour afficher l’icone dans le header) pour savoir ce qui prend le plus de temps entre les appels réseau ou l’affichage :

Exemple ici pour une liste simple les call ajax mettent meta+data=13+12 = 25ms, et l’affichage 1+89+2 = 92ms :

Le flux ajax obj/search est verbeux par ligne au niveau des méta-données JSON et s’il n’y a pas d’optimisation GZIP des flux http dans les couches inférieures (tomcat, proxy), les perfs générales s’en ressentent.

En V5, c’est en cours d’amélioration au niveau de la quantité de méta-données remontées par ligne, puis complété côté client pour éviter de répéter 90% du temps la même chose sur chaque attribut (comme le type ou la taille du champ… généralement seule la visibilité, les listes liées peuvent changer).

Cette optimisation est encore en test, on pourra backporter en V4 si c’est concluant = si pas de régression fonctionnelle sur les hooks… et que ça ne déplace pas un gain en temps réseau en perte de temps d’affichage pour reconstruire l’objet “partiellement” reçu.

.

il reste 24 attributs dans mon objet, contre 50 au départ.
13 sont visibles en liste et 12 en recherche.

Taille du flux sur l’objet contenant tous les attributs :

Taille du flux sur l’objet contenant 24 attributs :

ce sont les search qui sont longs. c’est aussi ce que j’ai remarqué sur les autres applications pour lesquelles nous avons des pb de performance

8,57Mo me semble effectivement énorme pour une liste avec 13 colonnes.
Il y a peut être des champs texte long, contenu riches ou des images ?

Quoiqu’il en soit ce sont les listes qui sont volumineuses car répètent trop d’informations redondantes sur chaque ligne au niveau des méta-data.

On va essayer de backporter les optimisation V5 en V4 au plus vite. Car vous ne devriez pas à avoir créer des objets dédiés aux listes pour “50 champs sur un objet dont 13 en liste”.

non, rien de tout ça … ce sont des réservations de ressources … des dates, des libellés. rien de bien méchant.

pour l’application de gestion des stagiaires de la formations professionnelle, je n’ai pas fait d’objet pour la liste. je ne comprends pas pourquoi je n’ai pas plus de remarques sur les lenteurs …

il y a maintenant 27866 stagiaires en base et voilà les temps de réponse :

je n’y étais pas allée depuis longtemps …
l’objet a 113 attributs mais seulement 13 affichés en liste.
sur l’environnement de dev qui a 10590 stagiaires, les temps de réponse sont corrects :

Ca me parait effectivement plus raisonnable en volume transféré, la UI ne ramène toujours qu’une seule page donc les perfs doivent rester stables qq soit la taille de la table (dès lors que la table est bien indexée sur les champs de recherche courante, Simplicité n’indexe par défaut que la clé fonctionnelle et les FK).

Il faudra nous donner la version de simplicité pour cette instance “normale”. Si c’est la même plateforme V4, il faudra aller fouiller dans les données du flux search des “ressources” ce qui pèse lourd dans les 8Mo (même si c’est 770k une fois zippé niveau http, ça prend du temps à dezipper).

Si ce ne sont pas des champs riche/doc, il reste aussi les listes de valeurs qui consomment bcp d’espace en V4.

En V5, c’est le dernier type en cours d’optimisation et ce n’est pas simple car il y a des listes liées et des états qui peuvent varier sur chaque ligne. A priori, on pourra uniquement factoriser les enumérés “simples”.

optimisations pour résoudre les pb de lenteur :

  • j’ai créé des objets Liste ne contenant que les attributs à afficher en liste

  • j’ai créé des objets ListeHistorique pour n’afficher dans les vues que les listes avec les objets avec un statut en cours.

  • les objets listeHistorique sont accessibles via domaine Historique

  • j’ai supprimé les groupBy dans les ListeHistorique

Toutes ces adaptations font que les temps de réponses sont très corrects

Parfait.

De notre côté on a revu certaines optimisations XSS côté front qui prenait beaucoup de temps. En te mettant à jour tu verras surement une différence sur la partie front une fois le flux Ajax reçu.

Le correctif pour limiter les injections de script (via $.append…) depuis un champ de saisie, nous avait obligé à passer par des versions qui éliminent les contenus douteux ($.appendSafe… retire les <script>, les onload onerror…) mais du coup sont très coûteux en temps de parsing.

Ca n’avait pas de sens de le faire partout, notamment au niveau de label simple où un $.text fait très bien le job de ne rien exécuter (1ms pour afficher un label versus 30ms en moyenne).

Le temps de rendering d’une liste est divisée par deux.
Ca redevient lent si l’objet a des champs riches/HTML qu’il faut passer à la moulinette Safe/XSS.