Java - Quarkus

Log-Levels

  # Inside application.properties ...

  # Standard quarkus global level
  quarkus.log.level=INFO
  # particular packages
  quarkus.log.category."org.apache".level=DEBUG
  • Setting as an environment variable
  # E.g. in a deployment file - need to use double underscore instead of "." for the category
  QUARKUS_LOG_CATEGORY__ORG_MY__LEVEL=WARN

MicroProfile Rest Client vs Server side Jax-RS

Quarkus Reactive programming for RestEasy

Microprofile RestClient Exception handling

When you are working with the microprofile rest client it throws a WebApplicationException for http codes >=400. If you want to see the content of the Response to get headers etc. you need to create a custom mapper that extends the ResponseExceptionMapper and register it with the rest client by annotation. This is slightly different to standard JAX-RS (but which uses exception mappers too - https://dennis-xlc.gitbooks.io/restful-java-with-jax-rs-2-0-2rd-edition/content/en/part1/chapter7/exception_handling.html or https://access.redhat.com/documentation/en-us/red_hat_jboss_fuse/6.2.1/html/apache_cxf_development_guide/restexceptionmapper)

@Path("/api/test")
@RegisterRestClient(configKey = "api-call")
@RegisterProvider(CustomResponseExceptionMapper.class)
@ApplicationScoped
public interface SomeService {

  @POST
  @Consumes(MediaType.APPLICATION_JSON)
  @Produces(MediaType.APPLICATION_JSON)
  CompletionStage<Response> someServiceCall(@HeaderParam("some-header-name") String someHeader,
      SomeRequest someRequest);
}
public class CustomResponseExceptionMapper implements ResponseExceptionMapper<WebApplicationException> {

  public WebApplicationException toThrowable(Response response) {
    if (response.getStatus() == 500) {
      Object errorCodeHeader = response.getHeaders().get(0);
      Object errorMsgHeader = response.getHeaders().get(1);

      if (errorCodeHeader != null && errorMsgHeader != null) {
        log.error("Error response: {} - {}", errorCodeHeader, errorMsgHeader);
      }
    }

    return new WebApplicationException("Service error, status code " + response.getStatus(), response);
  }
}

Scheduling stuff in Quarkus

Can use standard Quarkus schedule or an actual Quarkus-Quartz Scheduler library which seems more fully featured

<!-- Update for pom.xml -->
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-scheduler</artifactId>
</dependency>
@ApplicationScoped              
public class SomeBean {

    
    @Scheduled(every="10s")     
    void doStuff() {...}

    @Scheduled(cron="0 15 10 * * ?") 
    void doStuff() {...}

    // Cron in the application config
    @Scheduled(cron = "{cron.expr}") 
    void doStuff() {...}
}

Remote debug in Quarkus

# In local 
mvn quarkus:dev

# in remote container for example
mvn quarkus:remote-dev -Ddebug=false \
  -Dquarkus.package.type=mutable-jar \
  -Dquarkus.live-reload.url=http://localhost:8080 \
  -Dquarkus.live-reload.password=123

Quarkus Testing

@QuarkusTest
@TestProfile(SomeQuarkusTest.MyTestProfile.class)
class SomeQuarkusTest {

  public static class MyTestProfile implements QuarkusTestProfile {
    @Override
    public Map<String, String> getConfigOverrides() {
      return Map.of("someproperty.value", "true",
          "someservice.url", "http://localhost:9001/mockService");
    }
  }
  • This works even from a Quarkus TestResource (when defining your own impl of the resource lifecycle manager) but without a test profile, the regular profile doesn't get access to the config params - maybe a lifecycle issue with instantiation.

Quarkus CXF

quarkus.cxf.endpoint."endpoints".out-fault-interceptors
The comma-separated list of OutFaultInterceptor classes
Environment variable: QUARKUS_CXF_ENDPOINT__ENDPOINTS__OUT_FAULT_INTERCEPTORS


quarkus.cxf.client."clients".out-fault-interceptors
The comma-separated list of OutFaultInterceptor classes
Environment variable: QUARKUS_CXF_CLIENT__CLIENTS__OUT_FAULT_INTERCEPTORS

  • https://github.com/quarkiverse/quarkus-cxf/issues/4 - non blocking quarkus calls

Context handling in Quarkus microservices

  • https://quarkus.io/guides/context-propagation#usage-example-for-completionstage
    • When using a completion stage to chain up operations (e.g. calling multiple remote services) you need to use manual context propagation to ensure the context is passed along the chain.
    • The page above goes in to detail about how to do this with either mutiny or completion stage.
    • For completion stage the key thing to use is threadContext.withContextCapture to capture the context and then thenApplyAsync to ensure the context is passed along the chain.
  return threadContext.withContextCapture(client.get("/api/people/").send())
                .thenApplyAsync(response -> {
                    if (response.getStatus() != 200) {
                        throw new IllegalStateException("Error calling people service");
                    }
                    return response.persons;
                }, managedExecutor);