StreamCache FileNotFound在组播路由中发出更大的数据

时间:2014-09-04 04:44:06

标签: apache-camel

我们正在使用camel 2.13.2 - 我有一个带有AggregationStrategy的组播路由  在每个多播分支中,我们有一个自定义的camel组件,它返回大量数据(大约4 MB)并写入Stream Cache(缓存输出流),我们需要聚合多播中的数据(聚合策略)。

在Aggregation策略中,我需要使用camel XPathBuilder进行XPath评估。   因此,我尝试读取正文并从StreamCache转换为byte []以避免在类型转换过程中出现错误:org.apache.camel.converter.stream.InputStreamCache。在XPathBuilder中。

当我尝试在聚合策略开始时读取正文时,我收到以下错误。

* / tmp / camel / camel-tmp-4e00bf8a-4a42-463a-b046-5ea2d7fc8161 / cos6047774870387520936.tmp(没有这样的文件或目录),原因:FileNotFoundException:/ tmp / camel / camel-tmp- 4e00bf8a-4a42-463a-b046-5ea2d7fc8161 / cos6047774870387520936.tmp(没有这样的文件或目录)。         at java.io.FileInputStream.open(Native Method)         在java.io.FileInputStream。(FileInputStream.java:138)         at org.apache.camel.converter.stream.FileInputStreamCache.createInputStream(FileInputStreamCache.java:123)at org.apache.camel.converter.stream.FileInputStreamCache.getInputStream(FileInputStreamCache.java:117)         at org.apache.camel.converter.stream.FileInputStreamCache.writeTo(FileInputStreamCache.java:93)         在org.apache.camel.converter.stream.StreamCacheConverter.convertToByteArray(StreamCacheConverter.java:102)         at com.sap.it.rt.camel.aggregate.strategies.MergeAtXPathAggregationStrategy.convertToByteArray(MergeAtXPathAggregationStrategy.java:169)         在com.sap.it.rt.camel.aggregate.strategies.MergeAtXPathAggregationStrategy.convertToXpathCompatibleType(MergeAtXPathAggregationStrategy.java:161) *

以下是抛出错误的代码行:

        Object body = exchange.getIn().getBody(); 
        if( body instanceof StreamCache){ 
                StreamCache cache = (StreamCache)body; 
                xml = new String(convertToByteArray(cache,exchange));                                            
                exchange.getIn().setBody(xml); 
        } 

通过在多播相关路由中设置10MB的阈值来禁止流缓存写入文件,我们能够使用聚合策略。但我们不希望这样做,因为我们可能有更大的传入数据。

<camel:camelContext id="multicast_xml_1" streamCache="true">
    <camel:properties>
        <camel:property key="CamelCachedOutputStreamCipherTransformation" value="RC4"/>
        <camel:property key="CamelCachedOutputStreamThreshold" value="100000000"/>
    </camel:properties>
    ....
</camel:camelContext>

注意:如果我们在具有其他处理器的路由中使用基于StreamCache的camel组件但没有多播+聚合,则不会出现FileNotFound问题。

经过调试,我可以理解使用MulticastProcessor从StreamCache聚合大量数据的问题。

在MulticastProcessor.java中:调用doProcessParallel()并在完成多播的分支交换时,CachedOutputStream删除/清除临时文件。

甚至在多播分支交换到达聚合策略之前就会发生这种情况,聚合策略试图从分支交换机读取数据。如果StreamCache中存在大量数据,则临时文件已被删除,从而导致FileNotFound问题。

public CachedOutputStream(Exchange exchange, boolean closedOnCompletion) { 
    this.strategy = exchange.getContext().getStreamCachingStrategy(); 
    currentStream = new CachedByteArrayOutputStream(strategy.getBufferSize()); 

    if (closedOnCompletion) { 
        // add on completion so we can cleanup after the exchange is done such as deleting temporary files 
        exchange.addOnCompletion(new SynchronizationAdapter() { 
            @Override 
            public void onDone(Exchange exchange) { 
                try { 
                    if (fileInputStreamCache != null) { 
                        fileInputStreamCache.close(); 
                    } 
                    close();
                } catch (Exception e) { 
                    LOG.warn("Error deleting temporary cache file: " + tempFile, e); 
                } 
            } 

            @Override 
            public String toString() { 
                return "OnCompletion[CachedOutputStream]"; 
            } 
        }); 
    } 
} 

public void close() throws IOException { 
    currentStream.close(); 
    cleanUpTempFile(); 
}

如果我尝试设置closedOnCompletion = false,我可以绕过这个问题,同时在任何多播分支的任何组件中写入CachedOutputStream。

但这是一个漏洞的解决方案,因为streamcache临时文件可能永远不会被清除...因此我在读取AggregationStrategy中的数据后尝试关闭+清理缓存流。

是否可以调整MulticastProcessor以使多播分支交换仅在多播结束后聚合后达到“完成”状态?

请帮助/提供有关此问题的建议,因为我不熟悉使用camel Multicast。

谢谢, 拉克希米

1 个答案:

答案 0 :(得分:1)

我尝试向Restlet请求发送大于1MB的JSON响应时抛出了类似的异常(是的,我知道1MB JSON太大了):

java.io.FileNotFoundException: C:\Users\me\AppData\Local\Temp\camel\camel-tmp-7ad6e098-538d-4d4c-9357-2b7addb1f19d\cos6725022584818060586.tmp (The system cannot find the file specified)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(FileInputStream.java:146)
at org.apache.camel.converter.stream.FileInputStreamCache.createInputStream(FileInputStreamCache.java:123)
at org.apache.camel.converter.stream.FileInputStreamCache.getInputStream(FileInputStreamCache.java:117)
at org.apache.camel.converter.stream.FileInputStreamCache.read(FileInputStreamCache.java:112)
at java.io.InputStream.read(InputStream.java:170)
at java.io.InputStream.read(InputStream.java:101)
at org.restlet.engine.io.BioUtils.copy(BioUtils.java:81)
at org.restlet.representation.InputRepresentation.write(InputRepresentation.java:148)
at org.restlet.engine.adapter.ServerCall.writeResponseBody(ServerCall.java:510)
at org.restlet.engine.adapter.ServerCall.sendResponse(ServerCall.java:454)
at org.restlet.ext.servlet.internal.ServletCall.sendResponse(ServletCall.java:426)
at org.restlet.engine.adapter.ServerAdapter.commit(ServerAdapter.java:196)
at org.restlet.engine.adapter.HttpServerHelper.handle(HttpServerHelper.java:153)
at org.restlet.ext.servlet.ServerServlet.service(ServerServlet.java:1089)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:684)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1496)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102)

相同的解决方法对我有用:

    getContext().getProperties().put(CachedOutputStream.THRESHOLD, "" + THREE_MEGABYTE_TRESHOLD_BEFORE_FILE_CACHE);

我没有在这条路线中使用多播,只是简单的

重定时请求 - &gt;服务 - &gt;杰克逊马歇尔=&gt;错误

我使用Camel 2.14.0&amp; Restlet 2.2.2 with JDK 7 and Spring-boot 1.0.2 / Jetty

Camel reverse proxy - no response stream caching可能与我的问题有关。