GH-9297: Improve ImapIdleChannelAdapter.callIdle() for cause

Fixes: #9297

For a normal `jakarta.mail.StoreClosedException: * BYE Jakarta Mail Exception: java.net.SocketException: Connection reset`
 the `ImapIdleChannelAdapter.callIdle()` results in a resubmission (and reconnection)
 with logging 'Failed to execute IDLE task. Will attempt to resubmit in 10000 milliseconds.'`
However, when `selectorExpression` is in used and that one is based on mail `Message` object,
we may fail with `FolderClosedException` which is wrapped to the `SpelEvaluationException` and some
other stack traces.
So, `jakarta.mail.MessagingException` might be deep in the cause chain.

* Fix `ImapIdleChannelAdapter` via introducing `getJakartaMailMessagingExceptionFromCause()` utility
method which searches for the `jakarta.mail.MessagingException` in cause chain.
* Rework `ImapIdleChannelAdapter.callIdle()` logic to rely on this new method

**Auto-cherry-pick to `6.3.x` & `6.2.x`**
This commit is contained in:
Artem Bilan
2024-07-02 15:38:07 -04:00
parent 7974f9c5b6
commit 272fcd044d

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,6 +36,7 @@ import org.springframework.integration.mail.event.MailIntegrationEvent;
import org.springframework.integration.transaction.IntegrationResourceHolder;
import org.springframework.integration.transaction.IntegrationResourceHolderSynchronization;
import org.springframework.integration.transaction.TransactionSynchronizationFactory;
import org.springframework.lang.Nullable;
import org.springframework.messaging.MessagingException;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
@@ -200,22 +201,24 @@ public class ImapIdleChannelAdapter extends MessageProducerSupport implements Be
}
catch (Exception ex) {
publishException(ex);
if (this.shouldReconnectAutomatically
&& ex.getCause() instanceof jakarta.mail.MessagingException messagingException) {
if (this.shouldReconnectAutomatically) {
jakarta.mail.MessagingException messagingException =
getJakartaMailMessagingExceptionFromCause(ex.getCause());
//run again after a delay
logger.info(messagingException,
() -> "Failed to execute IDLE task. Will attempt to resubmit in "
+ this.reconnectDelay + " milliseconds.");
delayNextIdleCall();
}
else {
logger.warn(ex,
"Failed to execute IDLE task. " +
"Won't resubmit since not a 'shouldReconnectAutomatically' " +
"or not a 'jakarta.mail.MessagingException'");
break;
if (messagingException != null) {
//run again after a delay
logger.info(messagingException,
() -> "Failed to execute IDLE task. Will attempt to resubmit in "
+ this.reconnectDelay + " milliseconds.");
delayNextIdleCall();
continue;
}
}
logger.warn(ex,
"Failed to execute IDLE task. " +
"Won't resubmit since not a 'shouldReconnectAutomatically' " +
"or not a 'jakarta.mail.MessagingException'");
break;
}
}
}
@@ -256,6 +259,21 @@ public class ImapIdleChannelAdapter extends MessageProducerSupport implements Be
}
}
@Nullable
private static jakarta.mail.MessagingException getJakartaMailMessagingExceptionFromCause(Throwable cause) {
if (cause == null) {
return null;
}
if (cause instanceof jakarta.mail.MessagingException messagingException) {
return messagingException;
}
Throwable nextCause = cause.getCause();
if (cause == nextCause) {
return null;
}
return getJakartaMailMessagingExceptionFromCause(nextCause);
}
private class MessageSender implements Consumer<Object> {
MessageSender() {