Camel: переименование файла с: xxx на: xxx не удалось из-за невозможности удалить из файла: xxx после успешного копирования

Фон системы: Windows/ServiceMix/Camel/Smooks

У меня есть маршрут Camel

<camel:camelContext id="customsContext" xmlns="http://camel.apache.org/schema/spring">
    <camel:route>
        <camel:from uri="file://C:\Camel\?delay=2000"/>
        <camel:convertBodyTo type="javax.xml.transform.stream.StreamSource"/>
        <camel:to uri="smooks:smooks-config.xml"/>
    </camel:route>
</camel:camelContext>

который должен забрать файл и передать его пользовательскому анализатору EDI Smooks. Это работает до того момента, когда Camel копирует файл в каталог moveNamePrefix, а затем пытается удалить оригинал, когда выдает исключение. Поскольку файл никогда не очищается, это повторяется бесконечно.

2014-06-04 23:43:47,331 | WARN  | ://C:%5CCamel%5C | GenericFileOnCompletion          | ?                                   ? | 110 - org.apache.camel.camel-core - 2.12.3 | Error during commit. Exchange[Message: [Body is null]]. Caused by: [org.apache.camel.component.file.GenericFileOperationFailedException - Error renaming file from C:\Camel\edi-input.txt to C:\Camel\.camel\edi-input.txt]
org.apache.camel.component.file.GenericFileOperationFailedException: Error renaming file from C:\Camel\edi-input.txt to C:\Camel\.camel\edi-input.txt
        at org.apache.camel.component.file.FileOperations.renameFile(FileOperations.java:72)[110:org.apache.camel.camel-core:2.12.3]
        at org.apache.camel.component.file.strategy.GenericFileProcessStrategySupport.renameFile(GenericFileProcessStrategySupport.java:113)[110:org.apache.camel.camel-core:2.12.3]
        at org.apache.camel.component.file.strategy.GenericFileRenameProcessStrategy.commit(GenericFileRenameProcessStrategy.java:88)[110:org.apache.camel.camel-core:2.12.3]
        at org.apache.camel.component.file.GenericFileOnCompletion.processStrategyCommit(GenericFileOnCompletion.java:124)[110:org.apache.camel.camel-core:2.12.3]
        at org.apache.camel.component.file.GenericFileOnCompletion.onCompletion(GenericFileOnCompletion.java:80)[110:org.apache.camel.camel-core:2.12.3]
        at org.apache.camel.component.file.GenericFileOnCompletion.onComplete(GenericFileOnCompletion.java:54)[110:org.apache.camel.camel-core:2.12.3]
        at org.apache.camel.util.UnitOfWorkHelper.doneSynchronizations(UnitOfWorkHelper.java:100)[110:org.apache.camel.camel-core:2.12.3]
        at org.apache.camel.impl.DefaultUnitOfWork.done(DefaultUnitOfWork.java:228)[110:org.apache.camel.camel-core:2.12.3]
        at org.apache.camel.util.UnitOfWorkHelper.doneUow(UnitOfWorkHelper.java:61)[110:org.apache.camel.camel-core:2.12.3]
        at org.apache.camel.processor.CamelInternalProcessor$UnitOfWorkProcessorAdvice.after(CamelInternalProcessor.java:613)[110:org.apache.camel.camel-core:2.12.3]
        at org.apache.camel.processor.CamelInternalProcessor$UnitOfWorkProcessorAdvice.after(CamelInternalProcessor.java:581)[110:org.apache.camel.camel-core:2.12.3]
        at org.apache.camel.processor.CamelInternalProcessor$InternalCallback.done(CamelInternalProcessor.java:240)[110:org.apache.camel.camel-core:2.12.3]
        at org.apache.camel.processor.Pipeline.process(Pipeline.java:106)[110:org.apache.camel.camel-core:2.12.3]
        at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:191)[110:org.apache.camel.camel-core:2.12.3]
        at org.apache.camel.component.file.GenericFileConsumer.processExchange(GenericFileConsumer.java:401)[110:org.apache.camel.camel-core:2.12.3]
        at org.apache.camel.component.file.GenericFileConsumer.processBatch(GenericFileConsumer.java:201)[110:org.apache.camel.camel-core:2.12.3]
        at org.apache.camel.component.file.GenericFileConsumer.poll(GenericFileConsumer.java:165)[110:org.apache.camel.camel-core:2.12.3]
        at org.apache.camel.impl.ScheduledPollConsumer.doRun(ScheduledPollConsumer.java:187)[110:org.apache.camel.camel-core:2.12.3]
        at org.apache.camel.impl.ScheduledPollConsumer.run(ScheduledPollConsumer.java:114)[110:org.apache.camel.camel-core:2.12.3]
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)[:1.7.0_51]
        at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304)[:1.7.0_51]
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)[:1.7.0_51]
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)[:1.7.0_51]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)[:1.7.0_51]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)[:1.7.0_51]
        at java.lang.Thread.run(Thread.java:744)[:1.7.0_51]
Caused by: java.io.IOException: Renaming file from: C:\Camel\edi-input.txt to: C:\Camel\.camel\edi-input.txt failed due cannot delete from file: C:\Camel\edi-input.txt after copy succeeded
        at org.apache.camel.util.FileUtil.renameFile(FileUtil.java:421)[110:org.apache.camel.camel-core:2.12.3]
        at org.apache.camel.component.file.FileOperations.renameFile(FileOperations.java:70)[110:org.apache.camel.camel-core:2.12.3]
        ... 25 more

Так что да, файл все еще открыт, что блокирует удаление. Но тут становится немного интересно. Если вы перечисляете открытые файлы, вы видите, что они на самом деле открыты несколько раз, и вы получаете еще один каждые 2 секунды, что является задержкой опроса.

#1 C:\Camel\edi-input.txt by thread:Camel (customsContext) thread #0 - file://C:%5CCamel%5C on Thu Jun 05 10:08:13 EDT 2014
    at java.io.FileInputStream.<init>(FileInputStream.java:147)
    at java.io.FileInputStream.<init>(FileInputStream.java:101)
    at sun.net.www.protocol.file.FileURLConnection.connect(FileURLConnection.java:90)
    at sun.net.www.protocol.file.FileURLConnection.getInputStream(FileURLConnection.java:188)
    at java.net.URL.openStream(URL.java:1037)
    at org.milyn.delivery.AbstractParser.systemIdToStream(AbstractParser.java:192)
    at org.milyn.delivery.AbstractParser.getInputStream(AbstractParser.java:253)
    at org.milyn.delivery.AbstractParser.createInputSource(AbstractParser.java:227)
    at org.milyn.delivery.sax.SAXParser.parse(SAXParser.java:76)
    at org.milyn.delivery.sax.SmooksSAXFilter.doFilter(SmooksSAXFilter.java:86)
    at org.milyn.delivery.sax.SmooksSAXFilter.doFilter(SmooksSAXFilter.java:64)
    at org.milyn.Smooks._filter(Smooks.java:526)
    at org.milyn.Smooks.filterSource(Smooks.java:477)
    at org.milyn.smooks.camel.processor.SmooksProcessor.process(SmooksProcessor.java:112)
    at org.apache.camel.impl.ProcessorEndpoint.onExchange(ProcessorEndpoint.java:103)
    at org.apache.camel.impl.ProcessorEndpoint$1.process(ProcessorEndpoint.java:71)
    at org.apache.camel.util.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:61)
    at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:110)
    at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:72)
    at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:398)
    at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:191)
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:118)
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:80)
    at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:191)
    at org.apache.camel.component.file.GenericFileConsumer.processExchange(GenericFileConsumer.java:401)
    at org.apache.camel.component.file.GenericFileConsumer.processBatch(GenericFileConsumer.java:201)
    at org.apache.camel.component.file.GenericFileConsumer.poll(GenericFileConsumer.java:165)
    at org.apache.camel.impl.ScheduledPollConsumer.doRun(ScheduledPollConsumer.java:187)
    at org.apache.camel.impl.ScheduledPollConsumer.run(ScheduledPollConsumer.java:114)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
    at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:744)

Тем не менее, их меньше 100, хотя на данный момент завершено ~ 7000 циклов, так что да, все файлы закрываются во время GC (сборки мусора), а затем снова начинают накапливаться. Да, это говорит о том, что поток не закрывается до тех пор, пока ссылающийся на него объект не будет очищен сборщиком мусора. Однако я отследил код, и поток закрыт в org.milyn.delivery.sax.SmooksSAXFilter.doFilter

try {
    Writer writer = parser.parse(source, result, executionContext);
    writer.flush();
} catch (TerminateException e) {
    if(logger.isDebugEnabled()) {
        if(e.isTerminateBefore()) {
            logger.debug("Terminated filtering on visitBefore of element '" + SAXUtil.getXPath(e.getElement()) + "'.");
        } else {
            logger.debug("Terminated filtering on visitAfter of element '" + SAXUtil.getXPath(e.getElement()) + "'.");                  
        }
    }
} catch (Exception e) {
    throw new SmooksException("Failed to filter source.", e);
} finally {
    if(closeSource) {
        close(source);
    }
    if(closeResult) {
        close(result);
    }
}

Так что тут я немного в растерянности. Означает ли это, что Camel пытается зафиксировать транзакцию в другом потоке до того, как Smooks завершит работу?


person tlum    schedule 05.06.2014    source источник


Ответы (3)


Это Смукс!

При некоторых обстоятельствах Smooks сам открывает поток в классе org.milyn.delivery.AbstractParser, но никогда не закрывает его. Таким образом, открытый поток зависает до тех пор, пока не будет собран несуществующий объект. В случае Windows блокировка открытых файлов осуществляется операционной системой, и Camel не может переименовать или удалить файл. Этого может не быть в случае с другими операционными системами или версиями Java, если там не соблюдается блокировка.

Я открыл MILYN-662 и работаю над исправлением.

person tlum    schedule 05.06.2014

Похоже, что ваш camelcontext не был отключен должным образом, и поэтому блокировка файла удерживается. Вы, вероятно, хотите немного подождать с замком.

person Bytekoder    schedule 06.06.2014
comment
Блокировка файла Camel снимается. Это Smooks никогда не закрывает поток. - person tlum; 07.06.2014

Закройте входной поток в блоке finally (файл не закрывается должным образом после чтения). Это вызывает проблему невозможности переименовать существующий файл.

if (inputStream != null) {inputStream.close();}
person vedavyasa k    schedule 17.10.2020