Skip to content

Destroy process tree on exec abort#33596

Merged
asodja merged 11 commits into
gradle:masterfrom
jjohannes:destroy-process-tree-on-exec-abort
Jul 23, 2025
Merged

Destroy process tree on exec abort#33596
asodja merged 11 commits into
gradle:masterfrom
jjohannes:destroy-process-tree-on-exec-abort

Conversation

@jjohannes

@jjohannes jjohannes commented May 23, 2025

Copy link
Copy Markdown
Contributor

Fixes #7603
New attempt based on #18756

Note

❗ Most of the added lines in this PR is test and test setup code. There is effectively just one line of new productions code: process.descendants().forEach(java.lang.ProcessHandle::destroy);

Context

With Java 9+ Java offers APIs to solve this OS independently. With Gradle 9 (next release), the minimum Java version for running the Gradle daemon is 17. Therefore, a solution that only works for Java 9+ is reasonable.

If the ExecHandleRunner code (modified in this PR) runs in a worker process, the old behavior is kept and a message about that is logged on DEBUG level.

This PR is following up on a discussion on Slack with @oleg-nenashev and @jvandort.

Contributor Checklist

  • Review Contribution Guidelines.
  • Make sure that all commits are signed off to indicate that you agree to the terms of Developer Certificate of Origin.
  • Make sure all contributed code can be distributed under the terms of the Apache License 2.0, e.g. the code was written by yourself or the original code is licensed under a license compatible to Apache License 2.0.
  • Check "Allow edit from maintainers" option in pull request so that additional changes can be pushed by Gradle team.
  • Provide integration tests (under <subproject>/src/integTest) to verify changes from a user perspective.
  • Provide unit tests (under <subproject>/src/test) to verify logic.
  • [ ] Update User Guide, DSL Reference, and Javadoc for public-facing changes.
  • Ensure that tests pass sanity check: ./gradlew sanityCheck.
  • Ensure that tests pass locally: ./gradlew <changed-subproject>:quickTest.

Reviewing cheatsheet

Before merging the PR, comments starting with

  • ❌ ❓must be fixed
  • 🤔 💅 should be fixed
  • 💭 may be fixed
  • 🎉 celebrate happy things

Signed-off-by: Jendrik Johannes <jendrik.johannes@gmail.com>
@jjohannes jjohannes requested a review from a team May 23, 2025 08:31
@bot-gradle bot-gradle added from:contributor PR by an external contributor to-triage labels May 23, 2025
@jjohannes jjohannes force-pushed the destroy-process-tree-on-exec-abort branch 2 times, most recently from 3e889cc to 5c8ae37 Compare May 23, 2025 08:56
Signed-off-by: Jendrik Johannes <jendrik.johannes@gmail.com>
@jjohannes jjohannes force-pushed the destroy-process-tree-on-exec-abort branch from 5c8ae37 to 727131e Compare May 23, 2025 08:59
@big-guy big-guy added the 👋 team-triage Issues that need to be triaged by a specific team label May 23, 2025
@ov7a

ov7a commented May 23, 2025

Copy link
Copy Markdown
Member

Thank you for your proposed contribution!

This PR has a valid DCO and tests. The relevant team for this area will confirm the design of the implementation choices.

execHandle.waitForFinish().exitValue != 0
}

@Requires(UnitTestPreconditions.Jdk8OrEarlier)

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.

Unit tests no longer run on anything below Java 17, so this will never run. We need an integration test to exercise this properly on Windows.

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.

I added an integration test for the use case the feature solves. Unfortunately, it only runs on Unix, as I did not find a fixture for testing it on Windows. This also screams flakiness.

As this change has no Windows specific code on the Gradle side, I think is is fine though. And the code is tested on Windows in the unit test. I don't think in this case an integration test adds much. It's executing the same code path.

Regarding the test above I now removed: I am not sure how to get code to even execute on Java 8. So I did not any replacement.

If you think there should be additional tests, please advice what exactly we should add.

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.

Fixed this and added integration tests for Windows

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.

Thank you @asodja for picking this up. Much appreciated. 🙇

Comment thread subprojects/core/build.gradle.kts Outdated
@mlopatkin mlopatkin removed the 👋 team-triage Issues that need to be triaged by a specific team label Jun 10, 2025
Signed-off-by: Jendrik Johannes <jendrik.johannes@gmail.com>
Signed-off-by: Jendrik Johannes <jendrik.johannes@gmail.com>
Signed-off-by: Jendrik Johannes <jendrik.johannes@gmail.com>
@doctorpangloss

Copy link
Copy Markdown

this should get merged

@asodja

asodja commented Jul 21, 2025

Copy link
Copy Markdown
Member

I will take it from here and take care that it gets in 9.1.0.

@asodja asodja closed this Jul 21, 2025

package org.gradle.integtests.fixtures


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.

Extra line

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.

Fixed

return getProcessHandle(pid)
}

private static def getProcessHandle(Long pid) {

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.

This should be marked with @Nullable

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.

Fixed

private DaemonClientFixture client
private int daemonLogCheckpoint

@Requires(UnitTestPreconditions.Jdk9OrLater)

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.

This should not be necessary. All integ tests run on 17+

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.

Fixed

@doctorpangloss

Copy link
Copy Markdown

i backported this on top of 8.14 since too many plugins don't support 9 yet, i hope you guys will too
works flawlessly on desktop windows, macos, linux and our windows and linux CI
it fixes so many pain points...

@asodja asodja force-pushed the destroy-process-tree-on-exec-abort branch 2 times, most recently from 046d94a to 4631b1e Compare July 23, 2025 08:17
Co-authored-by: Justin <jvandort@gradle.com>
@asodja asodja force-pushed the destroy-process-tree-on-exec-abort branch from 4631b1e to 728fc34 Compare July 23, 2025 09:18
@asodja

asodja commented Jul 23, 2025

Copy link
Copy Markdown
Member

@doctorpangloss I am not sure if we will backport this, technically 8.x line is only in maintenance mode. We will discuss it internally

@gradle gradle deleted a comment from asodja Jul 23, 2025
@gradle gradle deleted a comment from asodja Jul 23, 2025
@gradle gradle deleted a comment from asodja Jul 23, 2025
@gradle gradle deleted a comment from asodja Jul 23, 2025
@gradle gradle deleted a comment from asodja Jul 23, 2025
@asodja asodja added this pull request to the merge queue Jul 23, 2025
@bot-gradle bot-gradle added this to the 9.1.0 RC1 milestone Jul 23, 2025
@ljacomet

ljacomet commented Jul 23, 2025

Copy link
Copy Markdown
Member

@doctorpangloss yes, this kind of fix would be a good value add to backport. But unfortunately, it relies on Java 9+ APIs and Gradle 8.x still supports running on Java 8+.
So it is unlikely we will be able to backport this as-is. If you have further interest in this and believe there is an easy way to backport while respecting the compatibility, please open an issue describing your thoughts.

Well, replied too fast, the code here has the right safeguards against that.
I created:

Merged via the queue into gradle:master with commit 7633dee Jul 23, 2025
28 checks passed
@asodja

asodja commented Jul 23, 2025

Copy link
Copy Markdown
Member

@jjohannes Thank you for your contribution!

joshuataylor added a commit to joshuataylor/intellij-elixir that referenced this pull request Dec 13, 2025
What a mess.

See:

- [Terminating Gradle build does not execute finalizedBy
task](gradle/gradle#13212)
- [`finalizedBy` does not work when task fails and the target task
depends on origin task](gradle/gradle#27707)
- [Finalizer tasks are not run when the build is
cancelled](gradle/gradle#28399)
- [Gradle doesn't stop forked
processes](gradle/gradle#7603)
- [Stop forked exec and javaexec on build
termination](gradle/gradle#18756)
- [Destroy process tree on exec
abort](gradle/gradle#33596)"
ljacomet pushed a commit that referenced this pull request Jan 20, 2026
ljacomet pushed a commit that referenced this pull request Jan 20, 2026
ljacomet pushed a commit that referenced this pull request Jan 20, 2026
ljacomet pushed a commit that referenced this pull request Jan 21, 2026
ljacomet pushed a commit that referenced this pull request Jan 21, 2026
@jjohannes jjohannes deleted the destroy-process-tree-on-exec-abort branch March 27, 2026 07:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

from:contributor PR by an external contributor in:exec-tasks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gradle doesn't stop forked processes

10 participants