springspring-boot-actuatorhttp-status-code-503readinessprobelivenessprobe

Spring Boot livenessState: DOWN and readinessState: OUT_OF_SERVICE even if application is running fine


i'm developing/running a SpringBoot App on Kubernetes 1.24, which i'm also using to learn several techniques with mostly using WebClient and with my newest attempt, also sending E-Mails with JavaMailSender etc.

Lately i was updating a few parts in my code, where i'm not sure anymore what was leading to the issue in the subject.

But i suspect it could have something to do with adding a new @Component for my EmailSender class or that i had to use @ComponentScan to access the mail package, as it was outside of my controller class package.

As e.g.:

[...]
@Configuration
public class EmailConfiguration {
    @Bean
    public JavaMailSender getJavaMailSender() {
           [...]
        }
}

and also:

@Component
public class EmailSender {
    @Autowired
    private JavaMailSender emailSender;
    @Bean
    public void sendSimpleMessage(String to, String subject, String text) {
       [...]
    }
}

Also i've updated from Eclipse Temurin 17.0.6+10 to 17.0.7+7

To get more details, i've added the following to the application.properties:

management.server.port=8081
management.server.address=0.0.0.0
management.endpoints.web.exposure.include=health,info,metrics,prometheus
management.endpoint.health.probes.enabled=true
management.health.livenessState.enabled=true
management.health.readinessState.enabled=true
management.endpoint.health.show-details=always
management.endpoints.web.base-path=/actuator

So i've got the following response calling http://localhost:8081/actuator/health:

{
  "status": "DOWN",
  "components": {
    "db": {
      "status": "UP",
      "details": {
        "database": "H2",
        "validationQuery": "isValid()"
      }
    },
    "diskSpace": {
      "status": "UP",
      "details": {
        "total": 1022565265408,
        "free": 861403496448,
        "threshold": 10485760,
        "path": "C:\\Users\\nick\\eclipse-workspace\\demoapp\\.",
        "exists": true
      }
    },
    "livenessState": {
      "status": "DOWN"
    },
    "ping": {
      "status": "UP"
    },
    "readinessState": {
      "status": "OUT_OF_SERVICE"
    }
  },
  "groups": [
    "liveness",
    "readiness"
  ]
}

My pom:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.6</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>my.demo.springboot</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Demo SpringBoot</name>
    <description>Demo Spring Boot Example</description>

    <properties>
        <java.version>17</java.version>
        <log4j2.version>2.20.0</log4j2.version>
        <netty.version>4.1.92.Final</netty.version>
        <snakeyaml.version>2.0</snakeyaml.version>
    </properties>

    <dependencies>
    
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.11.0</version>
        </dependency>

        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
        </dependency>
        
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      <scope>runtime</scope>
    </dependency>


        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-registry-prometheus</artifactId>
            <scope>runtime</scope>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.11.5</version>
        </dependency>
    
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.11.5</version>
        </dependency>

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.11.5</version>
        </dependency>
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>4.4.0</version>
        </dependency>

        <dependency>
            <groupId>org.ocpsoft.prettytime</groupId>
            <artifactId>prettytime</artifactId>
            <version>5.0.6.Final</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

I was reading on the following at the official documentation:

Tasks expected to run during startup should be executed by CommandLineRunner and ApplicationRunner components instead of using Spring component lifecycle callbacks such as @PostConstruct.

But i did not modified any behavior on such, so i'm currently not sure where and what to look for.

As i'm running on kubernetes, i'm using both endpoints to monitor my application, but now it keeps restarting as a both healthchecks fail with 503.

I'm hoping that it is just something simple i've forgot/changed and anyone knows or had that issue already.

Let me know if anyhow more information is required.

Thanks!

Update:

This only happens with Spring Boot 3.0.6, with 3.0.5 everything running fine with:

{
  "status": "UP",
  "components": {
    "diskSpace": {
      "status": "UP",
      "details": {
        "total": 1022565265408,
        "free": 863173750784,
        "threshold": 10485760,
        "path": "C:\\<censored>\\.",
        "exists": true
      }
    },
    "livenessState": {
      "status": "UP"
    },
    "mail": {
      "status": "UP",
      "details": {
        "location": "<censored>.net:25"
      }
    },
    "ping": {
      "status": "UP"
    },
    "readinessState": {
      "status": "UP"
    }
  },
  "groups": [
    "liveness",
    "readiness"
  ]
}

This issue on GitHub might be related.


Solution

  • Issue is related with GitHub issue 35161. With a fix and its description as:

    Liveness and readiness probes return down when lazy initialization is enabled

    Updating to Spring Boot Version 3.1.0 solved it for me (also 3.0.7 should have the fix, but untested from my side) and the health endpoint is up again (3.1.0 just has been published 3 days ago).

    Details:

    This is a regression caused by the changes for #34347. The return type of the @Bean method has changed from ApplicationAvailabilityBean to ApplicationAvailability. This means that type information is lost and the bean factory cannot tell that it's an ApplicationListener.

    {
      "status": "UP",
      "components": {
        "db": {
          "status": "UP",
          "details": {
            "database": "H2",
            "validationQuery": "isValid()"
          }
        },
        "diskSpace": {
          "status": "UP",
          "details": {
            "total": 1022565265408,
            "free": 862148792320,
            "threshold": 10485760,
            "path": "C:\\<censored>\\eclipse-workspace\\demo\\.",
            "exists": true
          }
        },
        "livenessState": {
          "status": "UP"
        },
        "ping": {
          "status": "UP"
        },
        "readinessState": {
          "status": "UP"
        }
      },
      "groups": [
        "liveness",
        "readiness"
      ]
    }