我有一个彗星(长轮询)Controller
调用,如果puts
没有运行该ID的计算,则会将一些ID和Consumer
带入阻塞队列从take
到queue
并对这些ID执行计算。我正在使用Springs
DeferredResult
进行异步支持。
我维护Map
DeferredResult
以及请求中收到的相应ID。当在消费者线程中完成id的计算时,我在Map
中检查该id,并设置关联的DeferredResults
setResult
,将响应发送回客户端。
在Controller
方法中,我onCompletion
回调了DeferredResult
,从DeferredResult
中移除了此Map
个对象。
客户端然后从其请求中删除此ID并发送剩余的ID。例如,客户端发送最初的ID为“1,2,3”,它们都被插入到BlockingQueue
中,并且表示id“2”的计算已提前完成,然后是DeferredResults
{{1}将被设置,它将响应返回给客户端。通过回调,此setResult
将从DeferredResult
中移除。并且下一个请求中的客户端将发送ID“1,3”。
现在一切正常,但是当我开始为此编写测试用例时,永远不会调用Map
回调。我甚至在泉水官方的例子中试过它,它似乎甚至没有被称为。有没有办法调用它,或者在我的实现中有些不正确的东西。
这是我的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;
}
调用@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());
}
}
方法并按预期收到响应,但由于Controller
回调从未被调用,我通过删除id再次调用该方法的逻辑需要命中{{{ 1}}保留过去的onCompletion
。
更新
测试类注释是:
Map
我有另一个观察,对DeferredResult
的调用未完成,即它不等待指定的5秒超时并立即返回,导致@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/test-context.xml" })
@WebAppConfiguration
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
为getLongPollingGraphData
。我读到了它,建议将result
添加到null
对象。
但这是我的测试用例的全部内容,我希望计算并返回结果,以便我可以根据收到的响应重新发送修改我的ids变量的请求。
答案 0 :(得分:0)
您使用的是哪个版本的Spring? 我已经为类似的案例打开SPR-13615,并在4.2.3(影响4.2.2)中得到修复。
如果您查看评论,可以使用
进行解决而无需更新 mvcResult.getRequest().getAsyncContext().complete();