Java 如何在将来取消时在Callable内终止CXF webservice调用

Java 如何在将来取消时在Callable内终止CXF webservice调用,java,cxf,future,interrupt,callable,Java,Cxf,Future,Interrupt,Callable,编辑 这个问题到目前为止已经经过了几次迭代,所以请随意查看修订版,以查看有关历史和尝试过的事情的一些背景信息 我将CompletionService与ExecutorService和Callable一起使用,通过CXF生成的代码在几个不同的Web服务上并发调用多个函数。。这些服务都为我在项目中使用的一组信息提供了不同的信息。但是,服务可能会在长时间内无法响应,而不会引发异常,从而延长对组合信息集的等待时间 为了解决这个问题,我将同时运行所有服务调用,几分钟后,我想终止任何尚未完成的调用,最好从

编辑

这个问题到目前为止已经经过了几次迭代,所以请随意查看修订版,以查看有关历史和尝试过的事情的一些背景信息


我将CompletionService与ExecutorService和Callable一起使用,通过CXF生成的代码在几个不同的Web服务上并发调用多个函数。。这些服务都为我在项目中使用的一组信息提供了不同的信息。但是,服务可能会在长时间内无法响应,而不会引发异常,从而延长对组合信息集的等待时间

为了解决这个问题,我将同时运行所有服务调用,几分钟后,我想终止任何尚未完成的调用,最好从可调用的内部或通过抛出详细的异常来记录哪些调用尚未完成

下面是一些高度简化的代码来说明我已经在做的事情:

private Callable<List<Feature>> getXXXFeatures(final WiwsPortType port, 
final String accessionCode) {
    return new Callable<List<Feature>>() {
        @Override
        public List<Feature> call() throws Exception {
            List<Feature> features = new ArrayList<Feature>();
            //getXXXFeatures are methods of the WS Proxy
            //that can take anywhere from second to never to return
            for (RawFeature raw : port.getXXXFeatures(accessionCode)) {
                Feature ft = convertFeature(raw);
                features.add(ft);
            }
            if (Thread.currentThread().isInterrupted())
                log.error("XXX was interrupted");
            return features;
        }
    };
}
private可调用getXXXFeatures(最终WiwsPortType端口,
最终字符串访问代码){
返回新的可调用(){
@凌驾
公共列表调用()引发异常{
列表功能=新建ArrayList();
//getXXXFeatures是WS-Proxy的方法
//从第二秒到永远都不会回来
for(RawFeature原始:port.getXXXFeatures(accessionCode)){
特征ft=转换特征(原始);
特征。添加(英尺);
}
如果(Thread.currentThread().isInterrupted())
日志错误(“XXX被中断”);
返回特性;
}
};
}
以及并发启动WS调用的代码:

WiwsPortType port = new Wiws().getWiws();
List<Future<List<Feature>>> ftList = new ArrayList<Future<List<Feature>>>();
//Counting wrapper around CompletionService, 
    //so I could implement ccs.hasRemaining()
CountingCompletionService<List<Feature>> ccs = 
        new CountingCompletionService<List<Feature>>(threadpool);
ftList.add(ccs.submit(getXXXFeatures(port, accessionCode)));
ftList.add(ccs.submit(getYYYFeatures(port accessionCode)));
ftList.add(ccs.submit(getZZZFeatures(port, accessionCode)));

List<Feature> allFeatures = new ArrayList<Feature>();
while (ccs.hasRemaining()) {
            //Low for testing, eventually a little more lenient
    Future<List<Feature>> polled = ccs.poll(5, TimeUnit.SECONDS);
    if (polled != null)
        allFeatures.addAll(polled.get());
    else {
        //Still jobs remaining, but unresponsive: Cancel them all
        int jobsCanceled = 0;
        for (Future<List<Feature>> job : ftList)
            if (job.cancel(true))
                jobsCanceled++;
        log.error("Canceled {} feature jobs because they took too long",
                        jobsCanceled);
        break;
    }
}
WiwsPortType port=newwiws().getWiws();
List ftList=new ArrayList();
//计算CompletionService周围的包装器,
//这样我就可以实现ccs.haslaining()
CountingCompletionService ccs=
新CountingCompletionService(线程池);
ftList.add(ccs.submit(getXXXFeatures(port,accessionCode));
ftList.add(ccs.submit(getyyyyyfeatures(端口访问代码));
ftList.add(ccs.submit(getZZZFeatures(port,accessionCode));
List allFeatures=new ArrayList();
while(ccs.haslaining()){
//低测试,最终更宽松一点
未来轮询=ccs.轮询(5,时间单位秒);
如果(轮询!=null)
allFeatures.addAll(polled.get());
否则{
//作业仍然存在,但没有响应:全部取消
int jobsCanceled=0;
对于(未来工作:ftList)
if(作业取消(true))
jobsCanceled++;
log.error(“取消了{}功能作业,因为它们花费的时间太长”,
职位空缺);
打破
}
}
我在这段代码中遇到的问题是,在等待port.getXXXFeatures(…)返回时,实际上并没有取消可调用项,而是以某种方式保持运行。从
if(Thread.currentThread().isInterrupted())log.error(“XXX被中断”)中可以看到语句中断标志在port.getFeatures返回后设置,这仅在Webservice调用正常完成后可用,而不是在调用Cancel时中断

有人能告诉我我做错了什么,以及如何在给定的时间段后停止正在运行的CXF Webservice调用,并在我的应用程序中注册此信息吗


向您致意,Tim

编辑3新答案

我看到这些选择:

  • 将您的问题作为功能请求发布到Apache CXF上
  • 自己修复ACXF并公开一些功能
  • 在Apache CXF中寻找异步WS-call支持选项
  • 考虑切换到不同的WS-provider(JAX-WS?)
  • 如果服务支持RESTful API,您的WS是否使用RESTful API调用自己(例如,带参数的普通HTTP请求)
  • 仅供über专家使用:使用真正的线程/线程组,并使用非正统方法杀死线程

CXF文档中有一些关于设置HTTPURLConnection上的读取超时的说明:


那可能会满足你的需要。如果服务器没有及时响应,将引发异常,可调用方将获得异常。(除了有一个可能挂起的bug。我不记得是2.2.2修复了这个bug,还是现在只是在快照中。)

抱歉,但这是如何工作的?您不能简单地“取消”可调用的。。您只能在提交Callable时取消返回的Future。。我看不出在将url提交给执行者后,一旦该url丢失,我将如何从该可调用url中获取该url。将问题重新表述为日志记录不再是问题:问题是webservice调用一开始没有被取消!感谢到目前为止的帮助,让我们看看这种重新措辞会带来什么新的答案。我也会调整我的答案,这样它就不会吸引反对票。若要将取消限制在内部,请使用isCancelled()方法。如果您在等待/IO上被阻止,您的cancel调用也会在内部导致InterruptedException。isCancelled()仅在将来可用,而我的代码驻留在可调用中,因此第一行无法工作。。至于第二行:我已经尝试(但正如我所说的,很糟糕)捕获可调用函数中的任何类型的异常,但到目前为止无法做到。。将call()中的所有行包含在try/catch块中以用于InterruptedException失败,因为存在无法访问的catch块异常,因为该异常从未从try语句体抛出。(或者Eclipse是这么说的;))这个令人恐惧的Thread类中有什么丑陋的老东西可以在这里提供帮助吗?应该有,因为取消操作会导致某些阻塞操作上的IntExc。然而,我对这个假设有困难:并不是每个阻塞都可以这样中断——我认为synchronized()就是这样