异步作业出错

时间:2014-09-16 20:53:57

标签: grails groovy

我正在尝试创建一个不会阻止请求的异步任务。用户发出请求,任务将启动,控制器将呈现“作业正在运行...”,这是为了避免请求被阻止等待任务完成。 任务完成后,它将执行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

4 个答案:

答案 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)

通过删除onCompleteonError调用,我能够在控制器中消除此异常。我猜这个异常是因为父线程在你调用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()方法来返回响应,否则将永远不会调用onErroronComplete方法。添加:

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
}