我正在尝试创建一个不会阻止请求的异步任务。用户发出请求,任务将启动,控制器将呈现“作业正在运行...”,这是为了避免请求被阻止等待任务完成。 任务完成后,它将执行onComplete并对该任务的结果执行某些操作(例如,调用将向用户发送邮件的服务)
| Error 2014-09-16 17:38:56,721 [Actor Thread 3] ERROR gpars.LoggingPoolFactory - Async execution error: null
代码如下:
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...'
}
完成堆栈跟踪:
| 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
答案 0 :(得分:3)
我最后使用带有grails-executor插件的执行器框架。我在此处上传了一个非常基本的示例:https://github.com/agusl88/grails-async-job-queuqe
该代码使用grails-executor插件的“自定义”版本,我从插件仓库合并了一些PR,并打包为jar,仅用于测试propuses。插件的回购是:https://github.com/basejump/grails-executor
答案 1 :(得分:1)
通过删除onComplete
和onError
调用,我能够在控制器中消除此异常。我猜这个异常是因为父线程在你调用render
时结束了。
所以你的:
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
变为:
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
}
}
这增加了你的工作(1)和结果处理(2和3)之间的耦合,但你可以通过编写自己的Closure
包装器来解决这个问题,它将额外的Closures作为参数。像这样:
// 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
}
}
}
这使您的代码更具可读性:
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 }
答案 2 :(得分:0)
在控制器中创建Promise异步任务时,您实际上必须通过调用任务上的get()
方法来返回响应,否则将永远不会调用onError
和onComplete
方法。添加:
job1.get()
在致电render
之前解决问题。
答案 3 :(得分:0)
就我而言,仅兑现承诺即可。
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
}