playframeworkscheduled-tasksws-client

play framework call WS inside Scheduled asynchronous tasks


I'am starting using play framework i want to write a job that makes a certain number of ws calls.

I wrote 2 classes as following:

@Singleton
public class AutoGateJob {

@Inject
private ActorSystem actorSystem;
@Inject
private ExecutionContext executionContext;
@Inject
private RgsDataServiceServices rgsDataServiceServices;

@Inject
public AutoGateJob(ApplicationLifecycle lifecycle, ActorSystem system, ExecutionContext
    context) {
    Logger.info("### create autojob");
    this.actorSystem = system;
    this.executionContext = context;

    this.initialize();

    lifecycle.addStopHook(() -> {
        Logger.info("### c'est l'heure de rentrer!!!");
        this.actorSystem.shutdown();
        return CompletableFuture.completedFuture(null);
    });
}

private void initialize() {
    this.actorSystem.scheduler().schedule(
        Duration.create(0, TimeUnit.SECONDS), // initialDelay
        Duration.create(5, TimeUnit.SECONDS), // interval
        () -> this.runAutoGateJobTasks(),
        this.executionContext
    );
}

private void runAutoGateJobTasks() {
    Logger.info("## Run job every 5 seconds");
    rgsDataServiceServices = new RgsDataServiceServices();

    rgsDataServiceServices.findAllPaymentToSendHandler()
    .handle((wsResponse, throwable) -> {
        Logger.info("## find all payment to send response: ", wsResponse.asJson());
        List<String> paymentsList = new ArrayList<>();
        paymentsList.forEach(s -> {
            Logger.info("## Processing payment: ", s);
        });
        return CompletableFuture.completedFuture(null);
    });
}

}

and

public class AutoGateJobInitializer extends AbstractModule {

@Override
protected void configure() {
    Logger.info("## Setup job on app startup!");
    bind(AutoGateJob.class).asEagerSingleton();
}

}

the problem is: Mys rgsDataServiceServices has a working WSClient injection that works well when used with controllers but when called in the AutoGateJob i have null pointer exception ( [error] a.d.TaskInvocation - null java.lang.NullPointerException: null ) I don't really understand what's going on but i need my job to behave this way.

Thank you for helping!


Solution

  • You should inject all of your dependencies into the constructor. What you're doing is only injecting some in the constructor, you then immediately schedule a task that will try to use all the dependencies, but chances are, that task will run before Guice has injected all your dependencies. If you want to ensure all your dependencies are available, only use constructor injection, ie:

    private final ActorSystem actorSystem;
    private final ExecutionContext executionContext;
    private final RgsDataServiceServices rgsDataServiceServices;
    
    @Inject
    public AutoGateJob(ActorSystem system, ExecutionContext context, RgsDataServiceServices rgsDataServiceServices) {
      Logger.info("### create autojob");
      this.actorSystem = system;
      this.executionContext = context;
      this.rgsDataServiceServices = rgsDataServiceServices
    
      this.initialize();
    }
    

    Also, you shouldn't be adding a lifecycle hook to shut the actor system down, Play already registers a lifecycle hook to do that. If you want, you can register a lifecycle hook to cancel the scheduled task, but I don't think that's really necessary because it will automatically be cancelled when the actor system shuts down.