Skip to content

Commit

Permalink
reworking wait job
Browse files Browse the repository at this point in the history
  • Loading branch information
Eric Kerwin committed May 25, 2021
1 parent a1cf424 commit f3d128b
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 90 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ buildscript {
project.ext.moduleName = 'com.synopsys.integration.integration-common'
project.ext.javaUseAutoModuleName = 'true'

version = '24.3.1-SNAPSHOT'
version = '25.0.0-SNAPSHOT'
description = 'The base library for all other integration libraries to encompass and export common dependencies and code.'

apply plugin: 'com.synopsys.integration.library'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* integration-common
*
* Copyright (c) 2021 Synopsys, Inc.
*
* Use subject to the terms and conditions of the Synopsys End User Software License and Maintenance Agreement. All rights reserved worldwide.
*/
package com.synopsys.integration.exception;

public class IntegrationTimeoutException extends IntegrationException {
public IntegrationTimeoutException() {
}

public IntegrationTimeoutException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}

public IntegrationTimeoutException(String message, Throwable cause) {
super(message, cause);
}

public IntegrationTimeoutException(String message) {
super(message);
}

public IntegrationTimeoutException(Throwable cause) {
super(cause);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* integration-common
*
* Copyright (c) 2021 Synopsys, Inc.
*
* Use subject to the terms and conditions of the Synopsys End User Software License and Maintenance Agreement. All rights reserved worldwide.
*/
package com.synopsys.integration.wait;

import com.synopsys.integration.exception.IntegrationException;
import com.synopsys.integration.exception.IntegrationTimeoutException;

public class BooleanWaitJobCompleter implements WaitJobCompleter<Boolean> {
@Override
public Boolean complete() throws IntegrationException {
return true;
}

@Override
public Boolean handleTimeout() throws IntegrationTimeoutException {
return false;
}

}
76 changes: 37 additions & 39 deletions src/main/java/com/synopsys/integration/wait/WaitJob.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,68 +7,66 @@
*/
package com.synopsys.integration.wait;

import com.synopsys.integration.exception.IntegrationException;
import com.synopsys.integration.log.IntLogger;
import org.apache.commons.lang3.time.DurationFormatUtils;

import java.time.Duration;
import java.util.function.Supplier;

public class WaitJob {
private WaitJobConfig waitJobConfig;

public static WaitJob create(IntLogger intLogger, long timeoutInSeconds, long startTime, int waitIntervalInSeconds, WaitJobTask waitJobTask) {
return new WaitJob(new WaitJobConfig(intLogger, timeoutInSeconds, startTime, waitIntervalInSeconds, waitJobTask));
}

public static WaitJob create(IntLogger intLogger, long timeoutInSeconds, Supplier<Long> startTimeSupplier, int waitIntervalInSeconds, WaitJobTask waitJobTask) {
return new WaitJob(new WaitJobConfig(intLogger, timeoutInSeconds, startTimeSupplier, waitIntervalInSeconds, waitJobTask));
}
import org.apache.commons.lang3.time.DurationFormatUtils;

public static WaitJob createUsingSystemTimeWhenInvoked(IntLogger intLogger, long timeoutInSeconds, int waitIntervalInSeconds, WaitJobTask waitJobTask) {
return new WaitJob(new WaitJobConfig(intLogger, timeoutInSeconds, WaitJobConfig.CURRENT_TIME_SUPPLIER, waitIntervalInSeconds, waitJobTask));
}
import com.synopsys.integration.exception.IntegrationException;
import com.synopsys.integration.log.IntLogger;

public static WaitJob create(IntLogger intLogger, long timeoutInSeconds, long startTime, int waitIntervalInSeconds, String taskName, WaitJobTask waitJobTask) {
return new WaitJob(new WaitJobConfig(intLogger, timeoutInSeconds, startTime, waitIntervalInSeconds, taskName, waitJobTask));
}
public class WaitJob<T extends Object> {
public static final BooleanWaitJobCompleter BOOLEAN_COMPLETER = new BooleanWaitJobCompleter();

public static WaitJob create(IntLogger intLogger, long timeoutInSeconds, Supplier<Long> startTimeSupplier, int waitIntervalInSeconds, String taskName, WaitJobTask waitJobTask) {
return new WaitJob(new WaitJobConfig(intLogger, timeoutInSeconds, startTimeSupplier, waitIntervalInSeconds, taskName, waitJobTask));
public static final WaitJob<Boolean> createSimpleWait(WaitJobConfig waitJobConfig, WaitJobCondition waitJobCondition) {
return new WaitJob<>(waitJobConfig, waitJobCondition, BOOLEAN_COMPLETER);
}

public static WaitJob createUsingSystemTimeWhenInvoked(IntLogger intLogger, long timeoutInSeconds, int waitIntervalInSeconds, String taskName, WaitJobTask waitJobTask) {
return new WaitJob(new WaitJobConfig(intLogger, timeoutInSeconds, WaitJobConfig.CURRENT_TIME_SUPPLIER, waitIntervalInSeconds, taskName, waitJobTask));
}
private final WaitJobConfig waitJobConfig;
private final WaitJobCondition waitJobCondition;
private final WaitJobCompleter<T> waitJobCompleter;

public WaitJob(WaitJobConfig waitJobConfig) {
public WaitJob(WaitJobConfig waitJobConfig, WaitJobCondition waitJobCondition, WaitJobCompleter<T> waitJobCompleter) {
this.waitJobConfig = waitJobConfig;
this.waitJobCondition = waitJobCondition;
this.waitJobCompleter = waitJobCompleter;
}

public boolean waitFor() throws InterruptedException, IntegrationException {
public T waitFor() throws InterruptedException, IntegrationException {
int attempts = 0;
IntLogger intLogger = waitJobConfig.getIntLogger();
long startTime = waitJobConfig.getStartTime();
Duration currentDuration = Duration.ZERO;
Duration maximumDuration = Duration.ofMillis(waitJobConfig.getTimeoutInSeconds() * 1000);
IntLogger intLogger = waitJobConfig.getIntLogger();
String taskDescription = waitJobConfig.getTaskDescription();

boolean allCompleted = waitJobCondition.isComplete();
if (allCompleted) {
String attemptPrefix = createAttemptPrefix(attempts, currentDuration, taskDescription);
return complete(intLogger, attemptPrefix);
}

String taskDescription = waitJobConfig
.getTaskName()
.map(s -> String.format("for task %s ", s))
.orElse("");
while (currentDuration.compareTo(maximumDuration) <= 0) {
String attemptMessagePrefix = String.format("Try #%s %s(elapsed: %s)...", ++attempts, taskDescription, DurationFormatUtils.formatDurationHMS(currentDuration.toMillis()));
if (waitJobConfig.getWaitJobTask().isComplete()) {
intLogger.info(String.format("%scomplete!", attemptMessagePrefix));
return true;
attempts++;
String attemptPrefix = createAttemptPrefix(attempts, currentDuration, taskDescription);
if (waitJobCondition.isComplete()) {
return complete(intLogger, attemptPrefix);
} else {
intLogger.info(String.format("%snot done yet, waiting %s seconds and trying again...", attemptMessagePrefix, waitJobConfig.getWaitIntervalInSeconds()));
intLogger.info(String.format("%snot done yet, waiting %s seconds and trying again...", attemptPrefix, waitJobConfig.getWaitIntervalInSeconds()));
Thread.sleep(waitJobConfig.getWaitIntervalInSeconds() * 1000);
currentDuration = Duration.ofMillis(System.currentTimeMillis() - startTime);
}
}

return false;
return waitJobCompleter.handleTimeout();
}

private T complete(IntLogger intLogger, String attemptPrefix) throws IntegrationException {
intLogger.info(String.format("%scomplete!", attemptPrefix));
return waitJobCompleter.complete();
}

private String createAttemptPrefix(int attempts, Duration currentDuration, String taskDescription) {
return String.format("Try #%s %s(elapsed: %s)...", attempts, taskDescription, DurationFormatUtils.formatDurationHMS(currentDuration.toMillis()));
}

}
18 changes: 18 additions & 0 deletions src/main/java/com/synopsys/integration/wait/WaitJobCompleter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* integration-common
*
* Copyright (c) 2021 Synopsys, Inc.
*
* Use subject to the terms and conditions of the Synopsys End User Software License and Maintenance Agreement. All rights reserved worldwide.
*/
package com.synopsys.integration.wait;

import com.synopsys.integration.exception.IntegrationException;
import com.synopsys.integration.exception.IntegrationTimeoutException;

public interface WaitJobCompleter<T extends Object> {
T complete() throws IntegrationException;

T handleTimeout() throws IntegrationTimeoutException;

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

import com.synopsys.integration.exception.IntegrationException;

public interface WaitJobTask {
@FunctionalInterface
public interface WaitJobCondition {
boolean isComplete() throws IntegrationException;

}
53 changes: 22 additions & 31 deletions src/main/java/com/synopsys/integration/wait/WaitJobConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,68 +7,59 @@
*/
package com.synopsys.integration.wait;

import com.synopsys.integration.log.IntLogger;

import java.util.Optional;
import java.util.function.Supplier;

import com.synopsys.integration.log.IntLogger;

public class WaitJobConfig {
public static final Supplier<Long> CURRENT_TIME_SUPPLIER = System::currentTimeMillis;

private final IntLogger intLogger;
private final String taskName;
private final long timeoutInSeconds;
private final Supplier<Long> startTimeSupplier;
private final int waitIntervalInSeconds;
private final String taskName;
private final WaitJobTask waitJobTask;

public WaitJobConfig(IntLogger intLogger, long timeoutInSeconds, long startTime, int waitIntervalInSeconds, WaitJobTask waitJobTask) {
this(intLogger, timeoutInSeconds, () -> startTime, waitIntervalInSeconds, null, waitJobTask);
public WaitJobConfig(IntLogger intLogger, String taskName, long timeoutInSeconds, long startTime, int waitIntervalInSeconds) {
this(intLogger, taskName, timeoutInSeconds, () -> startTime, waitIntervalInSeconds);
}

public WaitJobConfig(IntLogger intLogger, long timeoutInSeconds, Supplier<Long> startTimeSupplier, int waitIntervalInSeconds, WaitJobTask waitJobTask) {
this(intLogger, timeoutInSeconds, startTimeSupplier, waitIntervalInSeconds, null, waitJobTask);
}

public WaitJobConfig(IntLogger intLogger, long timeoutInSeconds, long startTime, int waitIntervalInSeconds, String taskName, WaitJobTask waitJobTask) {
this(intLogger, timeoutInSeconds, () -> startTime, waitIntervalInSeconds, taskName, waitJobTask);
}

public WaitJobConfig(IntLogger intLogger, long timeoutInSeconds, Supplier<Long> startTimeSupplier, int waitIntervalInSeconds, String taskName, WaitJobTask waitJobTask) {
public WaitJobConfig(IntLogger intLogger, String taskName, long timeoutInSeconds, Supplier<Long> startTimeSupplier, int waitIntervalInSeconds) {
this.intLogger = intLogger;
this.taskName = taskName;
this.timeoutInSeconds = timeoutInSeconds;
this.startTimeSupplier = startTimeSupplier;
this.waitIntervalInSeconds = waitIntervalInSeconds;
this.taskName = taskName;
this.waitJobTask = waitJobTask;

// waitInterval needs to be less than the timeout
if (waitIntervalInSeconds > timeoutInSeconds) {
this.waitIntervalInSeconds = (int) timeoutInSeconds;
} else {
this.waitIntervalInSeconds = waitIntervalInSeconds;
}
}

public long getStartTime() {
return startTimeSupplier.get();
public IntLogger getIntLogger() {
return intLogger;
}

public Optional<String> getTaskName() {
return Optional.ofNullable(taskName);
public String getTaskName() {
return taskName;
}

public IntLogger getIntLogger() {
return intLogger;
public String getTaskDescription() {
return String.format("for task %s ", taskName);
}

public long getTimeoutInSeconds() {
return timeoutInSeconds;
}

public Supplier<Long> getStartTimeSupplier() {
return startTimeSupplier;
public long getStartTime() {
return startTimeSupplier.get();
}

public int getWaitIntervalInSeconds() {
return waitIntervalInSeconds;
}

public WaitJobTask getWaitJobTask() {
return waitJobTask;
}

}
59 changes: 41 additions & 18 deletions src/test/java/com/synopsys/integration/wait/WaitJobTest.java
Original file line number Diff line number Diff line change
@@ -1,43 +1,66 @@
package com.synopsys.integration.wait;

import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertFalse;

import com.synopsys.integration.exception.IntegrationException;
import com.synopsys.integration.log.BufferedIntLogger;
import com.synopsys.integration.log.LogLevel;

import org.junit.Assert;
import org.junit.jupiter.api.Test;

public class WaitJobTest {
private final BufferedIntLogger testingLogger = new BufferedIntLogger();
private final WaitJobConfig waitJobConfig = new WaitJobConfig(testingLogger, "holypants", 5, WaitJobConfig.CURRENT_TIME_SUPPLIER, 1);

@Test
public void testTaskNameLogged() throws IntegrationException, InterruptedException {
BufferedIntLogger testingLogger = new BufferedIntLogger();
public void testTaskCompletesImmediately() throws IntegrationException, InterruptedException {
WaitJobCondition waitJobCondition = () -> true;
WaitJob<Boolean> waitJob = new WaitJob(waitJobConfig, waitJobCondition, WaitJob.BOOLEAN_COMPLETER);
boolean completed = waitJob.waitFor();

WaitJob waitJob = WaitJob.createUsingSystemTimeWhenInvoked(testingLogger, 5, 1, "holypants", createTask());
waitJob.waitFor();
assertTrue(completed);

String output = testingLogger.getOutputString(LogLevel.INFO);
Assert.assertTrue(output.contains("holypants"));
assertTrue(output.contains("holypants"));
assertTrue(output.contains("complete!"));
assertFalse(output.contains("not done yet"));
}

@Test
public void testTaskNameNotLogged() throws IntegrationException, InterruptedException {
BufferedIntLogger testingLogger = new BufferedIntLogger();
public void testTaskCompletesEventually() throws IntegrationException, InterruptedException {
WaitJobCondition waitJobCondition = new WaitJobCondition() {
private int count = 0;

@Override
public boolean isComplete() {
return ++count > 2;
}
};
WaitJob<Boolean> waitJob = new WaitJob(waitJobConfig, waitJobCondition, WaitJob.BOOLEAN_COMPLETER);
boolean completed = waitJob.waitFor();

WaitJob waitJob = WaitJob.createUsingSystemTimeWhenInvoked(testingLogger, 5, 1, createTask());
waitJob.waitFor();
assertTrue(completed);

String output = testingLogger.getOutputString(LogLevel.INFO);
Assert.assertFalse(output.contains("holypants"));
assertTrue(output.contains("holypants"));
assertTrue(output.contains("complete!"));
assertTrue(output.contains("not done yet"));
}

private WaitJobTask createTask() {
return new WaitJobTask() {
private int count = 0;
@Test
public void testTaskCompletesNever() throws IntegrationException, InterruptedException {
WaitJobCondition waitJobCondition = () -> false;
WaitJob<Boolean> waitJob = new WaitJob(waitJobConfig, waitJobCondition, WaitJob.BOOLEAN_COMPLETER);
boolean completed = waitJob.waitFor();

@Override
public boolean isComplete() throws IntegrationException {
return ++count > 1;
}
};
assertFalse(completed);

String output = testingLogger.getOutputString(LogLevel.INFO);
assertTrue(output.contains("holypants"));
assertFalse(output.contains("complete!"));
assertTrue(output.contains("not done yet"));
}

}

0 comments on commit f3d128b

Please sign in to comment.