2013-02-15 2 views
1

J'ai actuellement un problème avec l'approche requête synchrone jms/réponse, voici ce qui se passe:JMS synchrone demande/réponse en utilisant la file d'attente temporaire timed out lecture

1.) ProgramA créer un message jms, une file d'attente temporaire et définissez-le comme une réponse à. 2.12 ProgramB a un écouteur pour le message créé à partir de ProgramA, traite le message et y répond. Mais ProgramB doit communiquer avec un service Web tiers qui prend parfois plus de 10 secondes pour répondre, et c'est le problème que je mets le consommateur à écouter pour 5000 (5s) et bien sûr, il va expirer après. Donc, le message n'est pas reçu.

Mon observation: 1.) Même si ProgramA est en train de lire (pas de réponse pour le moment, j'essaye de supprimer la file d'attente temporaire). Ce n'est pas possible et ProgramB était encore capable d'écrire dans la file d'attente de réponse, mais personne ne va lire ce message (trop tard).

Lorsque j'essaie de changer le temps d'écoute de 5s à 20s, le problème a été résolu, mais est-ce la bonne approche?

Est-il également possible que ProgramB ne tente pas d'écrire dans la file d'attente lorsque ProgramA a arrêté la lecture?

codes partiels:

Destination replyQueue = send(jmsUtil, actionDTO); 
SalesOrderResponseDTO responseDTO = readReply(jmsUtil, replyQueue, actionDTO); 

public Destination send(JmsSessionUtil jmsUtil, SalesOrderActionDTO soDTO) { 
    try { 
     utx.begin();   
     jmsUtil.send(soDTO, null, 0L, 1, Long.parseLong(configBean.getProperty("jms.payrequest.timetolive")), true); 
     utx.commit(); 
     return jmsUtil.getReplyQueue(); 
    } catch (Exception e) { 
     try { 
      utx.rollback(); 
     } catch (Exception e1) { 

     }  
    } 
    return null; 
} 

public SalesOrderResponseDTO readReply(JmsSessionUtil jmsUtil, Destination replyQueue, SalesOrderActionDTO actionDTO) { 
    SalesOrderResponseDTO responseDTO = null; 
    try {  
     utx.begin(); 

     responseDTO = (SalesOrderResponseDTO) jmsUtil.read(replyQueue); 

     if (responseDTO != null) { 
      // fires the response event 
      SalesOrderResponsePayload eventPayload = new SalesOrderResponsePayload(); 
      eventPayload.setResponseDTO(responseDTO); 
      responseEvent.fire(eventPayload); 
     } else { // timeout 
      ((TemporaryQueue) replyQueue).delete(); 
      jmsUtil.dispose(); 
     } 
     utx.commit(); 
     return responseDTO; 
    } catch (Exception e) { 
     try { 
      utx.rollback(); 
     } catch (Exception e1) { 
     } 
    } 
    return responseDTO; 
} 

public String send(MessageDTO messageDTO, 
      JMSQueueEnum resultNotificationQueue, Long parentProcessId, 
      int JMSPriority, long timeToLive, boolean hasReply) 
      throws JMSException, InvalidDTOException, NamingException { 

    try { 
     // Process optional parameters 
     messageDTO.setResultNotificationQueue(resultNotificationQueue); 
     messageDTO.setParentProcessId(parentProcessId); 

     // Wrap MessageDTO in a JMS ObjectMessage 
     ObjectMessage msg = MessageDTOHelper.serialize(session, messageDTO); 
     msg.setJMSType(messageDTO.getClass().getSimpleName()); 
     msg.setStringProperty("DTOType", messageDTO.getClass() 
       .getSimpleName()); 

     requestProducer = session.createProducer(queue); 

     if (hasReply) { 
      replyQueue = session.createTemporaryQueue(); 
      replyConsumer = session.createConsumer(replyQueue);  
      msg.setJMSReplyTo(replyQueue); 
     } 

     if (JMSPriority > -1) { 
      requestProducer.send(msg, DeliveryMode.PERSISTENT, JMSPriority, 
        timeToLive); 
     } else { 
      // Send the JMS message 
      requestProducer.send(msg); 
     } 
     return msg.getJMSMessageID(); 
    } catch (Exception e) { 

    } 

    return null; 
} 

public MessageDTO read(Destination replyQueue) throws JMSException, 
      NamingException { 
    if (replyQueue instanceof Queue) { 
     Message msg = replyConsumer.receive(20000); 

     if (msg == null) { 
      return null; 
     } 

     MessageDTO messageDTO = MessageDTOHelper 
       .deserialize((ObjectMessage) msg); 

     return messageDTO; 
    } else { 

    } 
    return null; 
} 

Répondre

0

question actuelle est de savoir si vous avez besoin d'une communication synchrone ou asynchrone.

Je préférerais toujours asynchrone, et il semble de votre question qu'il n'y a pas besoin de communication synchrone ni dans votre cas. Cependant, s'il y a une raison pour synchrone alors vous êtes bloqué avec des files d'attente temporaires - vous devrez spécifier un intervalle de délai et vous rencontrerez des problèmes exprimés dans votre question. Si le programme A peut attendre, augmentez l'intervalle de délai d'attente bien que ce soit loin d'être optimal. Pour autant que je sache, il n'y a aucune possibilité pour le programme B de vérifier si A est toujours à l'écoute.

En cas de communication asynchrone, vous avez (au moins) deux options JMS:

  1. En utilisant différentes files d'attente de messages - Programme A envoie le message Queue1 et se termine, mais écoute (par exemple par le message Driven Bean) sur la file d'attente2 où le programme B met sa réponse quand c'est fait. Petit inconvénient est l'utilisation d'une paire supplémentaire de producteur et de consommateur.
  2. Utilisation de la même file d'attente de messages - Le programme A et le programme B envoient et reçoivent des messages sur la file d'attente 1, mais avec un sélecteur de message différent (voir description here). Fondamentalement, les sélecteurs de messages vont filtrer les messages pour un auditeur spécifique et ainsi permettre l'utilisation de la même file d'attente pour la communication bidirectionnelle.

Voir aussi:

+0

Salut @Miljen, malheureusement je suis coincé avec synchrone car la source de la requête doit afficher la réponse autant que possible.Je suis juste préoccupé par le fait que je dois augmenter le temps d'attente parce que la 3ème partie pourrait même répondre dans une minute et cela ralentirait le système quand j'ai des centaines d'utilisateurs simultanés. – czetsuya

+0

@czetsuya Je comprends. Cependant, vous ne bénéficierez toujours pas du maintien du programme A dans un état bloqué. Ma suggestion: A envoie le message avec un ID de corrélation, affiche la barre de progression (ou quelque chose de similaire) et termine. Lorsque le programme B répond avec l'ID de corrélation exacte, activez le programme A, supprimez la barre de progression et affichez la réponse. Sinon, vous risquez de manquer de ressources, car des centaines d'utilisateurs simultanés signifieraient des centaines de threads bloqués et en attente. –

0

Vous pourriez avoir un ajouter un en-tête à son message avec l'horodatage en cours + 5 secondes. Lorsque B reçoit la réponse de la 3ème partie, si l'heure actuelle est supérieure à l'en-tête, elle doit laisser tomber le résultat et ne pas envoyer. Vous pouvez utiliser la propriété de message jms time-to-live pour cela, bien que ce ne soit pas son but explicite.

Questions connexes