package mireka.transmission.queue;
import mireka.transmission.LocalMailSystemException;
import mireka.transmission.Mail;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class MailProcessingTask implements Runnable {
private final Logger logger =
LoggerFactory.getLogger(MailProcessingTask.class);
private final ScheduleFileDirQueue parentQueue;
private final MailName mailName;
private final FileDirStore dir;
private final MailProcessorFactory mailProcessorFactory;
private DateTime dateOfFirstFailedAttempt = null;
public MailProcessingTask(ScheduleFileDirQueue parentQueue,
FileDirStore store, MailProcessorFactory mailProcessorFactory,
MailName mailName) {
this.parentQueue = parentQueue;
this.dir = store;
this.mailProcessorFactory = mailProcessorFactory;
this.mailName = mailName;
}
@Override
public void run() {
logger.debug("Processing mail named " + mailName + "...");
Mail mail;
try {
mail = dir.read(mailName);
} catch (QueueStorageException e) {
logger.error("Cannot read mail. Mail will remain in the queue, "
+ "but it won't be retried until the "
+ "next server restart. Likely it is "
+ "best to remove it manually.", e);
return;
}
MailProcessor mailProcessor = mailProcessorFactory.create(mail);
try {
mailProcessor.run();
} catch (LocalMailSystemException e) {
if (e.errorStatus().shouldRetry())
handleTemporaryException(e);
else
handlePermanentException(e);
return;
}
try {
dir.delete(mailName);
} catch (QueueStorageException e) {
logger.error("Mail was processed sucessfully, "
+ "but it cannot be removed. "
+ "Mail will remain in the queue, "
+ "it will be submitted to processing again "
+ "following the next server restart. "
+ "It should be deleted manually before that.", e);
return;
}
logger.debug("Mail processing is completed.");
}
private void handleTemporaryException(LocalMailSystemException e) {
if (dateOfFirstFailedAttempt == null)
dateOfFirstFailedAttempt = new DateTime();
if (taskHasBeenFailingForTooMuchTime()) {
logger.error("A transient local failure prevented processing "
+ "the mail. Processing of this mail is "
+ "unsuccussful for a long time. "
+ "The first attempt was on " + dateOfFirstFailedAttempt
+ ". This was the last attempt, moving the mail "
+ "to the error directory...", e);
try {
dir.moveToErrorDir(mailName);
logger.debug("Mail is moved to the error directory.");
} catch (QueueStorageException e1) {
logger.error("Cannot move mail to error directory. "
+ "Mail will remain in the queue, "
+ "but it won't be retried until the "
+ "next server restart. Likely it is "
+ "best to remove it manually.", e1);
return;
}
} else {
logger.error("A transient local failure prevented processing "
+ "mail. Mail will remain in the queue unmodified. "
+ " Processing of the mail will be retried "
+ "5 minutes later.", e);
parentQueue.rescheduleFailedTask(this);
return;
}
}
private boolean taskHasBeenFailingForTooMuchTime() {
DateTime deadline = dateOfFirstFailedAttempt.plusDays(1);
return deadline.isBeforeNow();
}
private void handlePermanentException(LocalMailSystemException e) {
logger.error(
"A permanent local faulure prevented processing the mail. "
+ "Moving the mail to the error directory...", e);
try {
dir.moveToErrorDir(mailName);
logger.debug("Mail is moved to the error directory.");
} catch (QueueStorageException e1) {
logger.error("Cannot move mail to error directory. "
+ "Mail will remain in the queue, "
+ "but it won't be retried until the "
+ "next server restart. Likely it is "
+ "best to remove it manually.", e1);
return;
}
}
}