Skip to content

Dev tools causes misconfigured command-line application to exit with 0 #28541

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
msmerc opened this issue Nov 5, 2021 · 13 comments
Open

Dev tools causes misconfigured command-line application to exit with 0 #28541

msmerc opened this issue Nov 5, 2021 · 13 comments
Labels
type: bug A general bug
Milestone

Comments

@msmerc
Copy link

msmerc commented Nov 5, 2021

I have a really simple spring application that's misconfigured:

@SpringBootApplication()
public class SimpleApplication implements CommandLineRunner {
    public static void main(String[] args) {
        var ctx = SpringApplication.run(SimpleApplication.class, args);
        System.exit(SpringApplication.exit(ctx));
    }

    public static class MyObject {}
    
    //Oops - No bean provided!!!
    @Autowired MyObject myObject;

    @Override public void run(String... args) { }
}

I get the following error (in intellij):

...
Consider defining a bean of type 'test.app.SimpleApplication$MyObject' in your configuration.


Process finished with exit code 1

Which is what I'd expect.

If I add the spring-boot-devtools dependency in maven:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

Then I get the following:

...
Consider defining a bean of type 'test.app.SimpleApplication$MyObject' in your configuration.


Process finished with exit code 0

It seems that adding this package causes spring boot to have the wrong return codes.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Nov 5, 2021
@msmerc
Copy link
Author

msmerc commented Nov 5, 2021

Here's my full maven config:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>springboot-test</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>13</maven.compiler.source>
        <maven.compiler.target>13</maven.compiler.target>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.5.5</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <!-- This dependency causes the issue -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    </dependencies>
</project>

@cdmatta
Copy link

cdmatta commented Nov 5, 2021

  1. The app runs within a RestartLauncher due to devtools
    https://github.com/spring-projects/spring-boot/blob/v2.5.6/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/RestartLauncher.java#L46-L53

  2. When SpringApplication handles the failure it invokes SpringBootExceptionHandler.registerLoggedException for UnsatisfiedDependencyException

  3. The last thing SpringApplication does is ReflectionUtils.rethrowRuntimeException(exception);
    SpringApplication.java

  4. This causes the exception seen in RestartLauncher to be java.lang.reflect.InvocationTargetException containing target UnsatisfiedDependencyException

  5. Finally, SpringBootExceptionHandler has a registered Exception UnsatisfiedDependencyException .. does not have InvocationTargetException as a registed exception and thus the exit code is 0

RegisteredExceptionVsActual

Ideally, in this case it should investigate the target of the exception and match it

@scottfrederick scottfrederick self-assigned this Nov 5, 2021
@scottfrederick scottfrederick removed the status: waiting-for-triage An issue we've not yet triaged label Nov 10, 2021
@scottfrederick scottfrederick added this to the 2.4.x milestone Nov 10, 2021
@scottfrederick scottfrederick removed their assignment Nov 10, 2021
@scottfrederick scottfrederick added the type: bug A general bug label Nov 10, 2021
@wilkinsona wilkinsona modified the milestones: 2.4.x, 2.5.x Nov 15, 2021
@wilkinsona
Copy link
Member

#26894 is in a similar area.

@CangYa2021
Copy link

@cdmatta @wilkinsona
When relying on developmentOnly'org.springframework.boot:spring-boot-devtools', the SpringBoot project will schedule the org.springframework.boot.devtools.restart.RestartLauncher#run() function in devtools when it starts, and the abnormal status code 0 is returned by the abnormal status of devtools,
I guess this problem should be related to the operating principle of spring-boot-devtools.

@CangYa2021
Copy link

@msmerc @cdmatta
You can debug at the following methods.
image
image

@wilkinsona I think this situation is not a bug, isn't it ?

@msmerc
Copy link
Author

msmerc commented Nov 29, 2021

If this is the intended behavior then I think spring-boot-devtools needs to inform the user that it's changed the exit code! Otherwise this is very non-obvious. Took me ages to track down the culprit.

@wilkinsona
Copy link
Member

It looks like a bug to me. preventNonZeroExitCode() should only come into play if the JVM is exiting due to Dev Tools' own SilentExitException. For any other failure the intent is that the exit code should be unchanged. From what @cdmatta has described above, it's an UnsatisfiedDependencyException so the code that's specific to SilentExitException shouldn't be involved.

@CangYa2021
Copy link

@wilkinsona @msmerc
For the above problem, I tracked again and got the following results:

1、The first is to set SilentExitExceptionHandler in

2、Suspend the main thread at

, and then get the error of the child thread

3、Handle the error obtained in

protected void start(FailureHandler failureHandler) throws Exception {
do {
Throwable error = doStart();
if (error == null) {
return;
}
if (failureHandler.handle(error) == Outcome.ABORT) {
return;
}
}
while (true);
}

4、When we track

, it will return SilentExitException

5、At this time, the SilentExitExceptionHandler of the main thread handles SilentExitException and silently terminates the JVM

@Override
public void uncaughtException(Thread thread, Throwable exception) {
if (exception instanceof SilentExitException || (exception instanceof InvocationTargetException
&& ((InvocationTargetException) exception).getTargetException() instanceof SilentExitException)) {
if (isJvmExiting(thread)) {
preventNonZeroExitCode();
}
return;
}
if (this.delegate != null) {
this.delegate.uncaughtException(thread, exception);
}
}

I think devtool does not classify and actively handle the exceptions generated by the child threads, but chooses to return the exception information through the log listener, and chooses to silently end the program.
When developmentOnly'org.springframework.boot:spring-boot-devtools' is not introduced, the exit code should be 1 returned by JVM.

@CangYa2021
Copy link

@wilkinsona If this logic is unreasonable and I want to solve it, please give some guidance.

@wilkinsona
Copy link
Member

@msmerc What's your reason for using DevTools in an application that would normally run and then exit? There's some background about the current behaviour for applications that behave like this in #5968.

@wilkinsona wilkinsona added the status: waiting-for-feedback We need additional information before we can continue label Dec 8, 2021
@spring-projects-issues
Copy link
Collaborator

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

@spring-projects-issues spring-projects-issues added the status: feedback-reminder We've sent a reminder that we need additional information before we can continue label Dec 15, 2021
@msmerc
Copy link
Author

msmerc commented Dec 15, 2021

@wilkinsona I'm not quite sure I understand. Obviously there's no intention for the app to be misconfigured!

Our app has multiple modules. Basically one webapp and a bunch of supporting CommandLineRunner utilities. These modules all had common dependencies (including DevTools) - arguably this is incorrect since the devtools only make sense for the webapp, but it's hardly something non-spring-experts would be aware of.

We have a test that validates the spring configuration by running one of the spring command line utils on the code during a continuous integration stage. Although the app was misconfigured, the test was passing because the exit was 0, so our test wasn't picking up configuration issues.

The other problem is that it's very non-obvious that the devtools are the issue. There's nothing in the output telling you that devtools is changing the exit code.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue status: feedback-reminder We've sent a reminder that we need additional information before we can continue labels Dec 15, 2021
@wilkinsona
Copy link
Member

Thanks, @msmerc. Knowing if the usage is accidental or if there was a usecase that we have overlooked is valuable in helping us to prioritise a fix. If there was a usecase that we have overlooked, recommending that you avoid using dev tools in a command-line app would not have been very helpful.

@wilkinsona wilkinsona removed the status: feedback-provided Feedback has been provided label Jan 7, 2022
@wilkinsona wilkinsona changed the title springboot dev tools causes misconfigured application to exit with 0 springboot dev tools causes misconfigured command-line application to exit with 0 Jan 7, 2022
@wilkinsona wilkinsona changed the title springboot dev tools causes misconfigured command-line application to exit with 0 Dev tools causes misconfigured command-line application to exit with 0 Jan 7, 2022
@wilkinsona wilkinsona removed this from the 2.5.x milestone May 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

7 participants