From d69096e3bb2de902e6c44096b98e8a7d901df736 Mon Sep 17 00:00:00 2001 From: Sachin Dev Tomar Date: Thu, 23 Nov 2023 15:57:07 +0530 Subject: [PATCH] enhancement : Made http timeout configurable for all API Requests (default 300 seconds) (#56) * enhancement : Increased http timeout to 5 min * Made http timeout configurable in all API Requests --------- Co-authored-by: Sachin Tomar --- .../LeapworkJenkinsBridgeBuilder.java | 53 ++++++++++++++++--- .../Leapwork/Leapwork_plugin/Messages.java | 2 + .../Leapwork_plugin/PluginHandler.java | 28 +++++++++- .../LeapworkJenkinsBridgeBuilder/config.jelly | 3 ++ .../help-leapworkTimeout.html | 4 ++ 5 files changed, 80 insertions(+), 10 deletions(-) create mode 100644 src/main/resources/com/Leapwork/Leapwork_plugin/LeapworkJenkinsBridgeBuilder/help-leapworkTimeout.html diff --git a/src/main/java/com/Leapwork/Leapwork_plugin/LeapworkJenkinsBridgeBuilder.java b/src/main/java/com/Leapwork/Leapwork_plugin/LeapworkJenkinsBridgeBuilder.java index e803d0e..8eb1efc 100644 --- a/src/main/java/com/Leapwork/Leapwork_plugin/LeapworkJenkinsBridgeBuilder.java +++ b/src/main/java/com/Leapwork/Leapwork_plugin/LeapworkJenkinsBridgeBuilder.java @@ -44,6 +44,7 @@ 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; @@ -51,7 +52,6 @@ public class LeapworkJenkinsBridgeBuilder extends Builder implements SimpleBuild private boolean leapworkWritePassedFlowKeyFrames; private boolean leapworkEnableHttps; private String leapworkScheduleVariables; - private static final int TIMEOUT_IN_SECONDS = 180; private static PluginHandler pluginHandler = PluginHandler.getInstance(); @@ -59,13 +59,14 @@ public class LeapworkJenkinsBridgeBuilder extends Builder implements SimpleBuild // "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; @@ -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; @@ -120,6 +126,10 @@ public String getLeapworkDelay() { return leapworkDelay; } + public String getLeapworkTimeout() { + return leapworkTimeout; + } + public String getLeapworkSchNames() { return leapworkSchNames; } @@ -155,6 +165,8 @@ public void perform(final Run build, FilePath workspace, Launcher launcher EnvVars env = build.getEnvironment(listener); ArrayList 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); @@ -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)) { @@ -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); @@ -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 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 { @@ -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 { @@ -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())); @@ -435,6 +453,7 @@ public boolean isApplicable(Class 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; @@ -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; } diff --git a/src/main/java/com/Leapwork/Leapwork_plugin/Messages.java b/src/main/java/com/Leapwork/Leapwork_plugin/Messages.java index 0c2e16e..551f4d1 100644 --- a/src/main/java/com/Leapwork/Leapwork_plugin/Messages.java +++ b/src/main/java/com/Leapwork/Leapwork_plugin/Messages.java @@ -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"; @@ -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"; diff --git a/src/main/java/com/Leapwork/Leapwork_plugin/PluginHandler.java b/src/main/java/com/Leapwork/Leapwork_plugin/PluginHandler.java index b46362c..2338193 100644 --- a/src/main/java/com/Leapwork/Leapwork_plugin/PluginHandler.java +++ b/src/main/java/com/Leapwork/Leapwork_plugin/PluginHandler.java @@ -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; @@ -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"); } @@ -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(); diff --git a/src/main/resources/com/Leapwork/Leapwork_plugin/LeapworkJenkinsBridgeBuilder/config.jelly b/src/main/resources/com/Leapwork/Leapwork_plugin/LeapworkJenkinsBridgeBuilder/config.jelly index 7e22a4f..ed32b88 100644 --- a/src/main/resources/com/Leapwork/Leapwork_plugin/LeapworkJenkinsBridgeBuilder/config.jelly +++ b/src/main/resources/com/Leapwork/Leapwork_plugin/LeapworkJenkinsBridgeBuilder/config.jelly @@ -49,6 +49,9 @@ + + + diff --git a/src/main/resources/com/Leapwork/Leapwork_plugin/LeapworkJenkinsBridgeBuilder/help-leapworkTimeout.html b/src/main/resources/com/Leapwork/Leapwork_plugin/LeapworkJenkinsBridgeBuilder/help-leapworkTimeout.html new file mode 100644 index 0000000..944bd1c --- /dev/null +++ b/src/main/resources/com/Leapwork/Leapwork_plugin/LeapworkJenkinsBridgeBuilder/help-leapworkTimeout.html @@ -0,0 +1,4 @@ +
+The 'timeout' property represents the duration within which an operation or request expects to receive a response before considering it unsuccessful or timing out.
+It's measured in seconds, and the default value for this property is set to 300 seconds. +