Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Architecture - struts - thread

12 réponses
Avatar
Vincent
Bien le bonjour,

Ma question concerne plus l'organisation de classes que le code en lui même.

Je réalise une application web (imode) avec struts, tomcat 4.1, Apache2,
Interbase 6. Je n'ai aucun souci de montée en charge.

Un service que je souhaiterais mettre en place est l'insertion, dans une
base de données, de "mesures" (factices) qui auraient lieu toutes les 10
min, disons. Lorsque le client active ce service pendant sa session, le
robot d'insertion est instancié avec la liste des sites du client pour
lequel il souhaite faire une simulation d'insertion de mesures.

Pour mettre ceci dans le contexte struts, l'activation se ferait dans la
classe PeuplerAction. Et là, j'entrevois 2 solutions :

1°) Instancier, au démarrage de l'application, une servlet à laquelle je
pourrais ajouter ou supprimer des sites. La servlet possèderait une instance
de classe AjouteurMesureThread qui, toutes les 10 min, insère dans la base
de données une mesure pour chacun des sites qu'il possède. La servlet
jouerait donc juste le rôle de lien entre le robot AjouteurMesureThread et
l'action PeuplerAction.
Une de mes questions concernent la faisabilité de celà :
est-ce que, dans une Action, on peut atteindre une servlet qui tourne en
permanence (web.xml, <loadonstartup>)?
Que pensez-vous de cette solution?

2°) Autre solution : l'action PeuplerAction crée lui-même le thread
AjouteurMesureThread et l'ajoute dans la 'session' du client. Est-ce que le
thread sera toujours activé? Que pensez vous de cette solution sachant que
le client peut bien sûr désactiver la simulation d'insertion au cours de sa
session?
Le problème que me pose cette solution est qu'il faudra donc non plus un
thread pour tous les sites de tous les clients, mais un thread par client.
J'utilise un pool de connexion pour accéder à la base de données, mais
n'est-ce pas quand même dommage d'utiliser autant de thread?


Merci pour vos avis!


Au passage, je me suis souvent demandé le coût de garder des informations en
'session' d'un utilisateur. Faut-il faire très attention avec cela ou bien
n'est-ce important qu'avec plusieurs milliers d'utilisateurs en même temps?
(ce qui n'est pas du tout mon cas!)


--
Vincent
Attention à mon adresse.

10 réponses

1 2
Avatar
Vincent
"Vincent" a écrit dans le
message news: bfgb7a$d6e$

Pour mettre ceci dans le contexte struts, l'activation se ferait dans la
classe PeuplerAction. Et là, j'entrevois 2 solutions :

1°) Instancier, au démarrage de l'application, une servlet à laquelle je
pourrais ajouter ou supprimer des sites. La servlet possèderait une
instance

de classe AjouteurMesureThread qui, toutes les 10 min, insère dans la base
de données une mesure pour chacun des sites qu'il possède. La servlet
jouerait donc juste le rôle de lien entre le robot AjouteurMesureThread et
l'action PeuplerAction.
Une de mes questions concernent la faisabilité de celà :
est-ce que, dans une Action, on peut atteindre une servlet qui tourne en
permanence (web.xml, <loadonstartup>)?
Que pensez-vous de cette solution?

2°) Autre solution : l'action PeuplerAction crée lui-même le thread
AjouteurMesureThread et l'ajoute dans la 'session' du client. Est-ce que
le

thread sera toujours activé? Que pensez vous de cette solution sachant que
le client peut bien sûr désactiver la simulation d'insertion au cours de
sa

session?
Le problème que me pose cette solution est qu'il faudra donc non plus un
thread pour tous les sites de tous les clients, mais un thread par client.
J'utilise un pool de connexion pour accéder à la base de données, mais
n'est-ce pas quand même dommage d'utiliser autant de thread?


J'ai essayé de mettre en oeuvre cette deuxième solution, et ça ne semble pas
fonctionner... Faisant un test avec un 'main' (application), l'insertion
dans la bd fonctionne, mais n'étant pas un habitué des threads, je me
demandais si le thread n'était pas détruit à la fin de la méthode 'execute'
de PeuplerAction. En effet, la référence au thread est mise en session
(session.setAttribute) mais je ne sais pas si cela est valide pour conserver
le thread en vie...

Aucune erreur n'est générée.

--
Vincent

Avatar
Arnaud Roger
J'ai essayé de mettre en oeuvre cette deuxième solution, et ça ne semble
pas

fonctionner... Faisant un test avec un 'main' (application), l'insertion
dans la bd fonctionne, mais n'étant pas un habitué des threads, je me
demandais si le thread n'était pas détruit à la fin de la méthode
'execute'

de PeuplerAction. En effet, la référence au thread est mise en session
(session.setAttribute) mais je ne sais pas si cela est valide pour
conserver

le thread en vie...

Un thread vie tant qu'il n'est pas mort :)

c'est a dire qu'il vie tant que la method run tourne

Arnaud R.

Avatar
Arnaud Roger
1°) Instancier, au démarrage de l'application, une servlet à laquelle je
pourrais ajouter ou supprimer des sites. La servlet possèderait une
instance

de classe AjouteurMesureThread qui, toutes les 10 min, insère dans la base
de données une mesure pour chacun des sites qu'il possède. La servlet
jouerait donc juste le rôle de lien entre le robot AjouteurMesureThread et
l'action PeuplerAction.
Une de mes questions concernent la faisabilité de celà :
est-ce que, dans une Action, on peut atteindre une servlet qui tourne en
permanence (web.xml, <loadonstartup>)?
Que pensez-vous de cette solution?
c'est faisable il suffit de mettre le thread dans le servlet context

qui est global a tout la web app

ca doit se recuperer a l'aide de request.getServletContext


2°) Autre solution : l'action PeuplerAction crée lui-même le thread
AjouteurMesureThread et l'ajoute dans la 'session' du client. Est-ce que
le

thread sera toujours activé? Que pensez vous de cette solution sachant que
le client peut bien sûr désactiver la simulation d'insertion au cours de
sa

session?
Le problème que me pose cette solution est qu'il faudra donc non plus un
thread pour tous les sites de tous les clients, mais un thread par client.
J'utilise un pool de connexion pour accéder à la base de données, mais
n'est-ce pas quand même dommage d'utiliser autant de thread?


ca peut devenir embetant la premiere solution est plus legere

Au passage, je me suis souvent demandé le coût de garder des informations
en

'session' d'un utilisateur. Faut-il faire très attention avec cela ou bien
n'est-ce important qu'avec plusieurs milliers d'utilisateurs en même
temps?

(ce qui n'est pas du tout mon cas!)


ca depend de combien d'info il y a garder,
mais pour un site a forte frequentation il peut etre
plus utile de tapper dans la base a chaque request.
Et si il le faut, installer un systeme de cache comme JCS.

Avatar
bicou
On Mon, 21 Jul 2003 22:39:43 +0200, "Arnaud Roger"
wrote:

1°) Instancier, au démarrage de l'application, une servlet à laquelle je
pourrais ajouter ou supprimer des sites. La servlet possèderait une
instance

de classe AjouteurMesureThread qui, toutes les 10 min, insère dans la base
de données une mesure pour chacun des sites qu'il possède. La servlet
jouerait donc juste le rôle de lien entre le robot AjouteurMesureThread et
...


juste pour info, il me semble me rappeler (mais les choses ont
peut-être changé...) que les servlets étant multi-threadées par le
serveur les exécutant qu'il était plus que déconseillée d'y gérer des
thread 'manuellement'.

me trompes-je ?


Avatar
Vincent
"Arnaud Roger" a écrit dans le message news:
bfhca6$5ie$

J'ai essayé de mettre en oeuvre cette deuxième solution, et ça ne semble
pas

fonctionner... Faisant un test avec un 'main' (application), l'insertion
dans la bd fonctionne, mais n'étant pas un habitué des threads, je me
demandais si le thread n'était pas détruit à la fin de la méthode
'execute'

de PeuplerAction. En effet, la référence au thread est mise en session
(session.setAttribute) mais je ne sais pas si cela est valide pour
conserver

le thread en vie...

Un thread vie tant qu'il n'est pas mort :)

c'est a dire qu'il vie tant que la method run tourne

Arnaud R.


La question est de savoir comment mettre en oeuvre un thread qui
continuerait à s'exécuter même si la seule référence qui lui est faite, est
une variable dans la session.
Je ne comprends pas pourquoi cela ne fonctionne pas.
Voici un bout de code :
Dans l'Action :

MonThread t = (MonThread )
session.getAttribute(Constants.MON_THREAD_KEY);
if (t == null) {
// création car absent de la session
t = new MonThread();
for (int i = 0; i < liste.size(); i++) {
t.ajouterParam((Type1) liste.get(i));
}
t.start();
} else {
t.demarrer();
}
// Le thread est mis en session
session.setAttribute(Constants.MON_THREAD_KEY, t);


Dans la classe MonThread :

public void run() {
continueBoucle = true;
try {
DataHandler dh = new DataHandler();
while (continueBoucle) {
switch (etat) {
case DEMARRE : for (int i = 0; i < liste.getSize(); i++) {
dh.insertData((Type1)
liste.get(i));
}
break;
case ARRETE : // Rien à faire
break;
}
// Pause
try {
Thread.sleep(PERIODE);
} catch (InterruptedException ie) {
ie.printStackTrace(System.err);
}
} // end while
} catch (DataException de) {
de.printStackTrace(System.err);
}
}

Merci pour votre aide,

--
Vincent


Avatar
Vincent
"Arnaud Roger" a écrit dans le message news:
bfhj2l$5kb$
1°) Instancier, au démarrage de l'application, une servlet à laquelle je
pourrais ajouter ou supprimer des sites. La servlet possèderait une
instance

de classe AjouteurMesureThread qui, toutes les 10 min, insère dans la
base


de données une mesure pour chacun des sites qu'il possède. La servlet
jouerait donc juste le rôle de lien entre le robot AjouteurMesureThread
et


l'action PeuplerAction.
Une de mes questions concernent la faisabilité de celà :
est-ce que, dans une Action, on peut atteindre une servlet qui tourne en
permanence (web.xml, <loadonstartup>)?
Que pensez-vous de cette solution?


c'est faisable il suffit de mettre le thread dans le servlet context
qui est global a tout la web app

ca doit se recuperer a l'aide de request.getServletContext


Moi aussi je préfèrerais utiliser cette première solution. Mais je ne
parviens à voir comment manipuler ce thread à partir de la classe
'PeuplerAction'.

Comment l'atteindre? (imaginons une méthode 'setMonAttribute()' dans mon
thread t, qui est dans le servlet context)
getServlet().getServletContext()
...?

Merci!

--
Vincent


Avatar
Xavier Tarrago
ca devrait fonctionner, a mon avis. Ceci dit, ca ne m'etonnerait qu'a moitie
que ca ne fonctionne pas correctement. Il faudrait savoir ce que fait la
methode demarrer. Si deux actions appellent la methode demarrer dans la meme
periode, il y a un appel qui est perdu. Je na sais pas si c'est important.
Il serait pezut-etre plus efficace d'appeler wait au lieu de sleep et notify
dans la methode demarrer; Il faut egalement penser aux synchronisations.
"Vincent" a écrit dans le
message news: bfirg8$3tu$

"Arnaud Roger" a écrit dans le message news:
bfhca6$5ie$

J'ai essayé de mettre en oeuvre cette deuxième solution, et ça ne
semble



pas
fonctionner... Faisant un test avec un 'main' (application),
l'insertion



dans la bd fonctionne, mais n'étant pas un habitué des threads, je me
demandais si le thread n'était pas détruit à la fin de la méthode
'execute'

de PeuplerAction. En effet, la référence au thread est mise en session
(session.setAttribute) mais je ne sais pas si cela est valide pour
conserver

le thread en vie...

Un thread vie tant qu'il n'est pas mort :)

c'est a dire qu'il vie tant que la method run tourne

Arnaud R.


La question est de savoir comment mettre en oeuvre un thread qui
continuerait à s'exécuter même si la seule référence qui lui est faite,
est

une variable dans la session.
Je ne comprends pas pourquoi cela ne fonctionne pas.
Voici un bout de code :
Dans l'Action :

MonThread t = (MonThread )
session.getAttribute(Constants.MON_THREAD_KEY);
if (t == null) {
// création car absent de la session
t = new MonThread();
for (int i = 0; i < liste.size(); i++) {
t.ajouterParam((Type1) liste.get(i));
}
t.start();
} else {
t.demarrer();
}
// Le thread est mis en session
session.setAttribute(Constants.MON_THREAD_KEY, t);


Dans la classe MonThread :

public void run() {
continueBoucle = true;
try {
DataHandler dh = new DataHandler();
while (continueBoucle) {
switch (etat) {
case DEMARRE : for (int i = 0; i < liste.getSize(); i++) {
dh.insertData((Type1)
liste.get(i));
}
break;
case ARRETE : // Rien à faire
break;
}
// Pause
try {
Thread.sleep(PERIODE);
} catch (InterruptedException ie) {
ie.printStackTrace(System.err);
}
} // end while
} catch (DataException de) {
de.printStackTrace(System.err);
}
}

Merci pour votre aide,

--
Vincent






Avatar
Vincent
"Xavier Tarrago" a écrit dans le message news:
bflhtv$9m3$
ca devrait fonctionner, a mon avis. Ceci dit, ca ne m'etonnerait qu'a
moitie

que ca ne fonctionne pas correctement. Il faudrait savoir ce que fait la
methode demarrer. Si deux actions appellent la methode demarrer dans la
meme

periode, il y a un appel qui est perdu. Je na sais pas si c'est important.
Il serait pezut-etre plus efficace d'appeler wait au lieu de sleep et
notify

dans la methode demarrer; Il faut egalement penser aux synchronisations.


Démarrer et arrêter ne concerne pas le thread, mais uniquement l'état dans
lequel se trouve l'insertion. Le thread tourne, mais si l'état est 'ARRETE',
l'insertion n'est pas effectuée. C'est juste pour éviter d'avoir à recréer
le thread. On peut arrêter son activité sans avoir à le détruire.

// Constructeur :
public MonThread() {
this.listeParams= new ListeParam();
this.etat = DEMARRE;
try {
dh = new DataHandler();
} catch (DataException de) {
de.printStackTrace(System.err);
this.destroy();
}
}

/**
* Démarrer l'insertion toutes les X minutes.
*/
public void demarrer() {
etat = DEMARRE;
}

/**
* Arrêter l'insertion (Sans destruction du thread)
*/
public void arreter() {
etat = ARRETE;
}

Ceci est pour la solution où il y a un thread par utilisateur, c'est à dire
que le thread est mis en session. Ainsi, il ne peut y avoir qu'un seul appel
à démarrer() ou arreter() en même temps (pas de pb de concurrence d'accès).

Merci pour ta réponse,

--
Vincent

Avatar
Vincent
"Xavier Tarrago" a écrit dans le message news:
bflhtv$9m3$
ca devrait fonctionner, a mon avis.


Exact, ça fonctionne maintenant. J'essayé de faire des insertions dans une
BD, pour chaque élément d'une liste. Et c'est cette liste qui était
malencontreusement vide. Donc pas d'élément à insérer. Donc pas d'insertion.
:-)

C'est donc la deuxième solution qui a été mise en place (un thread par
client, mis en session).

--
Vincent

Avatar
Vincent
"Frederic Renout" a écrit dans le message news:


Bonjour,


Bonjour,

Maintenant ça tourne (cf. post précédent).

qu'est ce qui ne fonctionne pas correctement avec ton code?


En fait, c'était sans doute ça la meilleure question que je devais me poser,
car étant donné que c'était la première fois que je touchais au thread dans
une webapp, j'avais peur que cela pose un pb et j'ai négligé une autre
source de bugs.

Je suis sous Tomcat/Apache2/mod_jk2, avec JBuilder6 (Entreprise).
J'ai galéré à trouver ce problème parce que j'ai du mal à étudier le contenu
de mes variables. Je ne trouvais pas où sortait System.err , System.out
(maintenant je viens de trouver que c'était dans Apache2logsstderr.log
et stdout.log), et getServlet.log() va dans Tomcatlogs.
Ce qui est pratique c'est d'ajouter un p'tit bout dans server.xml pour avoir
des logs séparés (Tomcatlogs) pour l'appli considérée :
<!-- Tomcat test Context -->
<Context path="/test" docBase="test" debug="0" reloadable="true">
<Logger className="org.apache.catalina.logger.FileLogger"
prefix="test." suffix=".txt" timestamp="true"/>
</Context>

A part cela, comment faites-vous pour débugger une webapps? Une technique
particulière? Un outil?

Merci!

--
Vincent

1 2