Reputation: 715
I get an exception with Play Framework 2.5 while sending a notification e-mail on user action. Here is the code:
public class IpnListener extends Controller {
@Inject
private Notif notif;
@Inject
private WSClient ws;
public CompletionStage<Result> validate() {
return ws.url(/*...*/)
.thenApply(response -> {
/* do some validations */
notif.send(ctx(), notification, user.getEmail());
});
}
}
The Notif
class.
public class Notif {
@Inject
private MailerClient mailerClient;
@Inject
private HttpExecutionContext executionContext;
public void send(Http.Context context, Notification notification, String target) {
/* create an email with template*/
CompletableFuture.runAsync(() -> {
try {
mailerClient.send(email);
}
catch (Exception e) {
e.printStackTrace();
}
},
executionContext.current());
}
}
Then I get randomly this exception:
java.lang.RuntimeException: There is no HTTP Context available from here.
at play.mvc.Http$Context.current(Http.java:62)
at play.mvc.Controller.ctx(Controller.java:27)
at controllers.listeners.IpnListener.lambda$validate$0(IpnListener.java:69)
at services.payment.PayPal$Request.lambda$verify$0(PayPal.java:201)
at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:616)
at java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:591)
at java.util.concurrent.CompletableFuture$Completion.exec(CompletableFuture.java:457)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
java.lang.RuntimeException: There is no HTTP Context available from here.
at play.mvc.Http$Context.current(Http.java:62)
at play.mvc.Controller.ctx(Controller.java:27)
at controllers.listeners.IpnListener.lambda$validate$0(IpnListener.java:69)
at services.payment.PayPal$Request.lambda$verify$0(PayPal.java:201)
at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:616)
at java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:591)
at java.util.concurrent.CompletableFuture$Completion.exec(CompletableFuture.java:457)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
I'm thinking about saving the ctx()
value in a variable like that but I'm not sure about it's lifetime:
public class IpnListener extends Controller {
@Inject
private Notif notif;
@Inject
private WSClient ws;
public CompletionStage<Result> validate() {
Http.Context context = ctx();
return ws.url(/*...*/)
.thenApply(response -> {
/* do some validations */
notif.send(context, notification, user.getEmail());
});
}
}
Upvotes: 0
Views: 471
Reputation: 715
There is no HTTP context available in the thenApply()
method called from WSClient
so I had to use the HttpExecutionContext
with thenApplyAsync()
.
public class IpnListener extends Controller {
@Inject
private Notif notif;
@Inject
private WSClient ws;
@Inject
private HttpExecutionContext httpExecutionContext;
public CompletionStage<Result> validate() {
Http.Context context = ctx();
return ws.url(/*...*/)
.thenApplyAsync(response -> {
/* do some validations */
notif.send(context, notification, user.getEmail());
},
httpExecutionContext.current());
}
}
Upvotes: 0
Reputation: 647
You need to
@Inject HttpExecutionContext ec;
into your controller. On the thenApply() call, supply ec.current() as the executioner.
.thenApply(response -> {
}, ex.current());
Upvotes: 1