Skip to content

[Improvement-18034][alert] Add configurable timeout for script alert plugin#18050

Open
asadjan4611 wants to merge 15 commits intoapache:devfrom
asadjan4611:feature-18034-script-alert-timeout
Open

[Improvement-18034][alert] Add configurable timeout for script alert plugin#18050
asadjan4611 wants to merge 15 commits intoapache:devfrom
asadjan4611:feature-18034-script-alert-timeout

Conversation

@asadjan4611
Copy link
Copy Markdown
Contributor

Purpose of the pull request

Close: #18034

The Script Alert Plugin executes external scripts to send alerts. Currently, ProcessUtils.executeScript() calls process.waitFor() with no timeout. If a script hangs (network stall, deadlock, etc.), it permanently blocks a thread in the alert sender thread pool, degrading or blocking all alert delivery.

This PR adds a configurable timeout parameter (default: 60 seconds) to the Script Alert Plugin following the same pattern used by the HTTP Alert Plugin.

Brief change log

  • Add SCRIPT_TIMEOUT, NAME_SCRIPT_TIMEOUT, DEFAULT_SCRIPT_TIMEOUT constants to ScriptParamsConstants
  • Add InputNumberParam timeout parameter to ScriptAlertChannelFactory.params()
  • Replace blocking process.waitFor() with process.waitFor(timeout, TimeUnit.SECONDS) in ProcessUtils
  • Destroy process forcibly and interrupt stream gobblers on timeout
  • Parse timeout config in ScriptSender with fallback to default
  • Handle timeout exit code with clear error message in alert result

Verify this pull request

This change added tests and can be verified as follows:

  • Added ProcessUtilsTest.testExecuteScriptTimeout to verify process timeout and forced destruction (returns exit code -2)
  • Added ScriptSenderTest.testDefaultTimeout to verify default timeout works correctly
  • Added ScriptSenderTest.testCustomTimeout to verify custom timeout value is parsed and applied
  • Updated ScriptAlertChannelFactoryTest.testGetParams to verify new param count (3 → 4)
  • Compilation verified locally with mvn clean compile

@asadjan4611 asadjan4611 requested a review from SbloodyS as a code owner March 11, 2026 09:45
@SbloodyS SbloodyS requested a review from Copilot March 11, 2026 10:05
@SbloodyS SbloodyS added this to the 3.4.2 milestone Mar 11, 2026
@SbloodyS SbloodyS added the improvement make more easy to user or prompt friendly label Mar 11, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a configurable execution timeout to the Script Alert Plugin to prevent hung scripts from permanently blocking alert-sender threads, aligning behavior with the HTTP alert plugin’s timeout pattern.

Changes:

  • Introduce script timeout plugin parameter (default 60s) and expose it via the Script plugin channel factory params.
  • Update script execution to use waitFor(timeout, TimeUnit.SECONDS) and return a dedicated timeout exit code.
  • Add/adjust unit tests for the new timeout parameter and timeout behavior.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-script/src/main/java/org/apache/dolphinscheduler/plugin/alert/script/ProcessUtils.java Adds timed waiting for script processes and timeout handling.
dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-script/src/main/java/org/apache/dolphinscheduler/plugin/alert/script/ScriptSender.java Parses timeout config and maps timeout exit code to a clearer alert result message.
dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-script/src/main/java/org/apache/dolphinscheduler/plugin/alert/script/ScriptParamsConstants.java Adds timeout-related constants and default value.
dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-script/src/main/java/org/apache/dolphinscheduler/plugin/alert/script/ScriptAlertChannelFactory.java Exposes timeout as an InputNumberParam in the Script plugin UI params.
dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-script/src/test/java/org/apache/dolphinscheduler/plugin/alert/script/ProcessUtilsTest.java Updates tests to use the new timeout API and adds a timeout test case.
dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-script/src/test/java/org/apache/dolphinscheduler/plugin/alert/script/ScriptSenderTest.java Adds basic tests for default/custom timeout configuration.
dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-script/src/test/java/org/apache/dolphinscheduler/plugin/alert/script/ScriptAlertChannelFactoryTest.java Updates expected param count after adding timeout.
Comments suppressed due to low confidence (1)

dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-script/src/main/java/org/apache/dolphinscheduler/plugin/alert/script/ProcessUtils.java:64

  • The catch block interrupts the current thread for both InterruptedException and IOException. Interrupting the thread on an IOException can cause unrelated higher-level code to behave as if it was interrupted. Split the catch and only call Thread.currentThread().interrupt() when the exception is actually an InterruptedException.
        } catch (IOException | InterruptedException e) {
            log.error("execute alert script error {}", e.getMessage());
            Thread.currentThread().interrupt();
        }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

@asadjan4611
Copy link
Copy Markdown
Contributor Author

@SbloodyS I have resolved all the copilot issue's please review it again.

@asadjan4611 asadjan4611 force-pushed the feature-18034-script-alert-timeout branch from e902f7e to 124bf56 Compare March 12, 2026 14:07
closeProcessStreams(process);
joinGobbler(inputStreamGobbler);
joinGobbler(errorStreamGobbler);
return -2;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to use positive integer here.

.build();

return Arrays.asList(scriptUserParam, scriptPathParam, scriptTypeParams);
InputNumberParam scriptTimeoutParam =
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is best to tell the user the meaning of the exit code in the document.

? config.get(ScriptParamsConstants.NAME_SCRIPT_USER_PARAMS)
: "";
String timeoutConfig = config.get(ScriptParamsConstants.NAME_SCRIPT_TIMEOUT);
if (StringUtils.isNotBlank(timeoutConfig)) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (StringUtils.isNotBlank(timeoutConfig)) {
if (StringUtils.isNotEmpty(timeoutConfig)) {

try {
parsedTimeout = Long.parseLong(timeoutConfig);
} catch (NumberFormatException ex) {
log.warn("Invalid script timeout config value: '{}', using default: {}",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should return alertResult here.

private String[] cmd = {"/bin/sh", "-c", shellFilPath + " -t 1"};

@Test
@DisabledOnOs(OS.WINDOWS)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to do this since we've decleared in the document that windows is not supported.

}

@Test
@DisabledOnOs(OS.WINDOWS)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

@asadjan4611 asadjan4611 requested a review from EricGao888 as a code owner March 25, 2026 04:17
@Slf4j
public final class ProcessUtils {

static final int EXECUTE_ERROR_EXIT_CODE = -1;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not use negative number here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay fixed out

}

private String[] cmd = {"/bin/sh", "-c", shellFilPath + " -t 1"};
private static String getJavaBin() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

}

@Test
@DisabledOnOs(OS.WINDOWS)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@asadjan4611 asadjan4611 requested a review from SbloodyS March 26, 2026 12:50

private String[] cmd = {"/bin/sh", "-c", shellFilPath + " -t 1"};
private static String getJavaBin() {
String executableName = System.getProperty("os.name").toLowerCase().contains("win")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AlertResult alertResult;
alertResult = scriptSender.sendScriptAlert("test user params NPE", "test content");
Assertions.assertTrue(alertResult.isSuccess());
if (isWindows()) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AlertResult alertResult;
alertResult = scriptSender.sendScriptAlert("test title Kris", "test content");
Assertions.assertTrue(alertResult.isSuccess());
if (isWindows()) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alertResult = scriptSender.sendScriptAlert("test path NPE", "test content");
assertFalse(alertResult.isSuccess());
Assertions.assertTrue(alertResult.getMessage().contains("shell script is invalid, only support .sh file"));
if (isWindows()) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

public void testDefaultTimeout() {
ScriptSender scriptSender = new ScriptSender(scriptConfig);
AlertResult alertResult = scriptSender.sendScriptAlert("test title Kris", "test content");
if (isWindows()) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scriptConfig.put(ScriptParamsConstants.NAME_SCRIPT_TIMEOUT, "30");
ScriptSender scriptSender = new ScriptSender(scriptConfig);
AlertResult alertResult = scriptSender.sendScriptAlert("test title Kris", "test content");
if (isWindows()) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ScriptSender scriptSender = new ScriptSender(scriptConfig);
AlertResult alertResult = scriptSender.sendScriptAlert("test title Kris", "test content");
Assertions.assertFalse(alertResult.isSuccess());
if (isWindows()) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@asadjan4611 asadjan4611 requested a review from SbloodyS April 1, 2026 08:14
@asadjan4611
Copy link
Copy Markdown
Contributor Author

@SbloodyS i have fix all the issue's please again review it .

@SbloodyS
Copy link
Copy Markdown
Member

SbloodyS commented Apr 8, 2026

CI still failed. @asadjan4611

@asadjan4611
Copy link
Copy Markdown
Contributor Author

@SbloodyS
i have fix all the checks that have been failing and i test it locally now all the checks related to it have been passsed

@SbloodyS
Copy link
Copy Markdown
Member

SbloodyS commented Apr 8, 2026

You should run mvn spotless:apply to format the code. @asadjan4611

@asadjan4611
Copy link
Copy Markdown
Contributor Author

okay @SbloodyS
Thanks your guidance and i have done it.

Copy link
Copy Markdown
Member

@SbloodyS SbloodyS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are still many unaddressed comments, you should check them yourself first.

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 9, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
0.0% Coverage on New Code (required ≥ 60%)

See analysis details on SonarQube Cloud

@asadjan4611 asadjan4611 requested a review from SbloodyS April 9, 2026 07:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend document improvement make more easy to user or prompt friendly test

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Improvement][alert] Script alert plugin can hang indefinitely (no process timeout) and exhaust alert sender threads

3 participants