I'm trying to create an async task that will not block the request. The user make the request, the task will start, and the controller will render "Job is running...", this is for avoid the request being blocked waiting the task to complete.
Once the task is finish, it will execute the onComplete and do something with the result of that task (for example call a service that will send a mail to an user)
| Error 2014-09-16 17:38:56,721 [Actor Thread 3] ERROR gpars.LoggingPoolFactory - Async execution error: null
The code is the following:
package testasync
import static grails.async.Promises.*
class TestController {
def index() {
//Create the job
def job1 = task {
println 'Waiting 10 seconds'
Thread.sleep(10000)
return 'Im done'
}
//On error
job1.onError { Throwable err ->
println "An error occured ${err.message}"
}
//On success
job1.onComplete { result ->
println "Promise returned $result"
}
render 'Job is running...'
}
Complete stacktrace:
| Error 2014-09-17 10:35:24,522 [Actor Thread 3] ERROR gpars.LoggingPoolFactory - Async execution error: null
Message: null
Line | Method
->> 72 | doCall in org.grails.async.factory.gpars.GparsPromise$_onError_closure2
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 62 | run in groovyx.gpars.dataflow.DataCallback$1
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run in java.util.concurrent.ThreadPoolExecutor$Worker
^ 745 | run . . . in java.lang.Thread
I ended using the executor framework with the grails-executor plugin. I uploaded a very basic example here: https://github.com/agusl88/grails-async-job-queuqe
That code is using a "custom" version of the grails-executor plugin, i merged some PR's from the plugin repo and packaged as jar just for testing propuses. The repo of the plugin is this: https://github.com/basejump/grails-executor
I was able to get rid of this exception in a controller by removing the onComplete and onError calls. I guess the exception happens because the parent thread ended when you called render.
So your:
Promise p = task {
complexAsyncMethodCall(); // (1) do stuff
}
.onComplete { result -> println result } // (2) on success
.onError { Throwable t -> System.err.println("Error: " + t) } // (3) on error
Becomes:
Promise p = task {
try {
def result = complexAsyncMethodCall(); // (1) do stuff
println result // (2) on success
} catch(Throwable t) {
System.err.println("Error: " + t) // (3) on error
}
}
This adds coupling between your work (1) and the result processing (2 and 3) but you could overcome this by writing your own Closure wrapper that takes extra Closures as arguments. Something like this:
// may not work! written off the top of my head
class ProcessableClosure<V> extends Closure<V> {
Closure<V> work;
Closure<?> onError;
Closure<?> onComplete;
#Override
public V call(Object... args) {
try {
def result = work.call(args); // (1) do stuff
onComplete.call(result); // (2) on complete
} catch(Exception e) {
onError.call(result); // (3) on error
}
}
}
That makes your code more readable:
Closure doWork = { complexAsyncMethodCall(); } // (1) do stuff
Closure printResult = { println it } // (2) on complete
Closure logError = { Throwable t -> log.error t } // (3) on error
Closure runEverythingNicely = new ProcessableClosure(work: doWork, onComplete: printResult, onError: logError)
Promise p = task { runEverythingNicely }
When creating a Promise async task inside a controller you actually have to return the response by calling the get() method on the task, or the onError and onComplete methods will never be called. Adding:
job1.get()
Before your call to render will resolve the issue.
In my case, just returning a promise worked.
MyService.groovy
import static grails.async.Promises.*
def getAsync(){
Promise p = task {
//Long running task
println 'John doe started digging a hole here.'
Thread.sleep(2000)
println 'John doe working......'
return 'Kudos John Doe!'
}
p.onError { Throwable err ->
println "Poor John"+err
}
p.onComplete { result ->
println "Congrats." +result
}
println 'John Doe is doing something here.'
return p
}
Related
I have a GroovyMock of a static method. When my mock method is called the test fails because the correct arguments were not used, even though I accept all arguments to the mock. Why is this please?
// FileDownloadingService.groovy
class FileDownloadingService {
// I am going to mock this static method
static void download(URL urlLocation, String localDir, String localName) {
}
}
// ServiceUnderTestService.groovy
class ServiceUnderTestService {
def downloadData(URL url) {
FileDownloadingService.download(url, "temp", "ReferenceData.gz")
}
}
// within ServiceUnderTestServiceSpec
void "file is downloaded"() {
given: "A url for the file to download"
def urlLocation = "http://example.com/ReferenceData.gz"
def url = new URL(urlLocation)
def fileDownloadMock = GroovyMock(FileDownloadingService, global: true)
when: "we call downloadData"
service.downloadData(url)
then: "we actually try to download it"
1 * fileDownloadMock.download(_, _, _)
}
I get the following error message:
| Too few invocations for:
1 * fileDownloadMock.download(_, _, _) (0 invocations)
Unmatched invocations (ordered by similarity):
1 * fileDownloadMock.download(http://example.com/ReferenceData.gz, 'temp', 'ReferenceData.gz')
at org.spockframework.mock.runtime.InteractionScope.verifyInteractions(InteractionScope.java:78)
at org.spockframework.mock.runtime.MockController.leaveScope(MockController.java:76)
Why does the mock not pass, as I'm specifying all parameters are valid, no?
For a static method, the interaction needs to be specified as follows:
1 * FileDownloadingService.download(*_) // or: (_, _, _)
I have created a service NotifierService to send emails using grails mail plugin.
class NotifierService {
MailService mailService
def sendWarningEmail(String name, String email, Date blockingDate) {
try {
mailService.sendMail {
to email
from "noreply-myApp#domain.com"
subject "Status message: Warning"
body (view:"/email/warningEmail", model:[
name:name,
blockingDate:blockingDate
])
}
} catch (Exception e) {
e.printStackTrace()
}
}
}
I have created another service ApplicationUtilService in which I am trying to use the NotifierService.
class ApplicationUtilService{
def notifierService
def notifyUser(){
notifierService.sendWarningEmail("User name", "user#domain.com", new Date())
}
}
I am trying to call notifyUser() in a grails job UpdateJob
class UpdateJob{
def applicationUtilService
static triggers = {
// Scehduling parameters
}
def execute(){
applicationUtilityService.notifyUser()
}
}
I get the following error
Error 2014-12-05 12:04:53,550 [quartzScheduler_Worker-1] ERROR listeners.ExceptionPrinterJobListener - Exception occurred in job: Grails Job
Message: java.lang.NullPointerException: Cannot invoke method notifyUser() on null object
Line | Method
->> 111 | execute in grails.plugins.quartz.GrailsJobFactory$GrailsJob
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 202 | run in org.quartz.core.JobRunShell
^ 573 | run . . in org.quartz.simpl.SimpleThreadPool$WorkerThread ...`
It works when I instantiate as
ApplicationUtilService applicationUtilService = new ApplicationUtilService()
instead of using grails dependency injection. Again, the same problem with the notifierService in ApplicationUtilService and fixed by instantiating same as above.
Now, the real problem is with the mailService. The instantiation as above didn't work. How could I resolve it
The Null Pointer is occurring on UpdateJob.applicationUtilService, so it seems like applicationUtilService isn't being injected into UpdateJob correctly. Is UpdateJob in the right package?
In My Grails service, there is a part of a method I wish to run asynchronously.
Following, the doc for 2.3.x http://grails.org/doc/2.3.0.M1/guide/async.html
I do
public class MyService {
public void myMethod() {
Promise p = task {
// Long running task
}
p.onError { Throwable err ->
println "An error occured ${err.message}"
}
p.onComplete { result ->
println "Promise returned $result"
}
// block until result is called
def result = p.get()
}
}
However, I want to execute mine without any blocking. The p.get() method blocks. How do I execute the promise without any sort of blocking. I don't care if myMethod() returns, it is a kinda of fire and forget method.
So, according to the documentation if you don't call .get() or .waitAll() but rather just make use of onComplete you can run your task without blocking the current thread.
Here is a very silly example that I worked up in the console to as a proof of concept.
import static grails.async.Promises.*
def p = task {
// Long running task
println 'Off to do something now ...'
Thread.sleep(5000)
println '... that took 5 seconds'
return 'the result'
}
p.onError { Throwable err ->
println "An error occured ${err.message}"
}
p.onComplete { result ->
println "Promise returned $result"
}
println 'Just to show some output, and prove the task is running in the background.'
Running the above example gives you the following output:
Off to do something now ...
Just to show some output, and prove the task is running in the background.
... that took 5 seconds
Promise returned the result
I get the error "Caused by NullPointerException: null ->> 64 | getMailConfig in grails.plugin.mail.MailService". I have configured the config.groovy as per the documentation provided by mail plugin.
Please help me to resolve this issue.
Find my config.groovy code below.
grails
{
mail {
host = "smtp.gmail.com"
port = 465
username = "xxxxxx#gmail.com"
password = "xxxxxx"
props = ["mail.smtp.auth":"true",
"mail.smtp.socketFactory.port":"465",
"mail.smtp.socketFactory.class":"javax.net.ssl.SSLSocketFactory",
"mail.smtp.socketFactory.fallback":"false"]
}
}
Find my groovy class code below.
package common
import grails.plugin.mail.*;
public class FlowSchedule implements Job {
def mailService = new MailService()
public void execute(JobExecutionContext context)
throws JobExecutionException {
//some extra logic here
sendEmail(schedulerEntry.name,schedulerEntry.email)
}
def sendEmail(String name,String email)
{
mailService.sendMail {
to "amith.ravuru#citrix.com"
subject "Hello Amith"
body 'this is some text'
}
}
}
Complete Error trace:
Error |
2014-07-14 12:41:00,041 [DefaultQuartzScheduler_Worker-4] ERROR core.ErrorLogger - Job (group.Job_1 threw an exception.
Message: Job threw an unhandled exception.
Line | Method
->> 213 | run in org.quartz.core.JobRunShell
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
**^ 573 | run in org.quartz.simpl.SimpleThreadPool$WorkerThread
Caused by NullPointerException: null**
**->> 64 | getMailConfig in grails.plugin.mail.MailService**
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 59 | sendMail in ''
| 94 | sendEmail in common.FlowSchedule$$EOk1HyVA
| 79 | execute in ''
| 202 | run in org.quartz.core.JobRunShell
^ 573 | run in org.quartz.simpl.SimpleThreadPool$WorkerThread
I solved the issue by moving the sendEmail part to a controller. Then, call the controller method from any class in src/groovy. Because, in controllers, grailsApplication can be injected using def grailsApplication. Please find the controller code below.
class SendMailController
{
def grailsApplication
def sendEmail(String name,String email,String mailsubject)
{
if(email != null)
{
try
{
sendMail {
to email
from "exabgpnotifier#gmail.com"
subject "ExaBGP Notification"
body "Hello "+name+"\n\n"+ mailsubject +" \n\nRegards,\nExaBGP Team"
}
}
catch(Exception e)
{
e.printStackTrace()
println "ERROR!!: Unable to send the notification to email "+ finalemaillist.toString()
}
}
}
}
I guess that this plugin injects mailService into your application. So instead of creating service with constructor like you've done:
def mailService = new MailService()
Just declare the field and let DI mechanism to do the work of injecting the value:
def mailService
The remaining part of your code looks okay. Think about changing the name of sendMail method, now it's a bit confusing when you've got the same names for your method and the one from mailService.
Hope it'll help!
I don't think this will work:
grails
{
mail {
host = "smtp.gmail.com"
port = 465
username = "xxxxxx#gmail.com"
password = "xxxxxx"
props = ["mail.smtp.auth":"true",
"mail.smtp.socketFactory.port":"465",
"mail.smtp.socketFactory.class":"javax.net.ssl.SSLSocketFactory",
"mail.smtp.socketFactory.fallback":"false"]
}
}
That is valid code but doesn't do what you intend. The opening curly brace after grails needs to be on the same line so the closure is treated as an argument to the grails method.
grails {
mail {
host = "smtp.gmail.com"
port = 465
username = "xxxxxx#gmail.com"
password = "xxxxxx"
props = ["mail.smtp.auth":"true",
"mail.smtp.socketFactory.port":"465",
"mail.smtp.socketFactory.class":"javax.net.ssl.SSLSocketFactory",
"mail.smtp.socketFactory.fallback":"false"]
}
}
Open you resources.groovy file and put this entry.
import common.FlowSchedule
beans = {
// make sure you import flow schedule class
flowSchedule(FlowSchedule) {
mailService = ref('mailService')
}
}
Then in your class.
package common
import grails.plugin.mail.*;
public class FlowSchedule implements Job {
def mailService
public void execute(JobExecutionContext context)
throws JobExecutionException {
//some extra logic here
sendEmail(schedulerEntry.name,schedulerEntry.email)
}
def sendEmail(String name,String email)
{
mailService.sendMail {
to "amith.ravuru#citrix.com"
subject "Hello Amith"
body 'this is some text'
}
}
}
When you need flow schedule in any controller or service then just do this
class MyService {
def flowSchedule
def myMethod() {
flowSchedule.sendEmail('test','test#test.com')
}
}
I am in grails 2.3.1 - trying to use the async features.
This is bulk data processing. I am trying to synchronise 2 databases, which involves comparing both and returning a list of 'deltas'. I am trying to speed up the process
The documentation says I can just add a set of closures to a PromiseList and then call onComplete() to check that all the closures have completed. These are my attempts - directly building on "You can also construct a PromiseList manually" in the documentation:
def tasksMemberDeltas = new PromiseList()
pages.each {Integer page ->
tasksMemberDeltas << {findCreateMemberDeltas(page, (page + pageSize) - 1)}
if (page % 30 == 0) {
tasksMemberDeltas.onComplete {
tasksMemberDeltas = new PromiseList()
}
}
Returns:
Error groovy.lang.MissingMethodException:
No signature of method: java.util.ArrayList.onComplete()
In the end I called .get() which calls waitAll. Going into .get() and finding that it did waitAll was my revelation.
So if I have a single task I call:
waitAll finalDeltas
If I have a list I call:
taskFinalDeltas.get()
onComplete() logically relates to a single delta. Not the list. So this works OK:
Promise memberDeleteDeltas = task {
findDeleteAndTagDeltas()
}
memberDeleteDeltas.onError { Throwable err ->
println "An error occured ${err.message}"
}
memberDeleteDeltas.onComplete { result ->
println "Completed create deltas"
}
waitAll(memberDeleteDeltas)