Распространенной ошибкой является допущение, что команда IDLE будет публиковать обновления бесконечно долго.Однако RFC 2177 , который определяет состояния расширения IDLE:
Сервер МОЖЕТ считать клиента неактивным, если на нем запущена команда IDLE, и если на таком сервереТайм-аут неактивности МОЖЕТ неявно отключить клиента в конце периода его ожидания.Из-за этого клиентам, использующим IDLE, рекомендуется прекратить IDLE и переиздавать его, по крайней мере, каждые 29 минут, чтобы избежать выхода из системы.Это по-прежнему позволяет клиенту получать немедленные обновления почтового ящика, даже если ему требуется только «опрос» с интервалом в полчаса.
В частности, GMail имеет гораздо меньшее время ожидания, как вы сказали, около 10 минут.
Нам просто нужно повторять команду IDLE каждые 9 минут или около того, чтобы она работала.API javax.mail
не имеют возможности установить тайм-аут для команды IDLE, поэтому вам понадобится второй поток, чтобы обойти это.
Первый подход состоит в том, чтобы второй поток прерывал первый,обработка исключения и игнорирование его.Это, однако, не позволило бы чистым способом закрыть поток, поэтому я не буду рекомендовать его.Намного более чистый способ - заставить второй поток выдать команду NOOP на сервер.Это вообще ничего не делает, но достаточно для прерывания IDLE и его переиздания.
Здесь приведен код для этого:
public void startListening(IMAPFolder imapFolder) {
// We need to create a new thread to keep alive the connection
Thread t = new Thread(
new KeepAliveRunnable(imapFolder), "IdleConnectionKeepAlive"
);
t.start();
while (!Thread.interrupted()) {
LOGGER.debug("Starting IDLE");
try {
imapFolder.idle();
} catch (MessagingException e) {
LOGGER.warn("Messaging exception during IDLE", e);
throw new RuntimeException(e);
}
}
// Shutdown keep alive thread
if (t.isAlive()) {
t.interrupt();
}
}
/**
* Runnable used to keep alive the connection to the IMAP server
*
* @author Juan Martín Sotuyo Dodero <jmsotuyo@monits.com>
*/
private static class KeepAliveRunnable implements Runnable {
private static final long KEEP_ALIVE_FREQ = 300000; // 5 minutes
private IMAPFolder folder;
public KeepAliveRunnable(IMAPFolder folder) {
this.folder = folder;
}
@Override
public void run() {
while (!Thread.interrupted()) {
try {
Thread.sleep(KEEP_ALIVE_FREQ);
// Perform a NOOP just to keep alive the connection
LOGGER.debug("Performing a NOOP to keep alvie the connection");
folder.doCommand(new IMAPFolder.ProtocolCommand() {
public Object doCommand(IMAPProtocol p)
throws ProtocolException {
p.simpleCommand("NOOP", null);
return null;
}
});
} catch (InterruptedException e) {
// Ignore, just aborting the thread...
} catch (MessagingException e) {
// Shouldn't really happen...
LOGGER.warn("Unexpected exception while keeping alive the IDLE connection", e);
}
}
}
}