quarkus-workshops icon indicating copy to clipboard operation
quarkus-workshops copied to clipboard

Datasource cannot be injected in Health Check

Open agoncal opened this issue 3 years ago • 9 comments

We use to have an health check that was like that. Today, this code doesn't work because it cannot inject the Datasource. I don't have the time to investigate for now:

javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type javax.sql.DataSource and qualifiers [@Default]
	- java member: io.quarkus.workshop.superheroes.hero.health.DatabaseConnectionHealthCheck#dataSource
	- declared on CLASS bean [types=[io.quarkus.workshop.superheroes.hero.health.DatabaseConnectionHealthCheck, org.eclipse.microprofile.health.HealthCheck, java.lang.Object], qualifiers=[@Readiness, @Any], target=io.quarkus.workshop.superheroes.hero.health.DatabaseConnectionHealthCheck]
```	


package io.quarkus.workshop.superheroes.hero.health;

import org.eclipse.microprofile.health.HealthCheck; import org.eclipse.microprofile.health.HealthCheckResponse; import org.eclipse.microprofile.health.HealthCheckResponseBuilder; import org.eclipse.microprofile.health.Readiness;

import javax.inject.Inject; import javax.sql.DataSource; import java.sql.Connection; import java.sql.ResultSet; import java.sql.Statement;

@Readiness public class DatabaseConnectionHealthCheck implements HealthCheck {

@Inject
DataSource dataSource;

@Override
public HealthCheckResponse call() {
    HealthCheckResponseBuilder responseBuilder = HealthCheckResponse.named("Hero health check");
    try {
        int rows = numberOfRows();
        responseBuilder.up().withData("rows", rows);
    } catch (Exception e) {
        responseBuilder.down().withData("message", e.getMessage());
    }

    return responseBuilder.build();
}

private int numberOfRows() throws Exception {
    try (Connection connection = dataSource.getConnection();
         Statement statement = connection.createStatement();
         ResultSet resultSet = statement.executeQuery("SELECT COUNT(*) FROM Hero")) {
        if (resultSet.next()) {
            return resultSet.getInt(1);
        } else {
            return 0;
        }
    }
}

}

agoncal avatar Oct 07 '21 14:10 agoncal

Do we expose data sources as bean? (CC @Sanne / @geoand).

Does that change anything if you add @ApplicationScoped on your bean?

cescoffier avatar Oct 07 '21 14:10 cescoffier

Ah maybe there is a classifier, try add @Any with your @Inject

cescoffier avatar Oct 07 '21 15:10 cescoffier

Hm... This should work... We even use it in some of our tests: https://github.com/quarkusio/quarkus/blob/2.3.0.Final/integration-tests/smallrye-opentracing/src/main/java/io/quarkus/it/opentracing/JdbcResource.java#L16

geoand avatar Oct 07 '21 15:10 geoand

I thought there was an @ApplicationScoped missing on the health check, but I still get the same error

agoncal avatar Oct 07 '21 15:10 agoncal

Hey, the hero microservice use Hibernate Reactive! No data source!

cescoffier avatar Oct 07 '21 15:10 cescoffier

Then where does the type come from?

geoand avatar Oct 07 '21 15:10 geoand

if there is no datasource that explains why you can't inject it :)

or am I not understanding the question?

Sanne avatar Oct 07 '21 17:10 Sanne

If that really was the mistake, use the reactive SQL client instead of the Datasource:

    @Inject
    PgPool client;

Sanne avatar Oct 07 '21 20:10 Sanne

@cescoffier you are right. The code works great in the Villain microservices (uses Hibernate) but not in the Hero (which uses Hibernate Reactive).

@Sanne PgPool comes from Vert.x (io.vertx.mutiny.pgclient.PgPool). Isn't there a "higher level" database access I could use (I was hoping to find a ReactiveDataSourceAPI ;o) ? In the workshop we don't mention vertx and I would like to keep it hidden

agoncal avatar Oct 08 '21 11:10 agoncal