Attendre un évènement en base de données dans une servlet

Attendre un évènement en base de données dans une servlet - Java - Programmation

Marsh Posté le 05-01-2004 à 17:15:49    

Bon, on va essayer d'expliquer ma situation simplement.
J'ai une servlet qui est chargée de vérifier l'état d'une tâche en base de données. Cet état peut être (entre autres) : "CRS" (en cours), "OK" (terminé avec succès), ou "ERR" (terminé avec erreur). Ma servlet ne doit rendre de résultat QUE quand la tâche est terminée (OK ou ERR), ou au bout de 60 secondes, si la tâche n'est tjs pas terminée.
Pour cela j'ai essayé qqch dans ce style :

Code :
  1. while (true) {
  2.                 stmt = _c.createStatement();
  3.                 // Génération de la requète SQL
  4.                 String strQuery = "SELECT " + JOB_COLUMNS + " FROM " + JOBS_TABLE + " WHERE "
  5.                     + JOB_COLUMN_JOBID + " = '" + _strJobID + "'";
  6.                 r = stmt.executeQuery (strQuery);
  7.                 if ((r != null) && (r.next()))
  8.                     theJob = ResultSetToJob (r);
  9.                 // Si le job à été traité, rendre dans tous les cas
  10.                 if ((theJob == null) || (theJob.isJobTreated()))
  11.                     break;
  12.                 // Calcule du temps attendu jusqu'alors
  13.                 long lElapsedTime = System.currentTimeMillis() - lStartTime;
  14.                 // Si on ne doit pas attendre ou que le temps à attendre est dépassé
  15.                 if ((_iWait == 0) || (lElapsedTime >= _iWait))
  16.                     break;
  17.                 try {
  18.                     // TODO : éviter de tuer les perfs
  19.                     Runtime.getRuntime().wait(1000);
  20.                 } catch (InterruptedException e) {
  21.                     ;
  22.                 }
  23.             }


 
Problème : sur le "Runtime.getRuntime().wait(1000);", je me mange une exception :


java.lang.IllegalMonitorStateException: current thread not owner


 
Je comprend la raison de l'exception. Je vois pas comment y pallier. Plus largement : comment effectuer cette attente de changement d'état en base de données.
Le multi-thread est déja géré par mon moteur de servlet, je n'ai donc pas besoin de créer de nouveau thread, mais comment mettre ce thread là en attente ?
Merci...


---------------
Les Vers Solitaires, on aime ... ou pas !
Reply

Marsh Posté le 05-01-2004 à 17:15:49   

Reply

Marsh Posté le 05-01-2004 à 17:20:51    

public Object lock = new Object();
synchronzied(lock) {
   lock.wait(1000);
}


---------------
Just because you feel good does not make you right
Reply

Marsh Posté le 05-01-2004 à 17:56:29    

sans oublier le  
 
synchronzied(lock) {  
   lock.notify();  
}


---------------
ma vie, mon oeuvre - HomePlayer
Reply

Marsh Posté le 05-01-2004 à 18:01:25    

bin si il doit le réveiller avant oui :o


---------------
Just because you feel good does not make you right
Reply

Marsh Posté le 05-01-2004 à 21:41:17    

euh une servlet qui repond pas avant 1 minute, z'etes gentil mais le browser il va partir en timeout. j'espere.
problème de design à mon avis.
passer par une applet si vraiment necessaire.


---------------
Hey toi, tu veux acheter des minifigurines Lego, non ?
Reply

Marsh Posté le 05-01-2004 à 21:47:32    

the real moins moins a écrit :

euh une servlet qui repond pas avant 1 minute, z'etes gentil mais le browser il va partir en timeout. j'espere.
problème de design à mon avis.
passer par une applet si vraiment necessaire.


 
c'est clair qu'il y a un problème de design hein :o
 
le wait(1000) c'est 1 sec hein si c'est de ça que tu parles. Sinon

Citation :


Ma servlet ne doit rendre de résultat QUE quand la tâche est terminée (OK ou ERR), ou au bout de 60 secondes, si la tâche n'est tjs pas terminée.

Reply

Marsh Posté le 05-01-2004 à 21:58:41    

bon alors, mes remarques:
- si on peut proposer une autre solution de design, voici ce que je ferais: garder en session ou dans l'applicationContext le nombre de fois qu'une requete à été executée sans succes et le moment ou elle a été executée la 1e fois. executer la requete une seule fois par requette à la servlet, stocket le compteur, afficher le tout a l'utilisateur.
 
- sinon:
pourquoi ne pas utiliserun Timer, c'est fait pour ça et ça marche bien.


---------------
Hey toi, tu veux acheter des minifigurines Lego, non ?
Reply

Marsh Posté le 05-01-2004 à 22:01:08    

:jap:

Reply

Marsh Posté le 06-01-2004 à 08:59:10    

the real moins moins a écrit :

euh une servlet qui repond pas avant 1 minute, z'etes gentil mais le browser il va partir en timeout. j'espere.
problème de design à mon avis.
passer par une applet si vraiment necessaire.


 
Pour 60 Secondes, j'abuse peut être un peu. Mais le browser ne partira pas en time out de toute façon, car la servlet qui peut mettre jusqu'a 60 secondes à répondre est appelée entant que source d'une image (et sert à récupérer et balancer des bonnées d'images en binaire).


---------------
Les Vers Solitaires, on aime ... ou pas !
Reply

Marsh Posté le 06-01-2004 à 09:01:07    

the real moins moins a écrit :

bon alors, mes remarques:
- si on peut proposer une autre solution de design, voici ce que je ferais: garder en session ou dans l'applicationContext le nombre de fois qu'une requete à été executée sans succes et le moment ou elle a été executée la 1e fois. executer la requete une seule fois par requette à la servlet, stocket le compteur, afficher le tout a l'utilisateur.
 
- sinon:
pourquoi ne pas utiliserun Timer, c'est fait pour ça et ça marche bien.


 
Pourquoi ne pas utiliser un Timer ? Dans cette situation particulière, je veux justement bloquer le thread, et que le client n'ai pas de réponse tant que ma condition "theJob.isJobTreated()" n'est pas respectée ou que le time out de 60 secondes n'est pas écoulé.


---------------
Les Vers Solitaires, on aime ... ou pas !
Reply

Marsh Posté le 06-01-2004 à 09:01:07   

Reply

Marsh Posté le 06-01-2004 à 09:01:35    

Merci Dark pour ta réponse d'hier, j'pense que ça va m'aller parfaitement.
 
EDIT : oui, je sais que le wait (1000) c'est une secondes !


Message édité par El_gringo le 06-01-2004 à 09:02:12

---------------
Les Vers Solitaires, on aime ... ou pas !
Reply

Marsh Posté le 06-01-2004 à 09:19:07    

Ha mais au fait, j'y pense. Ce que tu m'as proposé Dark, ça va bloquer tous les clients qui cherchent à accèder à ma servlet pendant 1 secondes à chauqe fois. Moi je voudrais bloquer juste le thread en cours...


---------------
Les Vers Solitaires, on aime ... ou pas !
Reply

Marsh Posté le 06-01-2004 à 09:34:25    

el_gringo a écrit :

Ha mais au fait, j'y pense. Ce que tu m'as proposé Dark, ça va bloquer tous les clients qui cherchent à accèder à ma servlet pendant 1 secondes à chauqe fois. Moi je voudrais bloquer juste le thread en cours...


ben non. Le synchronize il le fait sur un objet local à la méthode, pas sur un objet de la servlet.

Reply

Marsh Posté le 06-01-2004 à 09:41:54    

benou a écrit :


ben non. Le synchronize il le fait sur un objet local à la méthode, pas sur un objet de la servlet.


 
En fait je m'apprêtais à supprimer ma dernière remarque.
Par contre j'suis pas d'accord avec toi benou, il le fait son synchronized sur un membre de l'instance (déclaration précédée d'un indicateur de portée). D'ailleurs si je fais le synchronized sur un objet local à la méthode, je me prend à nouveau l'exception que j'avais à mon 1er post. Si je déclare le verrou (lock) entant qu'attribut de ma classe Servlet, ça roule.


---------------
Les Vers Solitaires, on aime ... ou pas !
Reply

Marsh Posté le 06-01-2004 à 10:21:42    

el_gringo a écrit :


il le fait son synchronized sur un membre de l'instance


ouais j'avais pas vu le "public" ...
 
si c'est ca que tu veux ok, mais tous les appels à ta servlets resteront bloqués : tu rends ta servlet monothreadée à ce moment là....


---------------
ma vie, mon oeuvre - HomePlayer
Reply

Marsh Posté le 06-01-2004 à 10:27:59    

benou a écrit :


ouais j'avais pas vu le "public" ...
 
si c'est ca que tu veux ok, mais tous les appels à ta servlets resteront bloqués : tu rends ta servlet monothreadée à ce moment là....


 
C'est bien ce dont j'avais peur. Et comment je peux faire : ne pas répondre a un client donné tant que la condition "theJob.isJobTreated()" n'est pas vraie pour ce client, mais permettre néamoins l'accès à cette même servlet par d'autres threads ?


---------------
Les Vers Solitaires, on aime ... ou pas !
Reply

Marsh Posté le 06-01-2004 à 10:51:02    

Bon d'après ce que j'i compris, ce que tu veux faire c'est attendre qu'un truc se passe en base. C'est à dire que la première requête qui arrive fasse des recherche en base, juqsu'à ce que "le truc se passse". Tant que le truc ne "s'est pas passé", les autres requêtes doivent être misent en attente.
 
Donc si c'est ca, voilà comment faire :  

Code :
  1. private Object lock = new Object();
  2. private boolean working = false;
  3. public void doGet(...) throws ... {
  4.    ...
  5.    synchronized (this.lock) {
  6.       if (! theJob.isJobTreated()) {
  7.          if (this.working) {
  8.             this.lock.wait();
  9.          } else {
  10.             this.doTheJob();
  11.          }
  12.       }
  13.    }
  14. }
  15. /** must be called with a lock on job  */
  16. private void doTheJob() { 
  17.    this.working = true;
  18.    // fait ta recherche en base
  19.    while (true) {
  20.       stmt = _c.createStatement();
  21.       // Génération de la requète SQL  
  22.       String strQuery = "SELECT " + JOB_COLUMNS + " FROM " + JOBS_TABLE + " WHERE " + JOB_COLUMN_JOBID + " = '" + _strJobID + "'";
  23.      r = stmt.executeQuery (strQuery);
  24.      if ((r != null) && (r.next())) {
  25.         theJob = ResultSetToJob (r);
  26.      }
  27.      // Si le job à été traité, rendre dans tous les cas  
  28.      if ((theJob == null) || (theJob.isJobTreated())) {
  29.         this.working = true;
  30.         this.lock.notifyAll();
  31.         break;
  32.      }
  33.      try {
  34.         Thread.sleep(1000);
  35.      } catch (InterruptedException e) {
  36.         Thread.currentThread().interrupt();       
  37.         break;
  38.      }
  39.    }
  40. }


---------------
ma vie, mon oeuvre - HomePlayer
Reply

Marsh Posté le 06-01-2004 à 11:02:03    

el_gringo a écrit :


EDIT : oui, je sais que le wait (1000) c'est une secondes !


 
ce n'est pas à toi que je parlais mais à --


---------------
Just because you feel good does not make you right
Reply

Marsh Posté le 06-01-2004 à 11:03:52    

benou a écrit :

Bon d'après ce que j'i compris, ce que tu veux faire c'est attendre qu'un truc se passe en base. C'est à dire que la première requête qui arrive fasse des recherche en base, juqsu'à ce que "le truc se passse". Tant que le truc ne "s'est pas passé", les autres requêtes doivent être misent en attente.


 
Non, c'est pas ce que je cherche à faire. Au contraire, c'est ce que je veux éviter. J'explique le contexte, ça pourra aider à comprendre. Ma servlet sert à afficher une image spécifique selon chaque demande. Cette image est générée par un programme avec lequel elle comunique par base de données.
En schématisant :
- demande HTTP d'affichage d'image
- réception de la demande par la servlet HTTP
- écriture de l'ordre de génération d'image ("job" ) en base de données pour faire la demande au module de génération des images (sur lequel je n'ai absolument pas la main)
- attente que l'image ai été généré (job traité) par le module de génération des images (en vérifiant la base de données régulièrement : c'est dans celle-ci qu'est indiqué l'état de traitement du "job" )
- Quand le "job" est terminé, envoit de la réponse par la servlet HTTP (données d'images binaires + type MIME et compagnie)
 
La réponse ne doit être renvoyé au client QUE quand l'image est disponible (ou qu'une erreur a été constatée)


Message édité par El_gringo le 06-01-2004 à 11:07:12

---------------
Les Vers Solitaires, on aime ... ou pas !
Reply

Marsh Posté le 06-01-2004 à 11:12:38    

[:heink]
 
et pq tu ne t'arranges pas pour que ton module de génération d'image te callback qd il a terminé son bourzin. Ok ok, tu n'y a pas accès mais bon la façon dont il est invoqué tu peux modifier ca non?
 
(tu passe par la bd pour l'invoquer? [:totoz])


---------------
Just because you feel good does not make you right
Reply

Marsh Posté le 06-01-2004 à 11:17:05    

darklord a écrit :

[:heink]
et pq tu ne t'arranges pas pour que ton module de génération d'image te callback qd il a terminé son bourzin. Ok ok, tu n'y a pas accès mais bon la façon dont il est invoqué tu peux modifier ca non?
 
(tu passe par la bd pour l'invoquer? [:totoz])


 
Il me callbackera pas, tout simplement parce qu'il est pas fait pour ça. Il est écrit en C++, c'est un gros moteur de traitements de masse (qui en l'occurence sert à la génération d'images). Donc la façon dont il est invoqué, je peux pas modifier ça. Et, je comprend que ça te choque si je dit que je l' "invoque" par base de données. Disons que je lui poste une demande. ça passe mieux comme ça ?


---------------
Les Vers Solitaires, on aime ... ou pas !
Reply

Marsh Posté le 06-01-2004 à 11:34:25    

el_gringo a écrit :


 
Il me callbackera pas, tout simplement parce qu'il est pas fait pour ça. Il est écrit en C++, c'est un gros moteur de traitements de masse (qui en l'occurence sert à la génération d'images). Donc la façon dont il est invoqué, je peux pas modifier ça. Et, je comprend que ça te choque si je dit que je l' "invoque" par base de données. Disons que je lui poste une demande. ça passe mieux comme ça ?


 
oui ça passe mieux mais bon, ma réponse: "tu ne sais pas avoir un design propre si tu es obligé d'utiliser un truc pourri comme un porc"
 
et visiblement cai le cas :D


---------------
Just because you feel good does not make you right
Reply

Marsh Posté le 06-01-2004 à 11:40:30    

darklord a écrit :


 
oui ça passe mieux mais bon, ma réponse: "tu ne sais pas avoir un design propre si tu es obligé d'utiliser un truc pourri comme un porc"
 
et visiblement cai le cas :D


 
Ce truc est pas tout pourrit. C'est du traitement de masse. Je trouve pas choquand de lui poster de demander en base de données. Mais de toute façon, c'est comme ça, et ça, j'y peux absolument rien, j'dois faire avec. Si je peux pas avoir un design propre, tant pis, j'voudrais juste arriver à m'en sortir  :cry:


---------------
Les Vers Solitaires, on aime ... ou pas !
Reply

Marsh Posté le 06-01-2004 à 11:50:17    

el_gringo a écrit :


 
Ce truc est pas tout pourrit. C'est du traitement de masse. Je trouve pas choquand de lui poster de demander en base de données. Mais de toute façon, c'est comme ça, et ça, j'y peux absolument rien, j'dois faire avec. Si je peux pas avoir un design propre, tant pis, j'voudrais juste arriver à m'en sortir  :cry:  


 
ne te méprends pas hein, c'est bien ce que je dis. Si tu ne sais rien y faire, ca va etre dur de faire un truc propre c'est tout :/


---------------
Just because you feel good does not make you right
Reply

Marsh Posté le 06-01-2004 à 12:01:51    

darklord a écrit :


 
ne te méprends pas hein, c'est bien ce que je dis. Si tu ne sais rien y faire, ca va etre dur de faire un truc propre c'est tout :/


 
J'avais compris.
Pour en revenir au sujet exact : la méthode que tu m'as proposée dès la 1er réponse fonctionne, mais problème : le verrou est un membre de la servlet, il va donc bloquer l'accès a tous les utilisateur de la servlet pendant qu'un des utilisateurs attend. C'est pas ce que j'essaye de faire. Et si je passe le verrou entant que variable locale, je me prend encore l'exception suivante :

java.lang.IllegalMonitorStateException: current thread not owner


---------------
Les Vers Solitaires, on aime ... ou pas !
Reply

Marsh Posté le 06-01-2004 à 12:42:38    

montre ton code
 


---------------
Just because you feel good does not make you right
Reply

Marsh Posté le 06-01-2004 à 14:14:09    

La partie de code inspirée de ce que tu m'as proposé envoit l'exception dont je parlais. Si le met "lock" entant qu'attribut, ça passe. Mais le comportement n'est alors plus celui souhaité (bloquage de tous les clients de la servlet pendant l'attente de 1000 ms).

Code :
  1. while (true) {
  2.     stmt = _c.createStatement();
  3.     // Génération de la requète SQL
  4.     String strQuery = "SELECT " + JOB_COLUMNS + " FROM " + JOBS_TABLE + " WHERE "
  5.         + JOB_COLUMN_JOBID + " = '" + _strJobID + "'";
  6.     r = stmt.executeQuery (strQuery);
  7.     if ((r != null) && (r.next()))
  8.           theJob = ResultSetToJob (r);
  9.     // Si le job à été traité, rendre dans tous les cas
  10.     if ((theJob == null) || (theJob.isJobTreated()))
  11.           break;
  12.     // Calcule du temps attendu jusqu'alors
  13.     long lElapsedTime = System.currentTimeMillis() - lStartTime;
  14.     // Si on ne doit pas attendre ou que le temps à attendre est dépassé
  15.     if ((_iWait == 0) || (lElapsedTime >= _iWait))
  16.           break;
  17.     // Le bout de code à Dark un rien modifié
  18.     try {
  19.       Object lock = new Object();
  20.       synchronzied(lock) {
  21.           lock.wait(1000);
  22.       }
  23.     } catch (InterruptedException e) {;}
  24. }


Message édité par El_gringo le 06-01-2004 à 14:16:06

---------------
Les Vers Solitaires, on aime ... ou pas !
Reply

Marsh Posté le 06-01-2004 à 14:30:13    

Attend, mais le seul truc dont tu a besoin c'est de faire un sleep !!!
T'as juste à faire  
  try {  
      Thread.sleep(1000);
  } catch (InterruptedException e) {
      Thread.currentThread.interrupt();
  }  
 
pas besoin de faire de wait [:spamafote]


---------------
ma vie, mon oeuvre - HomePlayer
Reply

Marsh Posté le 06-01-2004 à 14:40:44    

oui mais bon si tu fais un sleep du thread ca va bloquer les autres threads qui voudraient accéder à cette instance de sa servlet.
 
Sinon gringo faudrait que je regarde un peu plus en profondeur, je ne comprends pas pq ca ne marcherait pas :/
 
Le deal c'est que si un thread, quel qu'il soit, est en wait d'un truc, tu ne peux pas t'attendre à ce qu'ils servent d'autres clients. Donc t'as pas de solution sinon de threadé ta servlet à mort


---------------
Just because you feel good does not make you right
Reply

Marsh Posté le 06-01-2004 à 14:42:39    

darklord a écrit :

oui mais bon si tu fais un sleep du thread ca va bloquer les autres threads qui voudraient accéder à cette instance de sa servlet.


 [:mlc2]  
 
 :heink:  
 
 [:wam]  
 
N'importe quoi :o


---------------
ma vie, mon oeuvre - HomePlayer
Reply

Marsh Posté le 06-01-2004 à 14:45:45    

benou a écrit :


 [:mlc2]  
 
 :heink:  
 
 [:wam]  
 
N'importe quoi :o


 
 :heink:  
donc qd tu as une instance de la servlet Machin et que tu appelles service() ca te crée un nouveau thread à chaque fois peut etre?


---------------
Just because you feel good does not make you right
Reply

Marsh Posté le 06-01-2004 à 14:48:29    

el_gringo a écrit :


 
Pour 60 Secondes, j'abuse peut être un peu. Mais le browser ne partira pas en time out de toute façon, car la servlet qui peut mettre jusqu'a 60 secondes à répondre est appelée entant que source d'une image (et sert à récupérer et balancer des bonnées d'images en binaire).

et ça change quoi? au mieux t'auras pas ton image, au pire t'auras quand meme le popup de timeout


---------------
Hey toi, tu veux acheter des minifigurines Lego, non ?
Reply

Marsh Posté le 06-01-2004 à 14:50:07    

darklord a écrit :


 :heink:  
donc qd tu as une instance de la servlet Machin et que tu appelles service() ca te crée un nouveau thread à chaque fois peut etre?


mais totoz quoi !!!! Tu le fais exprès c'est pas possible [:w3c compliant]
 
c'est les différents Thread (du pool de thread du moteur de servlet) qui appellent la méthode service sur la même instance de la servlet. Si y a un thread qui reste coincé un moment dans la méthode ca impacte pas les autres threads !


---------------
ma vie, mon oeuvre - HomePlayer
Reply

Marsh Posté le 06-01-2004 à 14:50:49    

j'adore les discours de sourds entre mecs qui savent pas s'exprimer :)


Message édité par the real moins moins le 06-01-2004 à 14:50:54

---------------
Hey toi, tu veux acheter des minifigurines Lego, non ?
Reply

Marsh Posté le 06-01-2004 à 14:51:21    

benou a écrit :


mais totoz quoi !!!! Tu le fais exprès c'est pas possible [:w3c compliant]
 
c'est les différents Thread (du pool de thread du moteur de servlet) qui appellent la méthode service sur la même instance de la servlet. Si y a un thread qui reste coincé un moment dans la méthode ca impacte pas les autres threads !


 
sauf que je ne parlais pas de ca et merci de me prendre pour un con fini.
Bon spagrave, j'ai l'habitude


---------------
Just because you feel good does not make you right
Reply

Marsh Posté le 06-01-2004 à 14:52:36    

the real moins moins a écrit :

j'adore les discours de sourds entre mecs qui savent pas s'exprimer :)


quoi c'est très clair ce que je dis ...


---------------
ma vie, mon oeuvre - HomePlayer
Reply

Marsh Posté le 06-01-2004 à 14:53:37    

darklord a écrit :


sauf que je ne parlais pas de ca et merci de me prendre pour un con fini.


 :heink:  

Citation :

oui mais bon si tu fais un sleep du thread ca va bloquer les autres threads qui voudraient accéder à cette instance de sa servlet.


 

darklord a écrit :


Bon spagrave, j'ai l'habitude


nan, vas-y ! dis, je veux comprendre !


Message édité par benou le 06-01-2004 à 14:53:49

---------------
ma vie, mon oeuvre - HomePlayer
Reply

Marsh Posté le 06-01-2004 à 14:56:41    

benou a écrit :


quoi c'est très clair ce que je dis ...

c'est bien ce que je dis :lol:


---------------
Hey toi, tu veux acheter des minifigurines Lego, non ?
Reply

Marsh Posté le 06-01-2004 à 14:57:32    

the real moins moins a écrit :

c'est bien ce que je dis :lol:


allez, raconte ce que tu as pas compris à tonton benou [:tonton_benou]


---------------
ma vie, mon oeuvre - HomePlayer
Reply

Marsh Posté le 06-01-2004 à 15:17:31    

benou a écrit :

Attend, mais le seul truc dont tu a besoin c'est de faire un sleep !!!
T'as juste à faire  
  try {  
      Thread.sleep(1000);
  } catch (InterruptedException e) {
      Thread.currentThread.interrupt();
  }  
 
pas besoin de faire de wait [:spamafote]


 
Ben voila. C'est tout bêtement ce que je cherchais depuis le début. Merci benou.


---------------
Les Vers Solitaires, on aime ... ou pas !
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed