2017-06-22 82 views
1

假設我有一些服務S接收到來自客戶端C的請求。 由於計算量過大,S不能立即響應,C也不能等到永遠,並且有他自己的超時期限。Spring MVC中的延遲計算

我的想法是實現服務器端如下所述: REST and long running jobs, Farazdagi

在我ServerController我有延遲計算一個線程池,併發圖來存儲響應。

private final int NUMBER_OF_WORKERS = 10; 
private Map<String, ResponseEntity<MathResponse>> responseMap = new ConcurrentHashMap<>(); 
private ExecutorService executorService = Executors.newFixedThreadPool(NUMBER_OF_WORKERS); 

/calculate測繪作業提交到線程池,並返回202 (Accepted) HTTP狀態,並把重定向鏈接Location頭。

@RequestMapping(value = "/calculate", method = RequestMethod.POST) 
public ResponseEntity<String> startWorkflow(@RequestBody MathRequest request, UriComponentsBuilder builder) { 
    UUID uuid = UUID.randomUUID(); 
    executorService.submit(() -> { 
     // time-consuming calculations here 
     ResponseEntity<MathResponse>response = HardMath.execute(request) 
     responseMap.put(uuid.toString(), response); 
    }); 

    HttpHeaders headers = new HttpHeaders(); 
    UriComponents uriComponents = builder.path("/wf/queue/{id}").buildAndExpand(uuid.toString()); 
    headers.setLocation(uriComponents.toUri()); 
    return new ResponseEntity<>(headers, HttpStatus.ACCEPTED); 
} 

/queue/id映射我返回的結果,如果它在地圖:

@RequestMapping(value = "/queue/{id}", method = RequestMethod.GET) 
public ResponseEntity<MathResponse> getQueueInfo(@PathVariable("id") String id) { 
    ResponseEntity<MathResponse> defaultQueueResponse = new ResponseEntity<>(new MathResponse(), HttpStatus.OK); 
    return responseMap.getOrDefault(id, defaultQueueResponse); 
} 

我認爲,採用這種低層次的東西一樣ConcurrentHashMap是不是一個好主意。 Spring中有沒有我可以使用的選項,而不是重新發明輪子?

+1

看起來你的地圖永遠不會被清除。可能是這裏的內存泄漏。實際上,您可以使用任何存儲 - 在內存DB或隊列中,結果也是帶有序列化響應的消息。 – StanislavL

+0

是的,我知道這一點。我只是想解釋一下這個想法,並展示一些我不信任的時刻。 –

+0

你認爲其他一切都適用嗎? –

回答

1

還有韌性的問題;如果結果對於S的一個實例是本地的(即在進程內的Map中),那麼如果S的這個實例崩潰或重新啓動,那麼結果將丟失,並且C將被迫重新提交它的請求。如果S中的結果緩存是由彈性的存儲庫的支持,則結果可能生存S.

的崩潰/重啓

Spring的caching abstraction與< 插入存儲這裏技術後備存儲>可能會有幫助。