org.catools.common.concurrent.CTimeBoxRunner Maven / Gradle / Ivy
package org.catools.common.concurrent;
import org.catools.common.concurrent.exceptions.CThreadTimeoutException;
import org.catools.common.date.CDate;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
/**
* There are many time in automation when you stock on some task
* due to application response time or dead loop inside automation code.
* We do want to fix both but we do not want to limit our
* execution due to such scenarios so we use a {@link CTimeBoxRunner} which
* is job is to wait for task only in defined time frame and throw exception
* if the task execution timeout
*
* @param type of result object
*/
public class CTimeBoxRunner implements Runnable {
private final Supplier job;
private final int timeoutInSeconds;
private final boolean throwExceptionIfTimeout;
private Throwable ex;
private R r;
private CTimeBoxRunner(Supplier job, int timeoutInSeconds, boolean throwExceptionIfTimeout) {
this.job = job;
this.timeoutInSeconds = timeoutInSeconds;
this.throwExceptionIfTimeout = throwExceptionIfTimeout;
}
/**
* Perform a task in separate concurrent and return the execution result.
* If the task not been finished in the defined time box then then
* return null without throwing any exception
*
* @param job task to be perform
* @param timeoutInSeconds execution timeout in seconds
* @param the type of return objects
* @return the result of task model
*/
public static R get(Supplier job, int timeoutInSeconds) {
return get(job, timeoutInSeconds, false);
}
/**
* Perform a task in separate concurrent and return the execution result.
* If the {@code throwExceptionIfTimeout} is set to be FALSE and the task not been finished
* in the defined time box then then return null without throwing any exception
* If the {@code throwExceptionIfTimeout} is set to be TRUE and the task not been finished
* in the defined time box then then throw any exception {@link CThreadTimeoutException}
*
* @param job task to be perform
* @param timeout execution timeout amount
* @param unit execution timeout time unit
* @param throwExceptionIfTimeout whether should throw execution on timeout or not
* @param the type of return objects
* @return the result of task model
* @throws CThreadTimeoutException throw execution on timeout if throwExceptionIfTimeout parameter set to TRUE
*/
public static R get(Supplier job, long timeout, TimeUnit unit, boolean throwExceptionIfTimeout) {
return new CTimeBoxRunner(job, (int) TimeUnit.SECONDS.convert(timeout, unit), throwExceptionIfTimeout).get();
}
/**
* Perform a task in separate concurrent and return the execution result.
* If the {@code throwExceptionIfTimeout} is set to be FALSE and the task not been finished
* in the defined time box then then return null without throwing any exception
* If the {@code throwExceptionIfTimeout} is set to be TRUE and the task not been finished
* in the defined time box then then throw any exception {@link CThreadTimeoutException}
*
* @param job task to be perform
* @param timeoutInSeconds execution timeout in seconds
* @param throwExceptionIfTimeout whether should throw execution on timeout or not
* @param the type of return objects
* @return the result of task model
* @throws CThreadTimeoutException throw execution on timeout if throwExceptionIfTimeout parameter set to TRUE
*/
public static R get(Supplier job, int timeoutInSeconds, boolean throwExceptionIfTimeout) {
return new CTimeBoxRunner(job, timeoutInSeconds, throwExceptionIfTimeout).get();
}
@Override
public void run() {
try {
r = job.get();
} catch (Throwable ex) {
this.ex = ex;
}
}
private R get() {
Thread thread = CThreadRunner.run(this);
CDate deadLine = new CDate().addSeconds(timeoutInSeconds);
boolean timeoutFlag = false;
// A little ugly code for sake of debugging and branch readability
while (true) {
if (r != null) {
break;
}
if (!thread.isAlive()) {
break;
}
if (deadLine.before(new CDate())) {
timeoutFlag = true;
break;
}
}
if (thread.isAlive()) {
thread.interrupt();
}
if (timeoutFlag && throwExceptionIfTimeout) {
throw new CThreadTimeoutException("Job execution takes more time than expected");
}
if (ex != null) {
throw new RuntimeException(ex);
}
return r;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy