Skip to content

Commit c6ecd90

Browse files
apinskeartembilan
authored andcommitted
Fix IMAP race condition around idle()
`IMAPFolder.idle()` by default keeps idle-ing after each response. We don't need that, because we want to fetch the new mails immediately (over the same connection). To make `idle()` not keep on going, we called `folder.isOpen()` which in most cases makes `idle()` stop by calling `noop()` internally (to keep the connection alive) which leads to the current `idle()`-call being canceled. The problem this commits addresses is that the call to `noop()` only happens if there were no calls in the last second. There is a check for that in `com.sun.mail.imap.IMAPFolder.keepConnectionAlive`. So if a new message appears less then a second after idle started, we will miss it. This new way interrupts `idle()` more often than before, e.g. when there is an expunge-message (i.e. a message was deleted), which we don't care about. But the subsequent `receive()` in IdleTask will simply get no messages and then turn around and start idle-ing again. **Cherry-pick to `5.3.x` & `master`** # Conflicts: # spring-integration-mail/src/main/java/org/springframework/integration/mail/ImapMailReceiver.java # spring-integration-mail/src/test/java/org/springframework/integration/mail/ImapMailReceiverTests.java
1 parent d6a4422 commit c6ecd90

File tree

2 files changed

+7
-31
lines changed

2 files changed

+7
-31
lines changed

spring-integration-mail/src/main/java/org/springframework/integration/mail/ImapMailReceiver.java

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -27,9 +27,6 @@
2727
import javax.mail.Folder;
2828
import javax.mail.Message;
2929
import javax.mail.MessagingException;
30-
import javax.mail.event.MessageCountAdapter;
31-
import javax.mail.event.MessageCountEvent;
32-
import javax.mail.event.MessageCountListener;
3330
import javax.mail.search.AndTerm;
3431
import javax.mail.search.FlagTerm;
3532
import javax.mail.search.NotTerm;
@@ -54,15 +51,14 @@
5451
* @author Oleg Zhurakousky
5552
* @author Gary Russell
5653
* @author Artem Bilan
54+
* @author Alexander Pinske
5755
*/
5856
public class ImapMailReceiver extends AbstractMailReceiver {
5957

6058
private static final int DEFAULT_CANCEL_IDLE_INTERVAL = 120000;
6159

6260
private static final String PROTOCOL = "imap";
6361

64-
private final MessageCountListener messageCountListener = new SimpleMessageCountListener();
65-
6662
private final IdleCanceler idleCanceler = new IdleCanceler();
6763

6864
private boolean shouldMarkMessagesAsRead = true;
@@ -188,16 +184,14 @@ public void waitForNewMessages() throws MessagingException {
188184
else if (!folder.getPermanentFlags().contains(Flags.Flag.RECENT) && searchForNewMessages().length > 0) {
189185
return;
190186
}
191-
imapFolder.addMessageCountListener(this.messageCountListener);
192187
try {
193188
this.pingTask = this.scheduler.schedule(this.idleCanceler,
194189
new Date(System.currentTimeMillis() + this.cancelIdleInterval));
195190
if (imapFolder.isOpen()) {
196-
imapFolder.idle();
191+
imapFolder.idle(true);
197192
}
198193
}
199194
finally {
200-
imapFolder.removeMessageCountListener(this.messageCountListener);
201195
if (this.pingTask != null) {
202196
this.pingTask.cancel(true);
203197
}
@@ -276,25 +270,6 @@ public void run() {
276270

277271
}
278272

279-
/**
280-
* Callback used for handling the event-driven idle response.
281-
*/
282-
private static class SimpleMessageCountListener extends MessageCountAdapter {
283-
284-
SimpleMessageCountListener() {
285-
}
286-
287-
@Override
288-
public void messagesAdded(MessageCountEvent event) {
289-
Message[] messages = event.getMessages();
290-
if (messages.length > 0) {
291-
// this will return the flow to the idle call
292-
messages[0].getFolder().isOpen();
293-
}
294-
}
295-
296-
}
297-
298273
private class DefaultSearchTermStrategy implements SearchTermStrategy {
299274

300275
DefaultSearchTermStrategy() {

spring-integration-mail/src/test/java/org/springframework/integration/mail/ImapMailReceiverTests.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -92,6 +92,7 @@
9292
* @author Oleg Zhurakousky
9393
* @author Gary Russell
9494
* @author Artem Bilan
95+
* @author Alexander Pinske
9596
*/
9697
@RunWith(SpringRunner.class)
9798
@ContextConfiguration(
@@ -609,7 +610,7 @@ public void testNoInitialIdleDelayWhenRecentNotSupported() throws Exception {
609610
Thread.sleep(300);
610611
shouldFindMessagesCounter.set(1);
611612
return null;
612-
}).given(folder).idle();
613+
}).given(folder).idle(true);
613614

614615
adapter.start();
615616

@@ -669,7 +670,7 @@ public void testInitialIdleDelayWhenRecentIsSupported() throws Exception {
669670
idles.countDown();
670671
Thread.sleep(1000);
671672
return null;
672-
}).given(folder).idle();
673+
}).given(folder).idle(true);
673674

674675
adapter.start();
675676

0 commit comments

Comments
 (0)