setAttributesIfNecessary(message, null); getMessagingTemplate().send(getErrorChannel(), buildErrorMessage(null, new ListenerExecutionFailedException("Message conversion failed", e, message)));
@Override public boolean isFatal(Throwable t) { if (t instanceof ListenerExecutionFailedException) { ListenerExecutionFailedException lefe = (ListenerExecutionFailedException) t; logger.error("Failed to process inbound message from queue " + lefe.getFailedMessage().getMessageProperties().getConsumerQueue() + "; failed message: " + lefe.getFailedMessage(), t); } return super.isFatal(t); }
@Bean public RabbitListenerErrorHandler throwANewException() { return (m, sm, e) -> { throw new RuntimeException("from error handler", e.getCause()); }; }
ConditionalRejectingErrorHandler eh = new ConditionalRejectingErrorHandler(t -> { if (t instanceof ListenerExecutionFailedException) { failed.set(((ListenerExecutionFailedException) t).getFailedMessage()); Exception e = new ListenerExecutionFailedException("foo", new MessageConversionException("bar"), new Message("".getBytes(), new MessageProperties())); try { assertSame(e, aradre.getCause()); e = new ListenerExecutionFailedException("foo", new MessageConversionException("bar", new AmqpRejectAndDontRequeueException("baz")), mock(Message.class)); eh.handleError(e);
setAttributesIfNecessary(message, null); AmqpInboundGateway.this.messagingTemplate.send(errorChannel, buildErrorMessage(null, new ListenerExecutionFailedException("Message conversion failed", e, message)));
if (ex.getCause() instanceof NoSuchMethodException) { throw new FatalListenerExecutionException("Invalid listener", ex);
@Override public boolean isFatal(Throwable t) { Throwable cause = t.getCause(); while (cause instanceof MessagingException && !(cause instanceof org.springframework.messaging.converter.MessageConversionException) && !(cause instanceof MethodArgumentResolutionException)) { cause = cause.getCause(); } if (t instanceof ListenerExecutionFailedException && isCauseFatal(cause)) { if (this.logger.isWarnEnabled()) { this.logger.warn( "Fatal message conversion error; message rejected; " + "it will be dropped or routed to a dead letter exchange, if so configured: " + ((ListenerExecutionFailedException) t).getFailedMessage()); } return true; } return false; }
/** * @param e The Exception. * @param message The failed message. * @return If 'e' is of type {@link ListenerExecutionFailedException} - return 'e' as it is, otherwise wrap it to * {@link ListenerExecutionFailedException} and return. */ protected ListenerExecutionFailedException wrapToListenerExecutionFailedExceptionIfNeeded(Exception e, Message message) { if (!(e instanceof ListenerExecutionFailedException)) { // Wrap exception to ListenerExecutionFailedException. return new ListenerExecutionFailedException("Listener threw exception", e, message); } return (ListenerExecutionFailedException) e; }
if (ex.getCause() instanceof NoSuchMethodException) { throw new FatalListenerExecutionException("Invalid listener", ex);
@Override public boolean isFatal(Throwable t) { Throwable cause = t.getCause(); while (cause instanceof MessagingException && !(cause instanceof org.springframework.messaging.converter.MessageConversionException) && !(cause instanceof MethodArgumentResolutionException)) { cause = cause.getCause(); } if (t instanceof ListenerExecutionFailedException && isCauseFatal(cause)) { if (this.logger.isWarnEnabled()) { this.logger.warn( "Fatal message conversion error; message rejected; " + "it will be dropped or routed to a dead letter exchange, if so configured: " + ((ListenerExecutionFailedException) t).getFailedMessage()); } return true; } return false; }
/** * @param e The Exception. * @param message The failed message. * @return If 'e' is of type {@link ListenerExecutionFailedException} - return 'e' as it is, otherwise wrap it to * {@link ListenerExecutionFailedException} and return. */ protected ListenerExecutionFailedException wrapToListenerExecutionFailedExceptionIfNeeded(Exception e, Message message) { if (!(e instanceof ListenerExecutionFailedException)) { // Wrap exception to ListenerExecutionFailedException. return new ListenerExecutionFailedException("Listener threw exception", e, message); } return (ListenerExecutionFailedException) e; }
returnOrThrow(amqpMessage, channel, message, e.getCause(), e);
@Override public void handleError(Throwable t) { log(t); if (!this.causeChainContainsARADRE(t) && this.exceptionStrategy.isFatal(t)) { if (this.discardFatalsWithXDeath && t instanceof ListenerExecutionFailedException) { Message failed = ((ListenerExecutionFailedException) t).getFailedMessage(); if (failed != null) { List<Map<String, ?>> xDeath = failed.getMessageProperties().getXDeathHeader(); if (xDeath != null && xDeath.size() > 0) { this.logger.error("x-death header detected on a message with a fatal exception; " + "perhaps requeued from a DLQ? - discarding: " + failed); throw new ImmediateAcknowledgeAmqpException("Fatal and x-death present"); } } } throw new AmqpRejectAndDontRequeueException("Error Handler converted exception to fatal", t); } }
@Override public void recover(Message message, Throwable cause) { if (this.logger.isWarnEnabled()) { this.logger.warn("Retries exhausted for message " + message, cause); } throw new ListenerExecutionFailedException("Retry Policy Exhausted", new AmqpRejectAndDontRequeueException(cause), message); }
returnOrThrow(amqpMessage, channel, message, e.getCause(), e);
@Override public void handleError(Throwable t) { log(t); if (!this.causeChainContainsARADRE(t) && this.exceptionStrategy.isFatal(t)) { if (this.discardFatalsWithXDeath && t instanceof ListenerExecutionFailedException) { Message failed = ((ListenerExecutionFailedException) t).getFailedMessage(); if (failed != null) { List<Map<String, ?>> xDeath = failed.getMessageProperties().getXDeathHeader(); if (xDeath != null && xDeath.size() > 0) { this.logger.error("x-death header detected on a message with a fatal exception; " + "perhaps requeued from a DLQ? - discarding: " + failed); throw new ImmediateAcknowledgeAmqpException("Fatal and x-death present"); } } } throw new AmqpRejectAndDontRequeueException("Error Handler converted exception to fatal", t); } }
@Override public void recover(Message message, Throwable cause) { if (this.logger.isWarnEnabled()) { this.logger.warn("Retries exhausted for message " + message, cause); } throw new ListenerExecutionFailedException("Retry Policy Exhausted", new AmqpRejectAndDontRequeueException(cause), message); }
@Test public void exceptionInListenerBadReturnExceptionSetting() { org.springframework.amqp.core.Message message = MessageTestUtils.createTextMessage("foo"); Channel channel = mock(Channel.class); MessagingMessageListenerAdapter listener = getSimpleInstance("fail", true, String.class); try { listener.onMessage(message, channel); fail("Should have thrown an exception"); } catch (ListenerExecutionFailedException ex) { assertEquals(IllegalArgumentException.class, ex.getCause().getClass()); assertEquals("Expected test exception", ex.getCause().getMessage()); } catch (Exception ex) { fail("Should not have thrown an " + ex.getClass().getSimpleName()); } }
/** * Invoke the handler, wrapping any exception to a {@link ListenerExecutionFailedException} * with a dedicated error message. * @param amqpMessage the raw message. * @param channel the channel. * @param message the messaging message. * @return the result of invoking the handler. */ private InvocationResult invokeHandler(org.springframework.amqp.core.Message amqpMessage, Channel channel, Message<?> message) { try { return this.handlerAdapter.invoke(message, amqpMessage, channel); } catch (MessagingException ex) { throw new ListenerExecutionFailedException(createMessagingErrorMessage("Listener method could not " + "be invoked with the incoming message", message.getPayload()), ex, amqpMessage); } catch (Exception ex) { throw new ListenerExecutionFailedException("Listener method '" + this.handlerAdapter.getMethodAsString(message.getPayload()) + "' threw exception", ex, amqpMessage); } }
@Test public void exceptionInListener() { org.springframework.amqp.core.Message message = MessageTestUtils.createTextMessage("foo"); Channel channel = mock(Channel.class); MessagingMessageListenerAdapter listener = getSimpleInstance("fail", String.class); try { listener.onMessage(message, channel); fail("Should have thrown an exception"); } catch (ListenerExecutionFailedException ex) { assertEquals(IllegalArgumentException.class, ex.getCause().getClass()); assertEquals("Expected test exception", ex.getCause().getMessage()); } catch (Exception ex) { fail("Should not have thrown an " + ex.getClass().getSimpleName()); } }