2014-09-19 2 views
1

참고 : 여기서 명백한 대답은 "완료하는 데 20 분이 걸리는 것을 수정합니다"입니다. 내가 여기에서 루트 병목 현상 인 실제 메커니즘 (아래의 WidgetProcessor 참조)에 대한 제어권이 없기 때문에 이것이 내가 찾는 대답이 아닙니다.Grails에서 장기 실행 비동기 호출 및 서버 푸시

HTML5와 JS를 통해 대부분의 처리를 클라이언트 쪽에서 처리하는 Grails (2.4.3) 응용 프로그램이 있습니다. 이제 사용자가 버튼을 클릭 할 필요가 있으며,이 이벤트가 매우 긴 시간 (어디에서 3 분에서 20 분까지) 비동기 프로세스로 시작되는지 궁극적으로 사용자의 화면이 동적으로 표시되어야합니다 (페이지 새로 고침) 결과가 업데이트되었습니다.

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 
    } 
} 

그리고 마지막으로

클릭에
$(".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() 방법에 보내 클라이언트 측 (jQuery를)에

:

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) 
    } 
} 
그래서 지금은이 문제가 :

  1. (가) 'result은'우리 내부의 Grails의 컨트롤러 (FizzController) 다시 WidgetJob#run()을 계산 통신하는 방법; 그리고
  2. Grails 컨트롤러의 'result'을 클라이언트 측 으로 동적으로 밀어 넣는 방법으로 페이지를 새로 고치지 않고 사용자의 UI가 갑자기 'result'값으로 업데이트됩니다.

어떻게하면이 작업을 수행 할 수 있습니까?

+0

당신이 asynch를 통해 할 수 있는지 의심 스럽습니다. 이것은 별도의 프로세스를 시작하기 때문입니다. 프론트 엔드가 업데이트를 위해 폴링하는 db 테이블을 업데이트하는 비동기 작업을 얻을 수 있습니다. 또는 웹 소켓을 볼 수도 있고, 상황에 따라 작동하는지 확실하지 않을 수도 있습니다. jssh 플러그인을 살펴보십시오. - 웹 소켓을 사용하여 상호 작용합니다. 백엔드 서버 및 실제 실시간 결과. – Vahid

답변

0

이 기술의 번호로 가능하지만, 가장 깨끗한는 아마도 다음

  • 는 사이에 웹 소켓을 만들 수 jssh 라이브러리 (또는 분위기, 또는 다른 Java 웹 소켓 라이브러리 중 하나를) 사용 클라이언트 브라우저와 Grails 앱; Grails 컨트롤러 내부의 해시 맵에 열려있는 각 웹 소켓에 대한 참조를 저장합니다. 즉, Grails 컨트롤러가 이러한 라이브러리 중 하나를 사용하여 새로운 websocket을 생성 할 때마다 맵/캐시에있는 참조를 어딘가에 저장하십시오.
  • 마지막으로 result을 허용하는 메소드/액션을 Grails 컨트롤러에 추가하십시오 Grails의 컨트롤러가 긴 작업 발로 대한 요청을 받으면 해당 params 인수

이제 다음, 그 해시 맵이 웹 소켓에 대한 참조가 저장되어있는 클라이언트 측 열려 웹 소켓 (속성을 생성/컨트롤러 자체의 필드), 위에서 정의 된대로 웹 서비스에 실행을 위임합니다.

웹 서비스는이 요청을 받으면이를 실행자 서비스에 전달하고 HTTP 200을 다시 Grails 서버에 반환합니다. 한편, 집행자 서비스는 결과를 처리하는 데 어려움을 겪습니다.약 20 분 후에 그 결과가 계산되어 그 결과를 받아들이는 Grails 앱의 액션으로 보내집니다. 이 동작은 이전과 동일한 컨트롤러 내에 존재합니다.

이 조치는 해시 맵에서 열린 websocket 연결을 찾아서 찾은 다음 그 결과를 클라이언트 측에 다시 보냅니다.