如何在Apache Camel中锁定写入中的文件以避免被其他消费者读取?
解决Apache Camel中写入文件时被提前读取的问题
你遇到的核心问题是大文件写入未完成时就被下游路由消费,这在处理大体积文件时确实很常见。你尝试过readLocks但没成功,大概率是配置的位置或类型不对,或者没配合写入侧的策略。下面给你几个实用的解决方案,结合你的代码来调整:
方案1:临时文件后缀策略(最推荐,简单可靠)
这个思路是让第一个路由先写入带临时后缀的文件,完成后自动重命名为目标文件;下游路由只监听最终后缀的文件,从根源避免读取未完成的文件。
修改你的第一个路由的写入端点:
from("file://A") .split().tokenize("\n", 999).streaming() .log("Spliting::::::::::") .unmarshal(csv) .bean("transferDate", "enrich") .marshal(csv) // 写入时用.tmp临时后缀,完成后自动移除后缀 .to("file://B?fileExist=Append&tempFileName=*.tmp");
然后修改第二个消费路由,只读取非临时后缀的文件:
// 只匹配不以.tmp结尾的文件,避免读取写入中的临时文件 from("file://B?delete=true&include=^.*(?<!\\.tmp)$") .to("file://A");
方案2:正确配置Read Lock + Write Lock
如果你坚持用锁机制,需要同时在写入端和读取端配置对应的锁策略:
写入端配置Write Lock
确保第一个路由写入文件时持有写锁,防止其他进程/路由干扰:
.to("file://B?fileExist=Append&writeLock=fileLock&writeLockTimeout=30000");
读取端配置Read Lock(优化版)
你的第二个路由需要配置更可靠的读锁类型,比如changed(检测文件大小是否稳定),并设置合理的检查间隔:
// changed锁会持续检查文件大小,直到连续两次检查都不变才认为文件稳定 from("file://B?delete=true&readLock=changed&readLockCheckInterval=5000&delay=1000") .to("file://A");
readLock=changed:通过检测文件大小变化判断是否写入完成readLockCheckInterval=5000:每5秒检查一次文件状态delay=1000:路由启动后延迟1秒再扫描文件,避免刚创建的文件被误读
方案3:Done File标记策略
让第一个路由写完文件后生成对应的.done标记文件,下游路由只在检测到标记文件时才消费目标文件:
修改第一个路由的写入端点:
.to("file://B?fileExist=Append&doneFileName=${file:name}.done");
然后修改第二个消费路由:
// 只有对应的.done文件存在时才读取目标文件,读取后自动删除.done文件 from("file://B?delete=true&doneFileName=${file:name}.done&deleteDoneFile=true") .to("file://A");
为什么你之前的readLocks没生效?
大概率是只在读取路由加了锁,但写入过程中文件一直在被追加内容,默认的readLock配置可能太敏感,或者检查间隔太短,导致还没等文件稳定就开始读取了。结合上面的方案,要么从写入侧隔离未完成的文件,要么让读取侧更耐心地等待文件稳定。
内容的提问来源于stack exchange,提问作者bvyas
相关产品推荐
相关产品推荐

