Servlets 关于在Grails中执行异步处理的简单方法的建议

Servlets 关于在Grails中执行异步处理的简单方法的建议,servlets,grails,asynchronous,quartz-scheduler,Servlets,Grails,Asynchronous,Quartz Scheduler,假设我有这样一个简单的控制器: class FooController { def index = { someVeryLongCompution() //e.g crawl a set of web pages render "Long computation was launched." } } 调用index操作时,我希望该方法在异步运行长计算时立即返回给用户 def index = { def asyncProcess = new Thread(

假设我有这样一个简单的控制器:

class FooController {

  def index = {
     someVeryLongCompution() //e.g crawl a set of web pages
     render "Long computation was launched."
  }
}
调用index操作时,我希望该方法在异步运行长计算时立即返回给用户

def index = {
     def asyncProcess = new Thread({
          someVeryLongComputation()
     } as Runnable )
     asyncProcess.start()

     render "Long computation was launched."
  }
我知道最可靠的方法是在体系结构中使用MessageBroker,但我想知道是否有更简单的方法

我尝试了Executor插件,但它会阻止http请求返回,直到长时间的计算完成

我尝试了Quartz插件,但这似乎适用于定期任务(除非有办法只运行一次作业?)


你们在Grails中是如何处理这样的请求的?

如果在Grails Quartz中使用一个简单的触发器,并将repeatCount设置为0,那么作业将只运行一次。但是,它与用户请求分开运行,因此您需要找到一些方法在完成后与用户通信。

解决此类问题的最佳方法是通过使用JMS


为了更简单的实现,不需要externel服务器/服务,您可以尝试该插件。

您希望在同一台Grails服务器上或不同的服务器上在哪里处理veryLongComputation()

如果是同一台服务器,则不需要JMS,另一种选择是创建一个新线程并异步处理计算

def index = {
     def asyncProcess = new Thread({
          someVeryLongComputation()
     } as Runnable )
     asyncProcess.start()

     render "Long computation was launched."
  }

Try-它支持异步事件侦听器。

我知道这是一个非常老的问题,只是想给出一个更新的答案

由于grails 2.3,框架支持使用Servlet 3.0异步请求处理的异步调用(当然,必须使用Servlet 3.0容器,配置中的Servlet版本应为3.0,这是默认的)

这里有记录:

一般来说,有两种方法可以实现您的要求:

import static grails.async.Promises.*
   def index() {
      tasks books: Book.async.list(),
            totalBooks: Book.async.count(),
            otherValue: {
              // do hard work
            }
   }
或Servlet异步方式:

def index() {
    def ctx = startAsync()
    ctx.start {
        new Book(title:"The Stand").save()
        render template:"books", model:[books:Book.list()]
        ctx.complete()
    }
}

小提示-grails方法使用promises,这是一个重大的(异步)飞跃。任何承诺都可以链接到进一步承诺,在成功和失败等情况下进行回调。

如果您想使用Quartz插件(就像我们一直做的那样),您可以这样做。它对我们很有效:

定义作业(无定时触发器)

调用.triggerNow()以异步模式手动执行作业

MyJob.triggerNow([key1:value1, key2: value2]); 
Pro-Tip#1

要从另一侧获取命名参数

def execute(context) {
    def value1 = context.mergedJobDataMap.get('key1');
    def value2 = context.mergedJobDataMap.get('key2');
    ...
    if (value1 && value2) {
      // This was called by triggerNow(). We know this because we received the parameters.
    } else {
      // This was called when the application started up. There are no parameters. 
    }
}
Pro-Tip#2

execute方法总是在应用程序启动时被调用,但命名参数为null


文档:

Grails2.2.1解决方案我还有一个额外的要求,即报告完成后必须自动弹出一个窗口。因此,我从上面选择了servlet方式。我用一个json格式的字符串替换了render a视图,返回结果如下所示。 此外,我的客户端不是gsp视图,而是ExtJS 4.1.1(HTML5产品)

你试过GrailsAPI吗?它应该尽可能简单

import static grails.async.Promise
import static grails.async.Promises

class FooController {

  def index = {
     Promise p = Promises.task {
         someVeryLongCompution() //e.g crawl a set of web pages
     }
     render "Long computation was launched."
  }
}

executor插件不应该阻止http请求,它对我来说工作正常,我建议你再看看。最好使用executor插件,特别是它会将Hibernate会话附加到后台线程。@Peter我知道executor插件的会话集成,但OP没有提到Hibernate,因此,如果您不需要,就没有理由添加必要的开销。我的意思是“没有理由添加
不必要的
开销”,如果需要Hibernate,而您仍然使用此解决方案(不是Executor插件),这意味着什么?不一致、错误等?感谢您回答有关StackOverflow的问题。上面的代码或注释似乎并没有试图解决如何异步执行非常长的计算的问题。你能编辑它,使它集中在这一点上吗?现在的代码更完整了,我前面引用了一个解决方案。我想我不应该那样做。这段代码显示了一个grails控制器操作,并且正在生产环境中运行。
import static grails.async.Promise
import static grails.async.Promises

class FooController {

  def index = {
     Promise p = Promises.task {
         someVeryLongCompution() //e.g crawl a set of web pages
     }
     render "Long computation was launched."
  }
}