jquery - Grails 中长时间运行的异步调用和服务器推送

标签 jquery grails asynchronous websocket server-push

请注意:这里明显的答案是“修复需要 20 分钟才能完成的事情”。这不是我要寻找的答案,因为我无法控制作为这里的根本瓶颈的实际机制(参见下面的 WidgetProcessor)。

我有一个 Grails (2.4.3) 应用程序,它通过 HTML5 和 JS 将大部分处理放在客户端。我现在需要用户单击一个按钮,并且该事件会启动一个很长(3-20 分钟)的异步过程,最终应该导致用户的屏幕是动态的(无页面刷新)更新了结果。

在客户端(jQuery):

$(".my-button").click(function(e){
    var btn = $(this);

    $.ajax({
        type: 'GET',
        url: "/myapp/fizz/kickOffBigJob",
        data: {fizz: $(btn).attr('fizz')},
        success: function (data) {
        }
    })
});

点击后,发送到我的FizzController#kickOffBigJob()方法:
class FizzController {
    FizzServiceClient fizzServiceClient = FizzServiceFactory.newFizzServiceClient()

    // ... lots of other stuff

    // This is called when the button above is clicked.
    def kickOffBigJob(params) {
        // Send the request off to a RESTful web service. This service is what
        // handles the asynchronous process and ultimately returns a result
        // (a String). The service endpoint returns immediately ( < 500ms) but
        // the actual result can take up to 20 minutes to be computed.
        fizzServiceClient.kickOffBigJob(convertToWidget(params))
    }
}

内部 FizzService#kickOffBigJob() :
// This code is deployed to a different JVM/WAR that exposes RESTful endpoints that
// respond to 'fizzServiceClient.kickOffBigJob(Widget)'.
class FizzService {
    ExecutorService executor = initExecutor()

    // This method submits the 'widget' to an executor and then returns an HTTP response
    // to the service client. Note that this response is not the 'result' we're looking
    // for, it's just a quick indication that the request was received OK.
    def kickOffBigJob(Widget widget) {
        WidgetJob widgetJob = new WidgetJob(widget)
        executorService.submit(widgetJob)   // WidgetJob extends Runnable
    }
}

最后:
class WidgetJob implements Runnable {
    Widget widget
    WidgetProcessorFactory wpf = new WidgetProcessorFactory()

    // Constructors, etc.

    @Override
    def run() {
        WidgetProcessor processor = wpf.newWidgetProcess()

        // Where the magic happens; this is what takes up to 20 minutes to
        // compute the 'result'.
        String result = processor.process(widget)
    }
}

所以我现在有两个问题:
  • 如何沟通' result ' 我们在 WidgetJob#run() 内部计算回到 Grails Controller (FizzController);和
  • 如何动态推送'result ' 从 Grails Controller 返回到客户端 这样,在没有刷新页面的情况下,用户的 UI 会突然更新为“result” ' 值(value)。

  • 关于我如何做到这一点的任何想法?

    最佳答案

    这可以通过多种技术实现,但最干净的可能是以下技术:

  • 使用 jssh库(或 Atmosphere,或任何其他 Java websocket 库)在客户端浏览器和 Grails 应用程序之间创建 websocket; 将每个打开的 websocket 的引用存储在 Grails Controller 内的哈希图中 .也就是说,每次 Grails Controller 使用其中一个库来创建新的 websocket 时,都会在 map /缓存中的某处
  • 中存储对它的引用。
  • 向接受最终 result 的 Grails Controller 添加方法/操作作为其params之一论据

  • 现在,当 Grails Controller 收到启动长作业的请求时,它会在客户端创建一个开放的 websocket,将对此 websocket 的引用存储在 hashmap( Controller 本身的属性/字段)中,然后将执行委托(delegate)给上面定义的 web 服务。

    webservice 接收到这个请求,将它传递给一个执行器服务,并立即返回一个 HTTP 200 给 Grails 服务器。同时,执行器服务在处理结果时大吃一惊。大约 20 分钟后,计算结果并将其发送到接受结果的 Grails 应用程序的操作。这个 Action 和以前一样存在于同一个 Controller 中。

    此操作在 hashmap 中查找打开的 websocket 连接,找到它,并将结果发送回客户端。

    关于jquery - Grails 中长时间运行的异步调用和服务器推送,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25934002/

    相关文章:

    jquery - 如何使用jquery选择div inside div inside div

    jquery - 避免使用 JQuery 同时显示 2 个项目

    grails - 无法在 Grails 3.1.1 中安装 HTML5 拖放多文件上传插件

    sql - 在Grails中记录特定文件的SQL查询

    c# - 重载解析和异步等待

    javascript - 延迟返回等待异步函数(在卸载事件之前)

    javascript - jQuery 多维数组(动态键) - 无法设置未定义的属性

    grails - GrailsApplicationAware 的使用

    javascript - promise 异步等待没有 .then 回调

    javascript - 圆滑的轮播响应断点