Spring DeferredResult onCompletion未从测试用例中调用

rd2*_*d22 7 java spring asynchronous spring-mvc

我有一个彗星(长轮询)Controller呼叫,这需要在一些id和puts然后进入阻塞队列,如果没有计算该id运行时,用于Consumertakequeue与这些ID执行计算.我正在使用Springs DeferredResultasynch支持.

我维持MapDeferredResult,并在请求中接收到的相应的ID.当在消费者线程中完成id的计算时,我在其中检查该id Map并设置关联DeferredResults setResult,该响应将响应发送回客户端.

Controller方法中,我有一个onCompletion回调,DeferredResult从中删除此DeferredResult对象Map.

然后,客户端从其请求中删除此ID并发送剩余的ID.例如,客户端发送的初始ID为"1,2,3",它们都被插入BlockingQueue并且说id"2"的计算先前完成,然后DeferredResults setResult将其设置,这将响应返回给客户端.通过回调,这DeferredResult将被删除Map.并且下一个请求中的客户端将发送ID"1,3".

现在一切正常,但是当我开始为此编写测试用例时,onCompletion永远不会调用回调.我甚至在泉水官方的例子中试过它,它似乎甚至没有被称为.有没有办法在我的实现中调用它,或者某些东西是不正确的.

这是我的Controller方法:

@RequestMapping(value = "views/getLongPollingGraphData", method = RequestMethod.GET, headers = "Accept=application/json")
@ResponseBody
public DeferredResult<WebServiceResponse> getLongGraphData(
        HttpServletRequest request,
        @RequestParam(value = "ids") String ids) 
{
    //create a default response in case, when no result has been calculated till timeout
    WebServiceResponse awrDefault = new WebServiceResponse();

    //set time out this DeferredResult, after 5 seconds 
    final DeferredResult<WebServiceResponse> deferredResult = new DeferredResult<WebServiceResponse>(5000L, awrDefault);

    //logic to set in blocking queue
    //mMapOfDeferredResultAndViews.put(deferredResult, listOfViews.keySet());

    deferredResult.onCompletion(new Runnable() {
        @Override
        public void run() 
        {
            mMapOfDeferredResultAndViews.remove(deferredResult);
        }
    });

    return deferredResult;
}
Run Code Online (Sandbox Code Playgroud)

以下是测试用例的一部分:

@Before
public void setup() 
{
    this.mockMvc = webAppContextSetup(this.wac).build();
}

@Test
public void testLongPollGraphData()
{
    try
    {         
        String ids = "22,23,25";
        List<Integer> idList = convertStringToList(ids);

        while(idList.size() > 0)
        {
            MvcResult mvcResult = this.mockMvc.perform(get("/views/getLongPollingGraphData")
                .contentType(MediaType.APPLICATION_JSON)
                .param("ids", ids)          
                .andReturn();

            this.mockMvc.perform(asyncDispatch(mvcResult));
            WebServiceResponse result = (WebServiceResponse)mvcResult.getAsyncResult();

            if(result != null)
            {
                EJSChartsData chartsData = (EJSChartsData)result.getResponse();
                if(chartsData != null && chartsData.getViewId() != -1)
                {
                    int viewId = chartsData.getViewId();
                    idList.remove((Integer)viewId);
                    ids = idList.toString().replace("[", "").replace("]", "");
                }
            }
        }
    }
    catch(Exception e)
    {
        fail(e.toString());
    }
}
Run Code Online (Sandbox Code Playgroud)

Controller方法被调用,我按预期收到响应,但由于onCompletion回调从未被调用,我通过删除id再次调用方法的逻辑将命中作为Map过去的保持DeferredResult.

更新

测试类注释是:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/test-context.xml" })
@WebAppConfiguration
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
Run Code Online (Sandbox Code Playgroud)

我还有一个观察,呼叫getLongPollingGraphData没有完成,也就是说,它不会等待5秒指定的超时时间,并立即返回并导致resultnull.我读了它,建议添加.andExpect(request().asyncResult("Expected output"))mockMvc对象.

但这是我的测试用例的全部内容,我希望计算并返回结果,以便我可以根据收到的响应重新发送修改我的ids变量的请求.

kew*_*wne 0

你使用什么版本的Spring?我已经针对类似情况打开了SPR-13615,并在 4.2.3 中修复了该问题(影响 4.2.2)。

如果您查看评论,您可以使用以下方法解决此问题而无需更新

    mvcResult.getRequest().getAsyncContext().complete();
Run Code Online (Sandbox Code Playgroud)