Janez Radešček
Janez Radešček

Reputation: 1

How to regularly trigger its own endpoint?

I have an existing endpoint calling some function, and it works fine when doing a rest call to the endpoint. Then I want to create a scheduler that will call that function regularly. The scheduler itself works as expected, but now there is an unexpected exception in the function during a scheduled function. The rest of the endpoint still works. Since the problem seems to be a RequestScoped bean, I tried ActivateRequestContent, but nothing changes.

Below is minimally reproduicable example that better explain the problem.

EDIT: I don't want to modify the service or some external cron. I would prefer the solution to be within Scheduler.

I have a resource:

@Path("/hello")
public class GreetingResource {

    @Inject
    GreetingService greetingService;

    @GET
    public String hello() {
        return greetingService.getGreetings();
    }
}

A service:

@ApplicationScoped
public class GreetingService {

    @Inject
    RequestBean requestBean;

    public String getGreetings() {

        //do logic, call other services, save to DB, etc

        if (requestBean.getAcceptLanguage().equals("en")) {
            return "Hello from RESTEasy Reactive";
        } else {
            return "Hola desde RESTEasy Reactive";
        }
    }
}

And a RequestScoped bean.

@RequestScoped
public class RequestBean {

    private String acceptLanguage;

    RequestBean(HttpHeaders httpHeaders) {
        acceptLanguage = httpHeaders.getHeaderString(HttpHeaders.ACCEPT_LANGUAGE);
        if (acceptLanguage == null || acceptLanguage.isBlank()) {
            this.acceptLanguage = "en";
        }
    }

    public String getAcceptLanguage() {
        return acceptLanguage;
    }
}

The endpoints work in test and postman.

But now I need to do the exact same work regularly.

So I added the scheduler.

@ApplicationScoped
public class Scheduler {

    @Inject
    GreetingService greetingService;

    @Scheduled(every = "10s")
    @ActivateRequestContext
    public void scheduledTask() {

        try {
            Log.info("Scheduler is starting");
            greetingService.getGreetings();
            Log.info("Scheduler is finished");
        } catch (Exception e) {
            Log.error("Error while running scheduler", e);
        }

    }
}

I expected no exception, but I got an exception inside the scheduledTask.

java.lang.IllegalStateException: No RESTEasy Reactive request in progress
        at org.jboss.resteasy.reactive.server.injection.ContextProducers.getContext(ContextProducers.java:149)
        at org.jboss.resteasy.reactive.server.injection.ContextProducers.headers(ContextProducers.java:52)
        at org.jboss.resteasy.reactive.server.injection.ContextProducers_ProducerMethod_headers_VA74pGGn-tu4h7_tlI2NceCHbzU_Bean.doCreate(Unknown Source)
        at org.jboss.resteasy.reactive.server.injection.ContextProducers_ProducerMethod_headers_VA74pGGn-tu4h7_tlI2NceCHbzU_Bean.create(Unknown Source)
        at org.jboss.resteasy.reactive.server.injection.ContextProducers_ProducerMethod_headers_VA74pGGn-tu4h7_tlI2NceCHbzU_Bean.create(Unknown Source)
        at io.quarkus.arc.impl.RequestContext$1.get(RequestContext.java:79)
        at io.quarkus.arc.impl.RequestContext$1.get(RequestContext.java:75)
        at io.quarkus.arc.generator.Default_jakarta_enterprise_context_RequestScoped_ContextInstances.c2(Unknown Source)
        at io.quarkus.arc.generator.Default_jakarta_enterprise_context_RequestScoped_ContextInstances.computeIfAbsent(Unknown Source)
        at io.quarkus.arc.impl.RequestContext.getIfActive(RequestContext.java:75)
        at io.quarkus.arc.impl.ClientProxies.getSingleContextDelegate(ClientProxies.java:28)
        at jakarta.ws.rs.core.ContextProducers_ProducerMethod_headers_VA74pGGn-tu4h7_tlI2NceCHbzU_ClientProxy.arc$delegate(Unknown Source)
        at jakarta.ws.rs.core.ContextProducers_ProducerMethod_headers_VA74pGGn-tu4h7_tlI2NceCHbzU_ClientProxy.getHeaderString(Unknown Source)
        at com.example.RequestBean.<init>(RequestBean.java:12)
        at com.example.RequestBean_Bean.doCreate(Unknown Source)
        at com.example.RequestBean_Bean.create(Unknown Source)
        at com.example.RequestBean_Bean.create(Unknown Source)
        at io.quarkus.arc.impl.RequestContext$1.get(RequestContext.java:79)
        at io.quarkus.arc.impl.RequestContext$1.get(RequestContext.java:75)
        at io.quarkus.arc.generator.Default_jakarta_enterprise_context_RequestScoped_ContextInstances.c0(Unknown Source)
        at io.quarkus.arc.generator.Default_jakarta_enterprise_context_RequestScoped_ContextInstances.computeIfAbsent(Unknown Source)
        at io.quarkus.arc.impl.RequestContext.getIfActive(RequestContext.java:75)
        at io.quarkus.arc.impl.ClientProxies.getSingleContextDelegate(ClientProxies.java:28)
        at com.example.RequestBean_ClientProxy.arc$delegate(Unknown Source)
        at com.example.RequestBean_ClientProxy.getAcceptLanguage(Unknown Source)
        at com.example.GreetingService.getGreetings(GreetingService.java:16)
        at com.example.GreetingService_ClientProxy.getGreetings(Unknown Source)
        at com.example.Scheduler.scheduledTask(Scheduler.java:21)
        at com.example.Scheduler_Subclass.scheduledTask$$superforward(Unknown Source)
        at com.example.Scheduler_Subclass$$function$$1.apply(Unknown Source)
        at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:73)
        at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:62)
        at io.quarkus.arc.impl.ActivateRequestContextInterceptor.invoke(ActivateRequestContextInterceptor.java:124)
        at io.quarkus.arc.impl.ActivateRequestContextInterceptor.aroundInvoke(ActivateRequestContextInterceptor.java:33)
        at io.quarkus.arc.impl.ActivateRequestContextInterceptor_Bean.intercept(Unknown Source)
        at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:42)
        at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:30)
        at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:27)
        at com.example.Scheduler_Subclass.scheduledTask(Unknown Source)
        at com.example.Scheduler_ClientProxy.scheduledTask(Unknown Source)
        at com.example.Scheduler_ScheduledInvoker_scheduledTask_b06a23f86c5479393959068a663c2a2a98c84093.invokeBean(Unknown Source)
        at io.quarkus.scheduler.common.runtime.DefaultInvoker.invoke(DefaultInvoker.java:24)
        at io.quarkus.scheduler.common.runtime.StatusEmitterInvoker.invoke(StatusEmitterInvoker.java:35)
        at io.quarkus.scheduler.runtime.SimpleScheduler$ScheduledTask.doInvoke(SimpleScheduler.java:443)
        at io.quarkus.scheduler.runtime.SimpleScheduler$ScheduledTask$2.call(SimpleScheduler.java:425)
        at io.quarkus.scheduler.runtime.SimpleScheduler$ScheduledTask$2.call(SimpleScheduler.java:422)
        at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$0(ContextImpl.java:178)
        at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:279)
        at io.vertx.core.impl.ContextImpl.lambda$internalExecuteBlocking$2(ContextImpl.java:210)
        at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
        at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1512)
        at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:1583)

Relevant dependency:

<quarkus.platform.version>3.8.5</quarkus.platform.version>
...
<dependency>
   <groupId>io.quarkus</groupId>
   <artifactId>quarkus-resteasy-reactive-jackson</artifactId>
</dependency>
<dependency>
   <groupId>io.quarkus</groupId>
   <artifactId>quarkus-scheduler</artifactId>
</dependency>

EDIT 2: Solutions that do work, but are not ok.

  1. Rework service -> service is huge, dont have time.
  2. External cron job calls working endpoint -> i cant control external apps, problems with Authorization
  3. calling shell with curl my endpoint -> seems weird, problems with Authorization
  4. Use code from test in scheduler
given()
   .when()
   .get("/hello")
   .then()
   .statusCode(200);

-> This looks very nice compared to 1-3 solutions, but having restassured import in main code feels wrong. Is it wrong?

Upvotes: 0

Views: 90

Answers (1)

alphamikevictor
alphamikevictor

Reputation: 647

You can try to use Quarkus RestClient to access the /hello path. If you need to deal with authentication, you can do something like:

Class to access API

import com.fasterxml.jackson.databind.JsonNode;
import jakarta.ws.rs.*;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

@RegisterRestClient
public interface Api {
    @GET
    @Path("/hello")
    JsonNode hello(@HeaderParam("Authorization") String token);
}

And then your Scheduled thing

@RestClient
Api api;
@Scheduled(every = "10s")
void doTheJob(){
  String token;
  // do something to get the token
  api.hello(token);
}

Upvotes: 1

Related Questions