At some point, that the stack trace will reveal, you are trying to access the current Http.Context. From a scheduler point of view, that won’t make sense since there is no current request available to the scheduler. It means the scheduler needs to have all the necessary data to run without relying on any request data.
Since I’m not seeing any access to Http.Context in the code you shared, it is maybe happening in prepayNotRefundedWarning view? Better if you can share the complete stack trace.
Yes, better to not use that since it depends on the request (to compose the absolute URL with scheme, host, etc.). Better to have this as a configuration that you can access and use the reverse router just to get the path section.
Now I get another error: java.util.NoSuchElementException: None.get
Hard to know what is happening based only on this line. Post the complete stack trace. But usually, you don’t do a get on an Option because it can be None. Better to use getOrElse if this is inside a view.
The None.get error message was related to a bad Configuration dependency injection. Now I have troubles with Messages: java.lang.IllegalArgumentException: Unknown pattern letter: f which mean that the “format.dateTime” label isn’t matched in the language file.
This label exists and works perfecly when the view is rendered in a controller.
My Format.date() method looks like:
public static String date(String format, LocalDateTime date)
{
if (format == null || date == null) return "";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
return date.atZone(ZoneId.systemDefault()).format(formatter);
}
It is very hard to know what could be possibly happening when all we got is just a small section of the stack trace. Can you better detail what you are trying to do? How your project is configured? Where is this error happening? What is the complete stack trace?
java.lang.IllegalArgumentException: Unknown pattern letter: f
at java.time.format.DateTimeFormatterBuilder.parsePattern(DateTimeFormatterBuilder.java:1661)
at java.time.format.DateTimeFormatterBuilder.appendPattern(DateTimeFormatterBuilder.java:1570)
at java.time.format.DateTimeFormatter.ofPattern(DateTimeFormatter.java:536)
at helpers.Format.date(Format.java:37)
at views.html.mail.prepayNotRefundedWarning_Scope0$prepayNotRefundedWarning.apply(prepayNotRefundedWarning.template.scala:83)
at views.html.mail.prepayNotRefundedWarning_Scope0$prepayNotRefundedWarning.render(prepayNotRefundedWarning.template.scala:99)
at views.html.mail.prepayNotRefundedWarning.render(prepayNotRefundedWarning.template.scala)
at actors.UserChecker.check(UserChecker.java:82)
at actors.UserChecker.lambda$initialize$0(UserChecker.java:57)
at akka.actor.LightArrayRevolverScheduler$$anon$2$$anon$1.run(LightArrayRevolverScheduler.scala:102)
at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:39)
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:415)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
This line: Format.date(Messages("format.dateTime", user.getLastRefill()) should be displaying the date in the right format, depending on the language file. For example, in german it would be Format.date("dd.mm.YYYY HH:mm", user.getLastRefill()) and display 27.11.2017 13:30.
Instead it gets Format.date("format.dateTime", user.getLastRefill()) and f isn’t a valid DateTimeFormatter pattern.
I guess Messages() is doing something behind the scene to work with a controller action that is missing here.
Can you better detail what you are trying to do? How your project is configured? Where is this error happening?
I want to send e-mail automatically to specific users. The error happen when the e-mail is being sent.
And which format are you using? I mean, what is the value for format in Format.date? It looks like you are using an invalid format since lowercased f is not a defined for format patterns:
I guess that because the Http.Context is not available, Messages() cannot know what language to use for the translation. Is there a way to pass the language code to use (for ex the language of the user)?
But I still have an issue with the lack of HTTP Context because of the reverse routing.
java.lang.RuntimeException: There is no HTTP Context available from here.
at play.mvc.Http$Context.current(Http.java:62)
at play.mvc.Http$Context$Implicit.lang(Http.java:359)
at views.html.layouts.email_Scope0$email.apply(email.template.scala:112)
at views.html.mail.prepayNotRefundedWarning_Scope0$prepayNotRefundedWarning.apply(prepayNotRefundedWarning.template.scala:58)
at views.html.mail.prepayNotRefundedWarning_Scope0$prepayNotRefundedWarning.render(prepayNotRefundedWarning.template.scala:108)
at views.html.mail.prepayNotRefundedWarning.render(prepayNotRefundedWarning.template.scala)
at actors.UserChecker.lambda$check$1(UserChecker.java:107)
at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1626)
at play.core.j.HttpExecutionContext$$anon$2.run(HttpExecutionContext.scala:56)
at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:39)
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:415)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
As @marcospereira mentioned above, there is no request available, so I guess you would not have the context.
Can you associate the user selected language with the user object? That way it would be available when you iterate over users in the for loop?
user.getLanguage() returns the language code (eg: “en”) from the database as a string.
The language seems to work with that workaround as @messages() gets the right text from the “messages.xx” file where “xx” is the language code.
However, as you pointed out, I don’t have a request object in my actor so I cannot perform usual jobs like reverse routing in my template…
Is there a way to make it work? Maybe creating a fake request object?
I am not sure how creating a fake request would help. Instead how about exposing the email sender utility as an endpoint? Make it extend controller, and move the actor based scheduling logic to the client code which after the periodic frequency makes a call to the endpoint which finds the users to send email to?
That way you will have the request object and it will be much more natural than trying to fake a request?
Hello, I’ve already implemented scheduling sending emails by configuring React frontend code to send requests to Scala Play backend code as a part of newsletter subscription service. You can have a look at it on the Github: