Skip to content

Commit

Permalink
enhancement : Made http timeout configurable for all API Requests (de…
Browse files Browse the repository at this point in the history
…fault 300 seconds) (leapwork#56)

* enhancement : Increased http timeout to 5 min

* Made http timeout configurable in all API Requests

---------

Co-authored-by: Sachin Tomar <[email protected]>
  • Loading branch information
sachindevtomar and Sachin Tomar authored Nov 23, 2023
1 parent b245949 commit d69096e
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,28 +44,29 @@ public class LeapworkJenkinsBridgeBuilder extends Builder implements SimpleBuild
private final String leapworkPort;
private final Secret leapworkAccessKey;
private String leapworkDelay;
private String leapworkTimeout;
private String leapworkDoneStatusAs;
private String leapworkReport;
private final String leapworkSchIds;
private final String leapworkSchNames;
private boolean leapworkWritePassedFlowKeyFrames;
private boolean leapworkEnableHttps;
private String leapworkScheduleVariables;
private static final int TIMEOUT_IN_SECONDS = 180;

private static PluginHandler pluginHandler = PluginHandler.getInstance();

// Fields in config.jelly must match the parameter names in the
// "DataBoundConstructor"
@DataBoundConstructor
public LeapworkJenkinsBridgeBuilder(String leapworkHostname, String leapworkPort, String leapworkAccessKey,
String leapworkDelay, String leapworkDoneStatusAs, String leapworkReport, String leapworkSchNames,
String leapworkDelay, String leapworkTimeout, String leapworkDoneStatusAs, String leapworkReport, String leapworkSchNames,
String leapworkSchIds, boolean leapworkWritePassedFlowKeyFrames, boolean leapworkEnableHttps) {

this.leapworkHostname = leapworkHostname;
this.leapworkPort = leapworkPort;
this.leapworkAccessKey = Secret.fromString(leapworkAccessKey);
this.leapworkDelay = leapworkDelay;
this.leapworkTimeout = leapworkTimeout;
this.leapworkDoneStatusAs = leapworkDoneStatusAs;
this.leapworkReport = leapworkReport;
this.leapworkSchIds = leapworkSchIds;
Expand All @@ -89,6 +90,11 @@ public void setLeapworkDelay(String leapworkDelay) {
this.leapworkDelay = leapworkDelay;
}

@DataBoundSetter
public void setLeapworkTimeout(String leapworkTimeout) {
this.leapworkTimeout = leapworkTimeout;
}

@DataBoundSetter
public void setLeapworkWritePassedFlowKeyFrames(boolean leapworkWritePassedFlowKeyFrames) {
this.leapworkWritePassedFlowKeyFrames = leapworkWritePassedFlowKeyFrames;
Expand Down Expand Up @@ -120,6 +126,10 @@ public String getLeapworkDelay() {
return leapworkDelay;
}

public String getLeapworkTimeout() {
return leapworkTimeout;
}

public String getLeapworkSchNames() {
return leapworkSchNames;
}
Expand Down Expand Up @@ -155,6 +165,8 @@ public void perform(final Run<?, ?> build, FilePath workspace, Launcher launcher
EnvVars env = build.getEnvironment(listener);
ArrayList<InvalidSchedule> invalidSchedules = new ArrayList<>();

int timeout = pluginHandler.getTimeout(leapworkTimeout, listener);

String workspacePath = pluginHandler.getWorkSpaceSafe(workspace, env);
this.leapworkReport = pluginHandler.getReportFileName(this.getLeapworkReport(),
DescriptorImpl.DEFAULT_REPORT_NAME);
Expand All @@ -174,8 +186,8 @@ public void perform(final Run<?, ?> build, FilePath workspace, Launcher launcher
.getScheduleVariablesRequestPart(getLeapworkScheduleVariables(), listener);

AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()
.setReadTimeout(TIMEOUT_IN_SECONDS * 1000)
.setRequestTimeout(TIMEOUT_IN_SECONDS * 1000)
.setReadTimeout(timeout * 1000)
.setRequestTimeout(timeout * 1000)
.build();

try (AsyncHttpClient mainClient = new AsyncHttpClient(config)) {
Expand Down Expand Up @@ -206,7 +218,7 @@ public void perform(final Run<?, ?> build, FilePath workspace, Launcher launcher
if (runId != null) {
resultsMap.put(runId, run);
CollectScheduleRunResults(controllerApiHttpAddress, Secret.toString(leapworkAccessKey), runId,
schTitle, timeDelay, isDoneStatusAsSuccess, writePassedKeyframes, run, listener);
schTitle, timeDelay, timeout, isDoneStatusAsSuccess, writePassedKeyframes, run, listener);
} else
resultsMap.put(UUID.randomUUID(), run);

Expand Down Expand Up @@ -288,12 +300,17 @@ public void perform(final Run<?, ?> build, FilePath workspace, Launcher launcher
}

private static void CollectScheduleRunResults(String controllerApiHttpAddress, String accessKey, UUID runId,
String scheduleName, int timeDelay, boolean isDoneStatusAsSuccess, boolean writePassedKeyframes,
String scheduleName, int timeDelay, int timeout, boolean isDoneStatusAsSuccess, boolean writePassedKeyframes,
LeapworkRun resultRun, final TaskListener listener) throws AbortException, InterruptedException {
List<UUID> runItemsId = new ArrayList<>();
Object waiter = new Object();

AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()
.setReadTimeout(timeout * 1000)
.setRequestTimeout(timeout * 1000)
.build();
// get statuses
try (AsyncHttpClient client = new AsyncHttpClient()) {
try (AsyncHttpClient client = new AsyncHttpClient(config)) {
boolean isStillRunning = true;

do {
Expand Down Expand Up @@ -380,7 +397,7 @@ private static void CollectScheduleRunResults(String controllerApiHttpAddress, S
String interruptedExceptionMessage = String.format(Messages.INTERRUPTED_EXCEPTION, e.getMessage());
listener.error(interruptedExceptionMessage);
RunItem invalidItem = new RunItem("Aborted run", "Cancelled", 0, e.getMessage(), scheduleName);
pluginHandler.stopRun(controllerApiHttpAddress, runId, scheduleName, accessKey, listener);
pluginHandler.stopRun(controllerApiHttpAddress, runId, scheduleName, accessKey, timeout, listener);
resultRun.incErrors();
resultRun.runItems.add(invalidItem);
} finally {
Expand All @@ -405,6 +422,7 @@ private void printPluginInputs(final TaskListener listener, String workspace) {
listener.getLogger().println(String.format(Messages.INPUT_SCHEDULE_NAMES_VALUE, getLeapworkSchNames()));
listener.getLogger().println(String.format(Messages.INPUT_SCHEDULE_IDS_VALUE, getLeapworkSchIds()));
listener.getLogger().println(String.format(Messages.INPUT_DELAY_VALUE, getLeapworkDelay()));
listener.getLogger().println(String.format(Messages.INPUT_TIMEOUT_VALUE, getLeapworkTimeout()));
listener.getLogger().println(String.format(Messages.INPUT_DONE_VALUE, getLeapworkDoneStatusAs()));
listener.getLogger().println(String.format(Messages.INPUT_WRITE_PASSED, isLeapworkWritePassedFlowKeyFrames()));
listener.getLogger().println(String.format(Messages.INPUT_VARIABLES, getLeapworkScheduleVariables()));
Expand Down Expand Up @@ -435,6 +453,7 @@ public boolean isApplicable(Class<? extends AbstractProject> aClass) {
}

public static final String DEFAULT_DELAY = "5";
public static final String DEFAULT_TIMEOUT = "300";
public static final String DEFAULT_REPORT_NAME = "report.xml";
public static final boolean DEFAULT_WRITE_PASSED_FLOW_KEYFRAMES = false;
public static final boolean DEFAULT_ENABLE_lEAPWORK_HTTPS = false;
Expand All @@ -453,10 +472,28 @@ public FormValidation doCheckLeapworkDelay(@QueryParameter("leapworkDelay") Stri
return FormValidation.ok();
}

public FormValidation doCheckLeapworkTimeout(@QueryParameter("leapworkTimeout") String timeout) {
int temp;
try {
temp = Integer.parseInt(timeout);

if (temp < 1) {
return FormValidation.error("Entered number must be higher than 0");
}
} catch (NumberFormatException ex) {
return FormValidation.error("Invalid number");
}
return FormValidation.ok();
}

public String getDefaultLeapworkDelay() {
return DEFAULT_DELAY;
}

public String getDefaultLeapworkTimeout() {
return DEFAULT_TIMEOUT;
}

public String getDefaultLeapworkReport() {
return DEFAULT_REPORT_NAME;
}
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/Leapwork/Leapwork_plugin/Messages.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public class Messages {
public static final String NO_DISK_SPACE = "No enough disk space to start schedule";
public static final String PORT_NUMBER_IS_INVALID = "Port number is invalid, setting to default %1$d";
public static final String TIME_DELAY_NUMBER_IS_INVALID = "Time delay number is invalid: %1$s, setting to default %2$s";
public static final String TIMEOUT_NUMBER_IS_INVALID = "Timeout number is invalid: %1$s, setting to default %2$s";
public static final String FULL_REPORT_FILE_PATH = "Creating report file by path: %1$s";
public static final String SCHEDULE_DISABLED = "Schedule %1$s[%2$s] is disabled";
public static final String INVALID_SCHEDULE_VARIABLE = "Failed to parse variable: %1$s";
Expand All @@ -90,6 +91,7 @@ public class Messages {
public static final String INPUT_SCHEDULE_NAMES_VALUE = "Schedule names: %1$s";
public static final String INPUT_SCHEDULE_IDS_VALUE = "Schedule ids: %1$s";
public static final String INPUT_DELAY_VALUE = "Delay between status checks: %1$s";
public static final String INPUT_TIMEOUT_VALUE = "Leapwork API Request/Response Timeout: %1$s";
public static final String INPUT_DONE_VALUE = "Done Status As: %1$s";
public static final String INPUT_WRITE_PASSED = "Write keyframes of passed flows: %1$b";
public static final String INPUT_VARIABLES = "Passed schedule variables: %1$s";
Expand Down
28 changes: 26 additions & 2 deletions src/main/java/com/Leapwork/Leapwork_plugin/PluginHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.AsyncHttpClientConfig;
import com.ning.http.client.Response;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
Expand Down Expand Up @@ -125,6 +126,23 @@ public int getTimeDelay(String rawTimeDelay, TaskListener listener) {
}
}

public int getTimeout(String rawTimeout, TaskListener listener) {
int defaultTimeout = 300;
try {
if (!rawTimeout.isEmpty() || !"".equals(rawTimeout))
return Integer.parseInt(rawTimeout);
else {
listener.getLogger()
.println(String.format(Messages.TIMEOUT_NUMBER_IS_INVALID, rawTimeout, defaultTimeout));
return defaultTimeout;
}
} catch (Exception e) {
listener.getLogger()
.println(String.format(Messages.TIMEOUT_NUMBER_IS_INVALID, rawTimeout, defaultTimeout));
return defaultTimeout;
}
}

public boolean isDoneStatusAsSuccess(String doneStatusAs) {
return doneStatusAs.contentEquals("Success");
}
Expand Down Expand Up @@ -388,13 +406,19 @@ private static UUID OnScheduleRunConnectionFailure(Exception e, TaskListener lis
}

@SuppressFBWarnings(value = "REC_CATCH_EXCEPTION")
public boolean stopRun(String controllerApiHttpAddress, UUID runId, String scheduleTitle, String accessKey,
public boolean stopRun(String controllerApiHttpAddress, UUID runId, String scheduleTitle, String accessKey, int timeout,
final TaskListener listener) {
boolean isSuccessfullyStopped = false;

listener.error(String.format(Messages.STOPPING_RUN, scheduleTitle, runId));
String uri = String.format(Messages.STOP_RUN_URI, controllerApiHttpAddress, runId.toString());
try (AsyncHttpClient client = new AsyncHttpClient()) {

AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()
.setReadTimeout(timeout * 1000)
.setRequestTimeout(timeout * 1000)
.build();

try (AsyncHttpClient client = new AsyncHttpClient(config)) {

Response response = client.preparePut(uri).setBody("").setHeader("AccessKey", accessKey).execute().get();
client.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@
<f:entry title="Delay (seconds):" field="leapworkDelay">
<f:textbox name="leapworkDelay" default="${descriptor.DEFAULT_DELAY}"/>
</f:entry>
<f:entry title="Timeout (seconds):" field="leapworkTimeout">
<f:textbox name="leapworkTimeout" default="${descriptor.DEFAULT_TIMEOUT}"/>
</f:entry>
<f:entry title="Done Status:" field="leapworkDoneStatusAs">
<f:select />
</f:entry>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div>
The 'timeout' property represents the duration within which an operation or request expects to receive a response before considering it unsuccessful or timing out.<br>
It's measured in seconds, and the default value for this property is set to 300 seconds.
</div>

0 comments on commit d69096e

Please sign in to comment.