Best practices pour la gestion de sessions pour une appli web - Divers - Programmation
Marsh Posté le 05-03-2015 à 23:25:25
Facile : t'as une appli en carton.
Le seul truc à savoir c'est qu'en cas de modifications tu deviendras responsable à la place de l'éditeur. Maintenant si tu veux risque ton boulot c'est ton droit...
Sinon :
1) Pour le multi onglet suffit d'éduquer ses utilisateurs. Par ex un user ouvre 2 fois une fiche client et la modifie différement. Seule la dernière modif est conservée. Bien sûr avec du temps - et éventuellement un chef de projet abruti - rien ne t'empêches de monter une usine à gaz pour palier à ce problème.
Protip : sur l'appli web que je développe y a une fonction "historique" qui permet de voir "qui a modifié, quoi et quand" dans une jolie popup.
2) L'une des best practice c'est que les users ne restent pas bloqués comme des cons... Une autre c'est de comprendre qu'on fait pas des applis web en 2015 comme on faisait des appli lourdes au 20eme siècle...
3) J'ai pas suffisamment d'expérience sur cette problématique là ...
Marsh Posté le 06-03-2015 à 09:52:07
1) j'ai déjà vue une bidouille qui marche pas trop mal, tu crée un code unique (hash de ta page plus variable spécifique id_client et/ou heure) que tu stocke en session et dans un input hidden, lors de la soumission du form tu vérifies que les 2 correspondent, sinon tu avertis l'utilisateur du dysfonctionnement.
2) j'ai eu un problème un peu similaire de session à conserver, et effectivement j'ai fait un petit script en ajax qui ping le serveur tout les minutes, ce qui rafraichit le cookie de session coté client et réinitialise les 20 minutes coté serveur.
3) pas évident à mettre en place pour toutes les actions de votre aplli, soit faut segmenter les traitements lourds, et toujours via ajax essayer de faire une barre d'avancement, mais ce n'est pas toujours possible, soit ce qui serait sans doute plus malin c'est d'avoir une liste de tache dans une base annexe, avec leur statut ("en cours", "succes", "erreur" ) et ne pas pouvoir relancer une tache déjà en cours...
Marsh Posté le 06-03-2015 à 10:54:28
+1 pour l'appli codée avec les pieds (mais ça, tu t'en étais rendu compte).
Pb 1 :
Perso, je conçois des pages "autonomes" (ie auto-suffisantes). Elles contiennent donc toutes les infos nécessaires pour qu'elles fonctionnent correctement (la session ne contient que des infos ne dépendant pas de la page affichée en cours).
Si la notion d'enchaînement de page est nécessaire (contrainte de précédence, par ex), alors j'utilise un automate à état et chaque page contient un jeton (avec ne certaine validité) ou un hash représentant l'état ou le contexte dans le quel se trouve l'appli soit par rapport à l'utilisateur, soit par rapport à l'ensemble des utilisateurs (dépend de l'action). Si l'appli change d'état parce que l'utilisateur a ouvert plusieurs onglets, le jeton/hash n'est plus valide pour les anciens onglets du coup, l'appli refuse de faire l'action, pas de risque d'incohérence ou de faire n'importe quoi.
Pb n°2 :
Pour la gestion des expirations de session, ça se gère soit via le langage (ex, en php, ça se gère tout seul) soit en BD : dans ce cas, on stocke le timestamp de la dernière action de l'utilisateur et dans le cron, y'a une tache périodique qui vérifie si le temps écoulé entre la date de dernière action et la date courante est > au timeout prévu. Si oui, il supprime la session dans la BD et ça déconnecte l'utilisateur.
Pb n°3 :
1) pour les taches identifiées lourdes, l'appli doit vérifier en fonction des droits de l'utilisateur s'il est autorisé à lancer ce genre de tache en dehors des heures prévues. Si c'est pas le cas, elle refuse l'action. J'ai implémenté ce genre de choses dans mon appli Astres (cf ma signature) pour des requêtes de stats de profils persos qui moulinent sévères (genre plusieurs minutes). Genre l'admin peut outrepasser les heures allouées si y'a vraiment une urgence mais d'autres profils moins élevés ne peuvent pas.
2) Pour chaque session, l'appli doit incrémenter un compteur en BD pour chaque type de tache. Elle le positionne à 1 en début d'exécution et le remettre à 0 à la fin. Tant que ce compteur n'est pas revenu à 0, un même utilisateur ne peut pas lancer la même tache. On peut aussi mettre ce compteur en commun avec tous les utilisateurs si la tache ne peut être parallélisée avec une même tache d'un autre utilisateur.
3) Analyser pourquoi les requêtes en BD rament autant. A moins que ça soit des taches de types rapport/stats, y'a pas de raison que ça mouline plusieurs minutes. Et même dans ce cas, voir si y'a pas moyen d'optimiser les requêtes (des fois, ça peut juste être des tables mal indexées). Ca peut être aussi la conf du SGBD à optimiser. Perso, j'ai divisé par 2 à 3 le temps d'exé de grosses requêtes d'Astres en tunant le fichier de conf de Mysql (en particulier, en augmentant la ram allouée pour des tables temporaires, le nb de tables ouvertes, et tout un tas de caches (pour le order by, pour les requêtes déjà exécutées...).
Marsh Posté le 06-03-2015 à 17:01:24
Plein de reponses! Merci! Et re alerte pave
scvo0ne a écrit : Le seul truc à savoir c'est qu'en cas de modifications tu deviendras responsable à la place de l'éditeur. Maintenant si tu veux risque ton boulot c'est ton droit... |
On est d'accord qu'on (mon equipe) ne peut pas toucher a tout ca, je cherche seulement a montrer a l'editeur qu'il existe bel et bien des solutions vu que pour le moment leur position c'est "on n'y peut rien".
Sinon :
scvo0ne a écrit : 1) Pour le multi onglet suffit d'éduquer ses utilisateurs.. |
Ca a ete evidemment la reponse de l'editeur, et ca fait 4 ans que c'est marque en rouge gras plusieurs fois dans la doc pour les utilisateurs et que le formateur le repete x fois pendant les sessions. Mais ca ne suffit pas, les utilisateurs etant ce qu'ils sont: l'ennemi numero 1. S'ils peuvent faire quelque chose, ils le feront, c'est comme ca. Et le probleme c'est que deux mois plus tard quand les donnees maintenant pourries bloquent un traitement sur des trucs qui ont atteint la date limite, on peut pas juste dire "Ha ben non on avait prevenu de pas faire du multi-onglets! Dommage pour vous, demerdez vous maintenant.". Ben non, faut aller mettre les mains dans le camboui directement en prod pour reparer tout ca - avec les N+x en mode gueulante sur le dos, un risque de faire foirer autre chose si l'analyse du probleme n'est pas bien faite, une perte de temps sur les autres trucs qu'on est en train de faire, etc.. A choisir, je prefererais largement controler le multi onglets - surtout que les exemples de Mechkurt et Rufo pour gerer ca c'est loin d'etre des usines a gaz.
scvo0ne a écrit : Protip : sur l'appli web que je développe y a une fonction "historique" qui permet de voir "qui a modifié, quoi et quand" dans une jolie popup. |
Voir au-dessus, ca sert pas vraiment a grand-chose. On log deja quasiment TOUT ce qui se passe vu qu'on est soumis a des audits reguliers par le regulateur (secteur bancaire) et que ne pas loguer c'est la garantie de se prendre une grosse amende dans le meilleur des cas et retirer la license bancaire dans le pire. Sauf que comme je disais au-dessus, ca me fait une belle jambe de savoir que c'est la faute de Robert si je suis en train de me faire souffler dans les bronches; je prefererais largement ne PAS donner l'option a Robert de pouvoir bousiller les donnees, tout le monde s'en porterait beaucoup mieux.
scvo0ne a écrit : 2) L'une des best practice c'est que les users ne restent pas bloqués comme des cons... Une autre c'est de comprendre qu'on fait pas des applis web en 2015 comme on faisait des appli lourdes au 20eme siècle... |
Ah ca. Mais bon tu te doutes bien que c'est pas en disant ca au fournisseur qu'il va me regler les problemes
mechkurt a écrit : 1) j'ai déjà vue une bidouille qui marche pas trop mal, tu crée un code unique (hash de ta page plus variable spécifique id_client et/ou heure) que tu stocke en session et dans un input hidden, lors de la soumission du form tu vérifies que les 2 correspondent, sinon tu avertis l'utilisateur du dysfonctionnement. |
Le pire etant qu'ils ont deja un genre de hash "session" en place qu'ils mettent dans tous les liens intra-appli pour des raisons de securite, donc ca serait pas vraiment la mer a boire d'etendre ca un peu.
mechkurt a écrit : 2) j'ai eu un problème un peu similaire de session à conserver, et effectivement j'ai fait un petit script en ajax qui ping le serveur tout les minutes, ce qui rafraichit le cookie de session coté client et réinitialise les 20 minutes coté serveur. |
Ouaip j'avais fait ca aussi une fois pour detecter les "fins de sessions" d'une applet Java qui passait son temps a planter en laissant les utilisateurs enfermes dehors (encore un autre editeur qui maitrisait son sujet )
mechkurt a écrit : 3) pas évident à mettre en place pour toutes les actions de votre aplli, soit faut segmenter les traitements lourds, et toujours via ajax essayer de faire une barre d'avancement, mais ce n'est pas toujours possible, soit ce qui serait sans doute plus malin c'est d'avoir une liste de tache dans une base annexe, avec leur statut ("en cours", "succes", "erreur" ) et ne pas pouvoir relancer une tache déjà en cours... |
Les traitements lourds... C'est toute une histoire, on fait deja notre possible. J'aime bien l'idee de la barre d'avancement mais j'estime que ca va etre beaucoup trop haut pour l'editeur reste un vrai "gestionnaire de taches" qui supervise ce que fait un utilisateur et agit en consequence qui n'a pas l'air trop gros a mettre en place.
rufo a écrit : |
Tes deux options marcheraient mais l'enchainement n'a pas vraiment d'importance et celle-la m'a l'air vraiment facile a mettre en place.
rufo a écrit : Pb n°2 : |
Nan tu as mal saisi le probleme. Le timeout session marche "bien" (je mets des guillements parce que j'ai quand meme vu des sessions qui ne se terminaient jamais mais en general c'est bon). Le probleme c'est quand l'utilisateur ferme l'onglet directement sans utiliser le lien "deconnexion" avant. Puis il s'apercoit qu'il a oublie de faire un truc, rouvre le navigateur et essaie de se reconnecter, sauf qu'il a deja une session ouverte sur le serveur (celle du navigateur ferme, qu'il ne pourra donc jamais recuperer), que son essai de connexion est vu comme une seconde session differente de la premiere, et donc a cause de la politique maison de session unique, il se fait refuser sa deuxieme session et doit attendre 30 minutes que la premiere fasse son timeout.
rufo a écrit : |
Malheureusement, ce n'est pas possible pour moi. Le post est deja long donc je vais faire court: j'ai deja fait ce que je pouvais de ce cote-la, mais il y a trop de choses hors de ma petite sphere d'influence.
rufo a écrit : |
rufo a écrit : |
La aussi je vais essayer de pas faire trop long. On cumule l'appli en mode prototype, le MDD douteux et un DBA totalement inutile. J'ai deja abattu un boulot enorme, reecrit des dizaines et des dizaines de requetes et de vues, remanie des tables, rajoute des indexs, modifie des traitements... On est passe de "quasiment inutilisable" a un truc a peu pres stable tant qu'il n'y a pas de batch en parallele. Sauf que les batchs ne dependent pas de moi, sont mal branles et surtout s'executent plusieurs jours non-stop (jour et nuit) en debut de mois. J'ai essaye de proposer des trucs pour ameliorer tout ca (et en particulier bouger certaines parties au jour le jour histoire d'utiliser plus la plage de batch journaliere qui est sous-utilisee, et ainsi de limiter le temps d'execution en debut de mois), mais ceux qui pilotent les batchs ont pris ca pour eux et m'ont envoye paitre.
Enfin bref, merci beaucoup, grace a vous j'ai quelques bonnes options a suggerer et rien qui n'ait l'air bien complique au final.
Vu que je vais quitter le projet, ca va surtout etre a mon remplacant de s'occuper de ca. Mais le projet que je rejoins se base sur le meme produit (une version plus recente mais apres discussion avec un de leur consultants, il pense que rien n'a change pour les trois problemes evoques) sauf qu'il n'est pas encore en place du tout et que maintenant que je sais tout ca, je les attends au tournant pendant la phase de tests
Marsh Posté le 07-03-2015 à 11:29:02
PB 1:
ne devrait pas exister, je plussoie la méthode de Rufo.
PB 2:
Si c'est réellement critique, pourquoi ne pas faire une page hors session qui autorise moyennant par exemple un couple login/mdp une déconnexion de la session en cours. Ca ne représent pas un trou de sécurité (au pire l'utilisateur se fait déconnecter)...
Et si la sécu est réellement un point si important pourquoi pas rajouter un envoyer mail par dessus pour prévenir l'utilisateur qu'il a été déco (pour être sur qu'il s'assure lui même que la déco était de sa volonté, et non pas quelqu'un qui le déco pour tenter de l'usurper).
EDIT: tu peux automatiser une déconnexion aussi sur la fermeture de session du poste du mec...
PB 3:
une BDD temporaire qui -par exemple, ca n'est pas assez détaillée- génère un MD5/hash de l'id de session + quelques données clefs- et une fois le thread fini, release dans la BDD La ligne, ainsi un nouveau thread n'a qu'a aller dans la BDD pour savoir s'il y a déjà une action en cours sur ce même jeu de données, et si c'est le cas un message "action déjà en cours, veuillez patienter".
Malheureusement d'après ce que tu dis ça pue un framework genre Spring ou Struts mal configuré dès le départ, et ça doit
être la raison pour laquelle ils sont frileux: tu touches pas facilement à la session une fois en place sur ces systèmes
=> Vu ce que tu nous décrit, soyons clair, ça n'est pas la faute de l'utilisateur hein -et la solution qui consiste à "éduquer l'utilisateur" est a mon sens pas réellement un gage de qualité du fournisseur-, déjà une appli qui prend plusieurs minute, surtout sur du web (avec donc plusieurs users en même temps), ca le fait pas du tout, mais admettons, ya ptete réellement un truc qui nécessite plusieurs minutes. Mais que le système ne sache pas s'il a déjà lancé l'action ya même pas 5 min est un réel problème, qu'il ne sache pas gérer plusieurs onglets sans perdre la trace, là encore est un réel soucis, et pour la sécurité, et pour la traçabilité...
Marsh Posté le 07-03-2015 à 12:21:54
Des batchs qui prennent plusieurs jours d'exécution
A ce tarif là, est-ce qu'il ne vaudrait pas mieux les exécuter sur une BD répliquée ? Comme ça, ça répartit la charge du SGBD et ralentit pas les users sur al BD de prod utilisée par l'appli web.
Et c'est clair qu'éduquer les users pour pallier un bug de l'appli, c'est vraiment pas top comme solution, à réserver en dernier recourt quand on a épuisé toutes les solutions avant. Mais faire ça juste pour pallier l'incompétence de l'éditeur, là, ça craint
Marsh Posté le 07-03-2015 à 22:35:25
Devil'sTiger a écrit : Spring |
En plein dans le mille.
rufo a écrit : Des batchs qui prennent plusieurs jours d'exécution |
4-5 jours en moyenne maintenant, avec mention speciale "on balance des trucs en prod sans tester" qui nous a valu un beau 18 jours en Fevrier. C'est pour ca que mes questions tombent maintenant, avec presque 3 semaines d'appli qui rame a fond et de donnees qui petent en prod, j'ai eu bien le temps d'isoler ce qui posait probleme
Encore une fois, je precise que les batchs, je n'y peux rien! Le gars qui les a concus et mis en place a deux Phds, un en "rocket science" (ca s'invente pas ca ) et un en stats. Sauf qu'en vrai il est plutot genre ca:
D'ailleurs il l'a meme deja faite en vrai lors d'un diner corporate. Mais il est completement intouchable (le biz le considere comme un cerveau sur pattes a cause des deux Phds), et completement ferme a toute remarque ou critique. Et malheureusement niveau IT et gestion de projet c'est pas loin d'etre une grosse buse. C'est une des raisons pour laquelle je me barre d'ailleurs.
Pour la BD repliquee c'est une bonne idee, d'ailleurs mon chef l'avait defendue a un moment donne, mais Mr Rocket Scientist n'a pas apprecie qu'on remette ses resultats en cause et a declare ca "inutile".
Marsh Posté le 08-03-2015 à 18:57:09
Je n'ose proposer du NoSQL comme solution si déjà une BD répliquée, ça passe pas
Marsh Posté le 09-03-2015 à 10:10:43
lasnoufle a écrit : |
Putain mais ces profils là c'est vraiment les pires
Fais-leur lire cette histoire là au business : https://www.simple-talk.com/opinion [...] bad-carma/ , ça va ptet leur faire ouvrir les yeux sur leur "génie"
Marsh Posté le 05-03-2015 à 21:59:26
Salut et alerte pave.
L'appli web (intranet) sur laquelle je bosse au boulot (fournie par un editeur) a de gros problemes au niveau de la gestion des sessions. Evidemment c'est fait dans le code source et c'est pas quelque chose qu'on a le droit de bidouiller nous-meme, et l'editeur est clairement reticent a nous corriger ca. Il a deja fallu qu'on leur mette le nez dans le caca avant qu'ils reconnaissent que leur code est pourri, et maintenant ils jugent ca "trop complique" a faire.
En y reflechissant, leurs problemes sont probablement relativement classiques pour une appli web, donc je me demandais si les specialistes HFRs pouvaient me dire comment c'est gere habituellement chez les fournisseurs dignes de ce nom.
Probleme 1: le multi-onglets. A chaque appel au serveur, la session stocke ou rafraichit des variables en memoire. Cote utilisateur, on ouvre joyeusement plusieurs onglets sous la meme session parce que c'est plus pratique; cote serveur, les variables stockees correspondent au dernier appel de page. Du coup, les variables ne "correspondent" plus qu'au dernier onglet ouvert, mais les utilisateurs reviennent sur un "vieil" onglet et lancent une action depuis cet onglet. L'action est donc lancee avec des variables de session qui ne correspondent plus a ce que l'utilisateur a a l'ecran a ce moment-la. Le serveur n'y voit que du feu; dans le meilleur des cas, les appels internes deviennent assez incoherents pour renvoyer une erreur, et quand on n'est pas chanceux, ca bousille des donnees en base sans rien dire.
C'est quoi les "best practices" pour ca? Du code JS pour detecter et empecher le multi onglet? Un "numero de page" affecte a chaque page et le serveur qui n'autorise que les actions venant de la derniere page qu'il a envoye? Stocker toutes les variables pour chaque "numero de page" et s'en servir de maniere appropriee jusqu'a que le serveur sache que cette page est definitivement fermee et ne pourra plus generer d'action?
Probleme 2: la session unique. L'appli est tres critique au niveau des donnees et il y a un tres fort controle sur les acces. Parmi d'autres trucs, les utilisateurs ne sont autorises qu'a avoir une seule session a la fois. Sauf que s'ils oublient de se deconnecter et ferment directement l'onglet/le navigateur, ben c'est dans leur cul: le serveur ne ferme pas la session et les utilisateurs ne peuvent plus se reconnecter vu qu'ils ont deja une session ouverte. De plus, la meme chose arrive parfois quand l'appli envoie un utilisateur dans les cordes (genre une action qui prend trop de temps, je sais pas trop comment l'editeur s'est demerde mais l'utilisateur se prend un "timeout" et est ejecte de l'appli au bout de 5 minutes, alors que sa session est encore en vie cote serveur avec un timeout de 30 minutes).
C'est quoi les "best practices" pour ca? Du code JS pour detecter les fermetures d'onglet/navigateur et fermer la session correctement? Quid des cas de plantage? Peut-etre un ping regulier du serveur depuis le navigateur et fermeture des sessions cote serveur quand le ping s'arrete?
Probleme 3: les actions lancees en parallele. En gros, quand un utilisateur clique sur un bouton pour lancer une action, le serveur cree une thread, qui choppe une session DB dans le pool, et commence a faire sa popote. Si l'utilisateur decide d'aller faire autre chose dans l'appli avant que son action ne finisse, le thread va continuer son action et la mener a bien quoi qu'il arrive. Jusque la c'est plutot normal (?), sauf que ca genere moults problemes du genre:
- l'action prend 3 plombes (ca arrive pour certains trucs "gourmands", ou quand l'equipe offshore fait joujou avec le serveur batch en dehors des heures alouees) , l'utilisateur s'impatiente et la relance. Aucun controle cote serveur, donc maintenant il y a deux threads qui tournent en parallele pour faire la meme chose. Selon l'action et le contexte, ca peut provoquer un fail d'une des deux actions, habituellement la deuxieme lancee (le meilleur cas meme si ca mene a des tickets "ca marche pas", au moins il n'y a pas de degat sur les donnees), ou bien on peut finir avec des donnees corrompues, et parfois on a des sessions DB qui se deadlockent (mais pas detecte par la DB, donc sessions "perdues", avec parfois accumulation jusqu'a epuisement de la pool de sessions DB (vu que l'utilisateur va continuer a relancer son action jusqu'a ce qu'elle finisse: jamais a cause du deadlock) et panique des utilisateurs qui en decoule)
- l'utilisateur se fait gicler (voir plus haut), pense que son action n'a pas marche, se reconnecte et relance l'action -> meme degats qu'au point 1
C'est quoi les "best practices" pour ca? Le serveur qui empeche toute action a un utilisateur tant que celle d'avant n'a pas fini? Ou bien qui detruit/rollback les threads pour l'utilisateur en cours a chaque reception d'une nouvelle action? Autre chose?
Notez bien que des qu'on en voit la possibilite, on modifie ce a quoi on a access (le contenu de certaines actions, le modele de donnees, etc.) pour eviter au maximum les impacts de ces 3 problemes. Mais evidemment, faut rajouter que toute l'appli est a la mesure de la gestion des sessions: c'est bon pour un prototype en ecole d'info avec 100 lignes en base et 1 utilisateur a la fois mais ca n'est absolument pas mature. Le modele de donnees est relativement mauvais (meme pas NF, certaines contraintes ne sont pas verifiees a cause de choix de tables douteux, etc.), certaines actions fournies par l'editeur (codees en Java) sont tellement lentes ou hasardeuses a utiliser qu'on les a remplacees par nos propres procedures stockees en base, etc.
Bref.
A+
---------------
C'était vraiment très intéressant.