Skip to content

Commit

Permalink
Fix retry mechanism for the DocFormatter and PdfConverter (#126)
Browse files Browse the repository at this point in the history
* Fix retry mechanism for the DocFormatter and PdfConverter
  • Loading branch information
Ilya-c committed Feb 10, 2020
1 parent 5ac9292 commit a4cda7b
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 28 deletions.
1 change: 1 addition & 0 deletions core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ configure(core) {
compile(group: "com.jayway.jsonpath", name: "json-path", version: "2.1.0")

testCompile(group: 'junit', name: 'junit', version: '4.5')
testCompile group: 'org.mockito', name: 'mockito-core', version: '3.2.4'
testCompile(group: 'org.hsqldb', name: 'hsqldb', version: '2.3.3')
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import com.sun.star.text.*;
import com.sun.star.util.XReplaceable;
import com.sun.star.util.XSearchDescriptor;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -74,7 +75,7 @@ public class DocFormatter extends AbstractFormatter {

public DocFormatter(FormatterFactoryInput formatterFactoryInput, OfficeIntegrationAPI officeIntegration) {
super(formatterFactoryInput);
Preconditions.checkNotNull("\"officeIntegration\" parameter can not be null", officeIntegration);
Preconditions.checkNotNull(officeIntegration, "\"officeIntegration\" parameter can not be null");

this.officeIntegration = officeIntegration;
supportedOutputTypes.add(ReportOutputType.doc);
Expand All @@ -84,21 +85,33 @@ public DocFormatter(FormatterFactoryInput formatterFactoryInput, OfficeIntegrati
public void renderDocument() {
try {
doCreateDocument(reportTemplate.getOutputType(), outputStream);
} catch (Exception e) {//just try again if any exceptions occurred
log.warn(String.format("An error occurred while generating doc report [%s]. System will retry to generate report again.", reportTemplate.getDocumentName()), e);
} catch (Exception e) {
retryDocumentCreation(reportTemplate.getOutputType(), outputStream, e, 0);
}
}

for (int i = 0; i < officeIntegration.getCountOfRetry(); i++) {
try {
doCreateDocument(reportTemplate.getOutputType(), outputStream);
return;
} catch (NoFreePortsException e1) {
if (e instanceof NoFreePortsException) {
throw (NoFreePortsException) e;
}
}
protected void retryDocumentCreation(final ReportOutputType outputType,
final OutputStream outputStream,
Exception lastTryException,
int currentAttempt) {
if (officeIntegration.getCountOfRetry() != 0 && currentAttempt < officeIntegration.getCountOfRetry()) {
log.warn(String.format("An error occurred while generating doc report [%s]. " +
"System will retry to generate report again (Current attempt: %s).",
reportTemplate.getDocumentName(), currentAttempt + 1));

log.debug(ExceptionUtils.getStackTrace(lastTryException));
try {
Thread.sleep(officeIntegration.getRetryIntervalMs());

doCreateDocument(outputType, outputStream);
} catch (Exception e) {
retryDocumentCreation(reportTemplate.getOutputType(), outputStream, e, ++currentAttempt);
}
} else {
if (lastTryException instanceof NoFreePortsException)
throw (NoFreePortsException) lastTryException;

throw wrapWithReportingException("An error occurred while generating doc report.", e);
throw wrapWithReportingException("An error occurred while generating doc report. All attempts failed", lastTryException);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import com.haulmont.yarg.exception.OpenOfficeException;
import com.sun.star.comp.helper.BootstrapException;

import java.lang.RuntimeException;
import java.util.Set;
import java.util.concurrent.*;

Expand All @@ -31,8 +30,9 @@ public class OfficeIntegration implements OfficeIntegrationAPI {
protected String openOfficePath;
protected String temporaryDirPath;
protected Integer[] openOfficePorts;
protected Integer timeoutInSeconds = 60;
protected int countOfRetry = 2;
protected Integer timeoutInSeconds = DEFAULT_TIMEOUT;
protected int countOfRetry = DEFAULT_RETRY_COUNT;
protected int retryIntervalMs = DEFAULT_RETRY_INTERVAL;
protected Boolean displayDeviceAvailable = false;

public OfficeIntegration(String openOfficePath, Integer... ports) {
Expand All @@ -58,6 +58,14 @@ public void setCountOfRetry(int countOfRetry) {
this.countOfRetry = countOfRetry;
}

public int getRetryIntervalMs() {
return retryIntervalMs;
}

public void setRetryIntervalMs(int retryIntervalMs) {
this.retryIntervalMs = retryIntervalMs;
}

public String getTemporaryDirPath() {
return temporaryDirPath;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,19 @@
package com.haulmont.yarg.formatters.impl.doc.connector;

public interface OfficeIntegrationAPI {

int DEFAULT_RETRY_COUNT = 2;
int DEFAULT_RETRY_INTERVAL = 1000;
int DEFAULT_TIMEOUT = 60;

String getTemporaryDirPath();

Integer getTimeoutInSeconds();

int getCountOfRetry();

int getRetryIntervalMs();

Boolean isDisplayDeviceAvailable();

void runTaskWithTimeout(OfficeTask officeTask, int timeoutInSeconds) throws NoFreePortsException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.haulmont.yarg.formatters.impl.doc.connector.OfficeResourceProvider;
import com.haulmont.yarg.formatters.impl.doc.connector.OfficeTask;
import com.sun.star.lang.XComponent;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -46,19 +47,33 @@ public void convertToPdf(FileType fileType, final byte[] documentBytes, final Ou
try {
doConvertToPdf(convertPattern, documentBytes, outputStream);
} catch (Exception e) {
log.warn("An error occurred while converting xls to pdf. System will retry to generate report again.", e);
for (int i = 0; i < officeIntegration.getCountOfRetry(); i++) {
try {
doConvertToPdf(convertPattern, documentBytes, outputStream);
return;
} catch (NoFreePortsException e1) {
if (e instanceof NoFreePortsException) {
throw (NoFreePortsException) e;
}
}
retryPdfConversion(convertPattern, documentBytes, outputStream, e, 0);
}
}

protected void retryPdfConversion(final String pattern,
final byte[] documentBytes,
final OutputStream outputStream,
Exception lastTryException,
int retriesCount) {
if (officeIntegration.getCountOfRetry() != 0 && retriesCount < officeIntegration.getCountOfRetry()) {
log.warn(String.format("An error occurred while converting to pdf. " +
"System will retry to convert again (Current attempt: %s).", retriesCount + 1));
log.debug(ExceptionUtils.getStackTrace(lastTryException));
try {
Thread.sleep(officeIntegration.getRetryIntervalMs());

doConvertToPdf(pattern, documentBytes, outputStream);
} catch (InterruptedException e) {
throw new ReportingException("Unable to convert to pdf. Retry interrupted", e);
} catch (Exception e) {
retryPdfConversion(pattern, documentBytes, outputStream, e, ++retriesCount);
}
} else {
if (lastTryException instanceof NoFreePortsException)
throw (NoFreePortsException) lastTryException;

throw new ReportingException("An error occurred while converting xls to pdf.", e);
throw new ReportingException("Unable to convert to pdf. All attempts failed", lastTryException);
}
}

Expand Down
45 changes: 44 additions & 1 deletion core/modules/core/test/smoketest/DocSpecificTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
import com.haulmont.yarg.formatters.ReportFormatter;
import com.haulmont.yarg.formatters.factory.DefaultFormatterFactory;
import com.haulmont.yarg.formatters.factory.FormatterFactoryInput;
import com.haulmont.yarg.formatters.impl.DocFormatter;
import com.haulmont.yarg.formatters.impl.doc.connector.OfficeIntegration;
import com.haulmont.yarg.formatters.impl.doc.connector.OfficeIntegrationAPI;
import com.haulmont.yarg.formatters.impl.doc.connector.OfficeTask;
import com.haulmont.yarg.formatters.impl.xls.PdfConverter;
import com.haulmont.yarg.formatters.impl.xls.PdfConverterImpl;
import com.haulmont.yarg.structure.BandData;
import com.haulmont.yarg.structure.BandOrientation;
import com.haulmont.yarg.structure.ReportFieldFormat;
Expand All @@ -20,11 +25,15 @@
import java.util.HashMap;
import java.util.concurrent.CountDownLatch;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.*;

/**
* @author degtyarjov
* @version $Id$
*/
public class DocSpecificTest extends AbstractFormatSpecificTest{
public class DocSpecificTest extends AbstractFormatSpecificTest {
@Test
public void testTableOdt() throws Exception {
BandData root = new BandData("Root");
Expand Down Expand Up @@ -182,4 +191,38 @@ public void run() {
System.out.println();
}

@Test
public void testRetryCount() throws Exception {
BandData root = createRootBand();
FormatterFactoryInput formatterFactoryInput = new FormatterFactoryInput("doc", root,
new ReportTemplateImpl("", "./modules/core/test/smoketest/test.doc",
"./modules/core/test/smoketest/test.doc", ReportOutputType.doc), null);
OfficeIntegrationAPI officeIntegrationApiMock = createOfficeIntegrationApiMock(5);
DocFormatter docFormatter = new DocFormatter(formatterFactoryInput, officeIntegrationApiMock);

// Check that in case of exception 'runTaskWithTimeout' will execute exactly retriesCount + 1 times
try {
docFormatter.renderDocument();
} catch (Exception e) {
verify(officeIntegrationApiMock, times(6))
.runTaskWithTimeout((OfficeTask) any(), anyInt());
}

officeIntegrationApiMock = createOfficeIntegrationApiMock(4);
PdfConverterImpl pdfConverter = new PdfConverterImpl(officeIntegrationApiMock);
try {
pdfConverter.convertToPdf(PdfConverter.FileType.DOCUMENT, null, null);
} catch (Exception e) {
verify(officeIntegrationApiMock, times(5))
.runTaskWithTimeout((OfficeTask) any(), anyInt());
}
}

protected OfficeIntegrationAPI createOfficeIntegrationApiMock(int retryCount) {
OfficeIntegrationAPI mOfficeIntegrationApi = mock(OfficeIntegrationAPI.class);
doThrow(RuntimeException.class).when(mOfficeIntegrationApi).runTaskWithTimeout((OfficeTask) any(), anyInt());
when(mOfficeIntegrationApi.getCountOfRetry()).thenReturn(retryCount);
when(mOfficeIntegrationApi.getRetryIntervalMs()).thenReturn(300);
return mOfficeIntegrationApi;
}
}

0 comments on commit a4cda7b

Please sign in to comment.