1

Bon, je suis en vacances, mais je suis tracassé par un problème que j'ai laissé en suspens au boulot (oui, je sais, c'est mal, mais bon...) :
J'ai une appli web qui me permet de faire la supervision d'opérations de synchronisation de comptes informatiques (je vous passe le détail, mais en gros je pioche des informations de différentes sources de données, je fais des croisements et des tris, j'en tire des listes d'individus pour lesquels j'exécute des procédures de création de compte, de recherche de comptes existants, de lien entre ces différents comptes, d'adaptation des droits, d'archivage, etc.).
L'opération est relativement longue (l'exécution totale dure 15 minutes pour en gros 700 comptes), mais ça ne me pose pas vraiment de problème (ce qui est le plus coûteux est l'exécution de SQL dans des environnements fermés où je n'ai pas la main sur l'indexation des données et avec des critères sélectifs vraiment tordus ; j'en ai fait mon deuil, et ça reste raisonnable).

Mon souci, c'est que j'ai envie/besoin de pouvoir suivre exactement ce qui se fait pendant l'opération (en particulier, si j'ai un problème avec un compte, je veux le voir immédiatement et pas attendre les 15 minutes, mais ça doit aussi me permettre de voir en direct si quelque chose de plus global échoue).
Je n'utilise pas d'Ajax (c'est peut-être une erreur ici, mais je ne suis pas sûr que ça change vraiment grand chose, en fait), mais une série de document.getElementById('proutprouttagada').innerHTML+=lesinfosenplus; qui sont envoyés au navigateur pendant l'oparation une fois que le squelette de la page a été envoyé. En sachant qu'en parallèle, j'alimente en tableau javascript avec toutes les informations dont j'ai besoin sur chaque compte (en gros, à gauche de ma page j'ai la liste des comptes qui ont été traités qui s'agrandit, et à droite j'ai plusieurs divs qui, lorsque je clique sur un compte de la colonne de gauche, récupèrent des infos du tableau qui grandit à chaque itération et les mets en forme).

Au final, c'est EXTRÊMEMENT lent (sur Fx sous linux, ça me prends plus de 3Go de RAM et ça m'assassine un Xeon 4 coeurs ; sous Windows, c'est étrangement beaucoup moins catastrophique et ça reste assez raisonnable même sur un Atom, mais ça n'est quand même pas "vendable" : plus le processus avance et moins c'est réactif... or idéalement ça devrait pouvoir traiter des populations de 30 à 40000 individus pour que je puisse diffuser mon outil à d'autres établissements plus gros) et la page générée est énorme (16Mo de code source une fois le traitement fini).

Brayf : si quelqu'un a des idées, même d'ordre général et même si ça doit me faire tout changer au niveau fonctionnement (mais en gardant l'idée d'une mise à jour de l'affichage pendant l'exécution du processus), je suis preneur. En sachant (histoire de faire taire le quelque-un (cheeky) qui pourrait arguer que je demande des infos pour le travail que j'envisage depuis toujours d'ouvrir le code à la communauté dès que tout sera stabilisé).
avatar

2

J'ai lu un peu rapidement, et je ne suis pas sûr : qu'est-ce qui génère lesinfosenplus ? Tout est en JS, ou tu vas piocher du contenu via une requête sur un serveur ? (tu dis que tu fais pas d'ajax ?)

3

tu utilise jquery avec des .live pour ajouter les event de click sur un compte ? si c'est le cas utilise plutôt un .on sur ton div contenant les compte et si c'est encore trop lent met manuellement les event sur chaque compte lors de leurs insertion

si t'est chaud pour tout changer tu peu tester node.js qui fait vraiment du temps reel

genre faire un chat :

partie serveur
var io = require('socket.io').listen(3000);

io.sockets.on('connection', function (socket) {
  socket.emit('message', {nick:"system",msg:"hello"} );
  socket.on('message', function (data) {
    socket.broadcast.emit('message', data );
  });
});


partie client :
<html> 
	<head> 
		<script src="http://code.jquery.com/jquery-latest.min.js"></script> 
		<script src="http://node.machin.fr:3000/socket.io/socket.io.js"></script> 
		<script> 
			var socket = io.connect('http://node.machin.fr:3000'); 
 
			$(document).ready(function() 
			{	socket.on('message',function(data) 
				{	console.log("message get : "+data.nick+" : "+data.msg); 
					$("#chat").append("<div><i>"+data.nick+"</i><br>"+data.msg+"</div>"); 
				}); 
 
				$("#submit").click(function() 
				{	var nick = $("#nick").val(); 
					var msg = $("#msg").val(); 
					socket.emit("message",{nick:nick,msg:msg}); 
				}); 
			}); 
		</script> 
	</head> 
	<body> 
		<div id="chat"></div> 
		<input type="text" id="nick" value="nick"/> 
		<textarea id="msg">message</textarea> 
		<input type="submit" id="submit" value="send"/> 
	</body> 
</html>


la c'est avec socket.io mais une implémentation de jquery existe qui depuis une requête jquery sur le serveur affecte le client de manière transparente
tu peu aussi voir du coté de dnode
voir même nowjs qui crée un objet partagé entre le client et le serveur
et la le mec il le pécho par le bras et il lui dit '

4

Ah, j'aurais dû préciser que je n'utilise aucun framework ^^ (mais du peu que j'ai creusé, j'ai pas mal accroché avec Prototype, je ne suis donc pas hostile à en utiliser un, à condition que ça soit vraiment rentable).
Pen^2 (./2) :
J'ai lu un peu rapidement, et je ne suis pas sûr : qu'est-ce qui génère lesinfosenplus ? Tout est en JS, ou tu vas piocher du contenu via une requête sur un serveur ? (tu dis que tu fais pas d'ajax ?)
C'est mon script php. En fait, c'est fait assez salement :
- Je commence par charger le layout de la page, qui est en gros juste du xhtml+css statique (avec 2/3 bricoles mineures générées dynamiquement), mais je ne ferme ni la balise body ni la balise html
- Ensuite, je passe au gros du traitement, et c'est là que, dans la foulée, j'envoie lesinfosenplus et tout le toutim en javascript qui va au bon endroit dans ma structure de page initiale. Comme la page se charge au fur et à mesure, je vois tout apparaître progressivement.
- Enfin je ferme mes balises body et html.
avatar

5

(c'est bien ce que je pensais, c'est ignoble tongue
Et même pas garanti de marcher dans tous les cas en fait, par exemple Opera a une option pour n'afficher la page qu'une fois qu'elle a entièrement fini de se charger.)
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

6

(Mais ça marche (mal cheeky) grin)
avatar

7

jquery est juste la pour faire jolis, le vrai truc c'est nodejs qui tourne sur le serveur

à ta place je m'inspirerais de qq chose comme ca :
http://gonzalo123.wordpress.com/2011/05/09/real-time-monitoring-php-applications-with-websockets-and-node-js/

php envois à node son avancement qui le distribue au navigateur




mais bon, ca ne servira pas à grand chose si ce n'est pas cette connections persistante qui fait ramer le cul ^^

c'est lent en permanence ou à l'append sur #proutprouttagada ?
ta un event sur chaque sous bloc de #proutprouttagada ?
éventuellement essayer de mettre celui ci dans un <select> ou un <textarea> plutot qu'un div ? (3go de ram ça fait peur ^^)

tu parle d'un tableau qui s'augmente avec chaque entrée, ta beaucoup d'info dedans ? c'est des chaines ou un objet ?
sauver des références simples et demander au serveur les détail au besoin ne serais pas envisageable ? (ici node pourrais stocker l'objet lui même, voir le partager au client avec nowjs)




edit > après, vu que ton code est censé tourner 15 minutes tu peu certainement te passer de node pour que php discute directement avec le js via websocket
bref un php avec le squelette html+le js, et un php qui fait lui le traitement et envois l'avancement
et la le mec il le pécho par le bras et il lui dit '

8

Mes tableaux sont assez importants, oui, avec pas mal d'infos (des chaînes de texte et de html - dont depuis peu des balises img avec du jpeg inline dedans).
Ca ralentit progressivement. Plus il y a de js à traiter, plus ça rame (ce qui me fait vraiment penser que le problème vient de ma façon d'envoyer l'information au navigateur ; j'ai vraiment l'impression qu'il a du mal avec l'ajout à la volée de contenu html).
Il faudrait que j'anonymise les données qui y sont stockées et que je poste le résultat, pour que vous puissiez voir. Mais comme il y a des données personnelles (y compris photos, noms, prénoms, cycle d'inscription, fonction, mot de passe crypté, etc.), ça risque de me prendre un peu de temps - et je n'ai pas accès à l'instance de test pendant la fermeture de l'établissement.
avatar

9

Mais pourquoi ne pas faire d'Ajax du tout ?

Mine de rien, jquery n'est pas très compliquée si c'est uniquement pour faire des requêtes AJAX simples. Dans tous les cas, faire une page qui se charge en un quart d'heure, c'est franchement moche embarrassed
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

10

Bah parce que je ne pense pas que ça change grand chose au problème, en fait...
Puis j'avoue que comme je suis une grosse feignasse (bon, il n'y a pas que ça, j'ai des condition de développement assez chiantes, donc j'essaye d'optimiser mon efficacité... et comme je suis le seul à utiliser cette partie de l'outil, je me fichais pas mal de la lenteur jusqu'à ce que ça devienne critique et que j'envisage sérieusement d'ouvrir le code), j'utilise exactement le même script pour l'affichage en direct et pour la génération de "logs dynamiques" (concrètement, ça me permet de lancer la même chose que le script avec un cron et php-cli et de le rediriger vers un fichier html ; ensuite, je consulte ce fichier pour voir le résultat... avec de l'Ajax, c'est pas possible, il faut développer deux modes de génération).
Mais bon, oui, il va probablement falloir que je repense tout en Ajax, avec un listeneur permanent (je n'ai jamais fait ça, je n'ai toujours fait que de l'ajax sur des événements particuliers, mais j'imagine que ça se fait aussi simplement, on accroche juste le listeneur au body dans une boucle infinie ? il n'y a pas de problèmes de débordement de mémoire ?)
avatar

11

Pas de framework pour la partie PHP ? tsss
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

12

Nop, tout à l'huile de coude (j'ai eu une très mauvaise expérience de framework aux tout débuts des frameworks : j'ai travaillé avec un en 2002 avec je ne sais plus lequel pour php 4.3, et il a été abandonné au bout d'un an, j'ai dû totalement réécrire l'application quand on a migré les serveurs en 5.0... et c'était beaucoup plus que quelques ajustement cheeky)
avatar

13

À vrai dire, je ne conçois plus faire une appli web (si petite soit-elle) sans passer par un framework, qui va te faire 90% du taf.

Ça demande un peu de temps pour comprendre comment ça fonctionne (genre un ou deux jours), mais au final le gain de temps est vraiment important. N'avoir qu'à écrire son modèle de données (sous forme yaml pour PHP / Symfony, ou directement des classes en Python / Django), et tout le reste qui est fait tout seul ou presque (base de données, la gestion des URL, l'API REST, l'authentification, ...), c'est quand même super pratique.
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

14

Oui, j'avais jeté un oeil sur yaml... faudrait que je profite des vacances pour m'y amuser un peu, tiens...
avatar

15

Si tu fais régulièrement de petites appli web, ça vaut vraiment le coup happy
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

16

(Mais est-ce utile dans le cas présent, où 90% du code est du traitement de donnée issue de bases externes, où l'application n'a pas de modèle de données à proprement parler puisqu'on fait passer la donnée issue de A, B, C vers K, L, M ?)
avatar

17

Nil (./10) :
on accroche juste le listeneur au body dans une boucle infinie ?
ewwwwww, non, je ferais pas ça. Regarde plutôt du côté de la fonction setInterval (http://www.xul.fr/ecmascript/settimeout.php) qui lancerait une petite requête AJAX pour récupérer l'avancement.

Sinon, je pense que ce qui prend du temps et de la mémoire est la concaténation elle même (innerHTML+= )
Essaie-donc de voir avec ce qu'ils racontent là bas : http://jsperf.com/innerhtml-vs-append
(je n'ai jamais testé, c'est juste une piste)

18

Pen^2 (./17) :
ewwwwww, non, je ferais pas ça. Regarde plutôt du côté de la fonction setInterval (http://www.xul.fr/ecmascript/settimeout.php) qui lancerait une petite requête AJAX pour récupérer l'avancement.
top (en plus je crois que je l'utilise déjà quelque part triso)

Et merci beaucoup pour la piste !
avatar

19

Je pense qu'un appendChild tout simple devrait fonctionner nettement mieux (j'ai l'impression que l'append proposé dans l'article n'est pas une vraie fonction et que c'est codé dans le js google...)
exemple : https://developer.mozilla.org/fr/docs/DOM/element.appendChild

20

(Je suis en train de me monter une machine virtuelle sur mon Atom première génération pour tester tout ça, désolé de ne pas donner de nouvelles mais c'est un poil lent à mettre en place grin mais je suis très impatient de tester en tout cas ^^)
avatar

21

Nil (./16) :
(Mais est-ce utile dans le cas présent, où 90% du code est du traitement de donnée issue de bases externes, où l'application n'a pas de modèle de données à proprement parler puisqu'on fait passer la donnée issue de A, B, C vers K, L, M ?)

(je vais parler pour Django, mais je crois que c'est aussi vrai pour Symfony)

Oui, pour plein de raisons :
* il y a toujours des trucs communs à tous les sites (authentification, gestion des urls, ...), ça évite de le recoder
* Ça évite de le recoder en ajoutant des failles de sécurité
* C'est plus facile pour quelqu'un d'autre de reprendre ton code (le framework impose une structure de code qui facilite les choses)
* Ton code sera sûrement plus modulaire
* C'est super simple de faire des outils en ligne de commande intégrés au site (tu as une commande ./manage.py, qui permet d'interagir facilement avec la base de données : par exemple, ton script serait en ligne de commande, seule la supervision serait en web)
* Ce n'est pas parce que tes bases sont externes que tu ne peux pas définir ton modèle dessus (exemple : je me suis fait rapidement un site Django, pour gérer une base LDAP couplée à une base externe PostgreSQL pour le DNS)
* l'apprentissage du framework servira à nouveau
* c'est plus facile de coupler à d'autres outils.
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

22

Non mais le fait que mes bases soient externes a une contrainte : je ne connais pas à l'avance ni la structure des bases d'entrée, ni celle des bases de sortie. A terme, l'application est un environnement de travail où on détermine un ou plusieurs flux d'entrée et un ou plusieurs flux de sortie, avec un contexte pré-défini (synchronisation, archivage, suppression, mise en attente des comptes), et des opérations complémentaires définies dans des fichiers de scripts personnalisés (Microsoft n'arrive pas à faire mieux avec MIIS/ILM/FIM).
A la rigueur, je peux étudier la faisabilité de décrire chaque modèle de données au format XML ou en yaml, mais c'est parfois beaucoup moins lisible que la syntaxe des tableaux de PHP. Et ça risque de ne pas être suffisant quoi qu'il arrive, malheureusement.
avatar

23

Je confirme ce que dit Flan au niveau des frameworks ; en ajoutant que c'est vrai aussi en PHP, pour les frameworks "complets".
Après, tu n'as pas forcément besoin de tout ça pour chaque appli ; et un framework plus simple comme Silex peut déjà te servir de bonne base.

Quant à ton besoin "plusieurs flux d'entrée et un ou plusieurs flux de sortie", plutôt que de tout coder "à la main", est-ce que tu as envisagé l'utilisation d'un ETL ?
En gratuit, tu dois pouvoir jeter un coup d'oeil à Talend, par exemple -- bon, c'est un peu de l'usine à gaz pas forcément évidente à maitriser, mais des fois ça permet de faire des trucs pas trop mal...
avatar
Tutorial C (TI-89/92+/v200) - Articles Développement Web (PHP, Javascript, ...)
« What is the sound of Perl? Is it not the sound of a wall that people have stopped banging their heads against? » - Larry Wall

24

Je suis pas sûr qu'utiliser un framework ait un quelconque rapport avec son problème, vous essayez juste de vendre votre truc grin

(en l'occurrence je crayonne Pen², le problème est probablement plus lié au fait que la page actuelle de Nil modifie .innerHTML et provoque donc un recalcul complet du layout en permanence)
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

25

Tiens, question bête : c'est la page web qui effectue le calcul ? hum Donc si tu fais un refresh par erreur, ça recommence tout ? Ou ta page web fait uniquement la supervision ?
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

26

flanker (./25) :
Tiens, question bête : c'est la page web qui effectue le calcul ? hum.gif Donc si tu fais un refresh par erreur, ça recommence tout ? Ou ta page web fait uniquement la supervision ?
Oui mais non : je crée un fichier .lock de sécurité pour éviter que ça ne se relance par erreur.
Ce fonctionnement me convient très bien (en tout cas aujourd'hui) : j'ai besoin de pouvoir arrêter l'exécution du script immédiatement (aux problèmes de cache PHP/Apache/OpenLdap près) au cas où une grosse erreur est détectée (si je dois attendre 15 minutes, je crève, et pour des raisons de cohérence des données le verrou me permet d'éviter que deux personnes ne lancent le script en même temps).
squale92 (./23) :
Quant à ton besoin "plusieurs flux d'entrée et un ou plusieurs flux de sortie", plutôt que de tout coder "à la main", est-ce que tu as envisagé l'utilisation d'un ETL ?
Ah, tiens, je ne connaissais pas, je vais regarder (cela dit, tout n'est malheureusement pas gérable automatiquement, en particulier parce que je suis obligé de faire des choses un peu sales, comme la détection d'un même individu présent dans plusieurs bases avec un certain pourcentage de matching - une même personne peut parfois être saisie avec des orthographes erronées ou différentes, en particulier pour les étrangers).
Mais je vais quand même regarder ça, on ne sait jamais.

Zeph > ouais, j'ai bien compris qu'ils essayent de me vendre leur truc, mais bon, je reste à l'écoute, je suis conscient d'avoir loupé pas mal de choses niveau outils de dev ^^ (et merci à Penpen d'être dans le sujet - qui a dit "pour une fois ?" grin)
avatar

27

(Han ! Je suis dans le sujet quand il y en a un, stout embarrassed)

28

Regarde plutôt du côté de la fonction setInterval (http://www.xul.fr/ecmascript/settimeout.php) qui lancerait une petite requête AJAX pour récupérer l'avancement.


avec le script php derrière qui attend un event ou un timeout avant de quitter, plus proche du temps reel et pas de requêtes inutiles.

par contre, l'ajax t'oblige à fragmenter ton code avec un second script dédié, ce qui implique un partage des infos entre eux et donc tout ce qui s'en suit

en utilisant des websocket c'est directement le serveur qui enverra un event au lieu du client qui demande une mise à jour

c'est bien plus souple pour toi, plus de fragmentation, et un dialogue bien plus optimal, souple et simple à mettre en place




je parlais de node.js plus haut, qui du fait de javascript lui même est parfait pour ces events, les callback étant une chose commune pour lui

de plus, le script node tourne plus ou moins "en boucle" (on doit faire ctrl-C :- ), en gros tu déclare un serveur une ecoute sur un / des ports et code tout comme des event de ton app.

le code ne se terminant jamais, les variables resterons toujours accessibles et pourrons évoluer au fils des requêtes

du fait du js également, tu peu partager entièrement les codes entre client et serveur, pour un système de template par exemple ou encore pour un jeux en ligne, permettre au serveur de lancer la même succession de commandes que le client et ainsi vérifier la conformité de ses dires

aussi des api comme dnode te permette de facilement lancer des fonctions serveur depuis le client et au serveur de déclencher des fonction clientes, avec callback, arguments et autres..

php lui se lance et se termine en utilisant un thread au passage, ici non, pas de requêtes par millions mais une vrai app avec au besoin un dialogue constant et temps reel, dans un seul thread dédié

pour terminer il existe une api dnode pour php (entre autre) permettant au deux d'exploiter le code de l'autre

voila, c'est pas pour rentrer dans un troll sur les langages, frameworks et autre, mais node est vraiment intéressant performant innovateur et puissant pour que se soit souligné
il signe pour moi un tournant dans le web, node est un peu comme une fusion entre un nginx et un php, un vrai couteau suisse
et la le mec il le pécho par le bras et il lui dit '

29

Bon, a priori utiliser appendChild et les fonctions associées devrait résoudre mon problème, sauf que ça demande un peu beaucoup d'adaptation cheeky (j'avais des choses assez complexes que je balançais dans le innerhtml, il faut que je découpe tout en éléments DOM :'(
avatar

30

^^
Ajouter ton contenu wrappé dans des divs via le appendChild ne suffit pas ?