Spring MDP - comment l'arrêter en cas de mauvais message
-
12-12-2019 - |
Question
J'ai un Spring MDP implémenté à l'aide de Spring DefaultMessageListenderContainer
écoute d'une file d'attente d'entrée sur WebSphere MQ v7.1.Si un mauvais message arrive (cela provoque RuntimeException
), ce qui se passe actuellement, c'est que la transaction est annulée et le message est remis dans la file d'attente.Cependant le MDP entre dans une boucle infinie.
Question 1:Pour mes besoins, j'aimerais pouvoir arrêter le traitement dès qu'il voit un mauvais message.Aucune nouvelle tentative n’est nécessaire.Est-il possible d'arrêter correctement l'écouteur de messages au cas où il verrait un mauvais message (par opposition à un message brut System.exit()
ou des méthodes de ce genre) ?Je n’aime vraiment pas que ça entre dans une boucle infinie.
Modifier:
Question 2:Existe-t-il un moyen d'arrêter ou de suspendre le conteneur d'écoute pour arrêter le traitement ultérieur des messages ?
La solution 3
J'ai résolu le problème de la manière suivante, je ne sais pas si c'est la meilleure façon, mais cela fonctionne.
- MDP implémente ApplicationContextAware ;Je maintiens également un état d'écoute (énumération avec les valeurs OPEN, CLOSE, ERROR) Fragment de code MDP ci-dessous :
//context private ConfigurableApplicationContext applicationContext; //listener state private ListenerState listenerState = ListenerState.OPEN; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = (ConfigurableApplicationContext) applicationContext; } //onMessage method public void processMessages(....) { try { process(...); } catch (Throwable t) { listenerState = ListenerState.ERROR; throw new RuntimeException(...); } } @Override public void stopContext() { applicationContext.stop(); }
- Dans le principal Java qui charge le contexte Spring, je fais ceci :
//check for errors for exit Listener listener = (Listener)context.getBean("listener"); listenerContainer listenerContainer = (ListenerContainer)context.getBean("listenerContainer"); try { while(true) { Thread.sleep(1000); //sleep for 1 sec if(!listener.getListenerState().equals(ListenerState.OPEN)) { listener.stopContext(); listenerContainer.stop(); System.exit(1); }> } } catch (InterruptedException e) { throw new RuntimeException(e); }
Autres conseils
La manière habituelle de traiter cela consiste à créer une file d’attente d’erreurs et, lorsque vous voyez un mauvais message, à le placer dans la file d’attente d’erreurs.
Certains systèmes gèrent cela pour vous, comme IBM MQ Series.Il vous suffit de configurer la file d'attente des erreurs et le nombre de tentatives souhaitées et il l'y placera.
Un administrateur examinera ensuite ces files d'attente et prendra les mesures appropriées sur les messages qui s'y trouvent (c'est-à-direcorrigez-les et soumettez-les à nouveau)
En fait, System.exit()
c'est trop brutal et...ne fonctionnera pas.La nouvelle tentative des messages ayant échoué est gérée du côté du courtier (WMQ), de sorte que le message sera retransmis une fois que vous redémarrerez votre application.
Le problème que vous décrivez s'appelle message empoisonné et doit être géré du côté du courtier.Cela semble être décrit dans Gestion des messages empoisonnés dans le manuel WMQ et dans Comment WebSphere Application Server gère les messages incohérents.