Apache Camel Quarkus中Caffeine缓存过期时间不生效问题排查
问题:Quarkus中Apache Camel Caffeine缓存过期配置未生效
配置与测试情况
配置文件中设置的缓存属性:
#cache camel.component.caffeine-cache.expire-after-write-time=60 camel.component.caffeine-cache.expire-after-access-time=60
测试结果:
- 测试1(下午2:00):请求命中缓存,
CamelCaffeineActionHasResult = true; - 测试2(下午2:04,距缓存写入已过去240秒):请求仍命中缓存,
CamelCaffeineActionHasResult = true。
按预期60秒后缓存应失效并重新调用服务,但实际未生效。
路由配置代码
@ApplicationScoped public class ResRoute extends RouteBuilder { @ConfigProperty(name = "client.findIndividualCustomerByDocId") String findIndividualCustomerByDocId; @ConfigProperty(name = "client.findOrganizacionCustomerByDocId") String findOrganizacionCustomerByDocId; @ConfigProperty(name = "path.openapi") String pathOpenapi; @ConfigProperty(name = "descripcion.servicio") String descripcionServicio; private ConfigureSsl configureSsl; private static final String SALIDA_BSS_EXCEPTION = "Salida del microservicio BSS FindCustomerByDocId ${exchangeProperty[bodyRs]}"; private static final String MSG_EXCEPTION = "Descripcion de la Exception: ${exception.message}"; public ResRoute() { configureSsl = new ConfigureSsl(); } @Override public void configure() throws Exception { BeanDate beanDate= new BeanDate(); getContext().getRegistry().bind("BeanDate",beanDate); restConfiguration() .bindingMode(RestBindingMode.json) .dataFormatProperty("json.in.disableFeatures", "FAIL_ON_UNKNOWN_PROPERTIES") .apiContextPath(pathOpenapi) .apiProperty("api.title", "FindCustomerByDocId") .apiProperty("api.description", descripcionServicio) .apiProperty("api.version", "1.0.0") .apiProperty("cors", "true"); rest("customerInformation/v1.4.0/users/") .get("/{user_id}/customers").to("direct:/{user_id}/customers") .outType(Customer.class) .param().name("FindCustomerByDocIdResponse").type(body).description("parametro de salida").required(true) .endParam() .to("direct:pipeline"); from("direct:pipeline") .doTry() .process(new FindCustomerByDocIdProcessorReq()) .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+"User ID: ${exchangeProperty[userId]}") .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+"Correlator ID: ${exchangeProperty[correlatorId]}") .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+"Tipo de Documento (Num): ${exchangeProperty[documentTypeNum]}") .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+"Tipo de Cliente: ${exchangeProperty[customerType]}") .choice() .when(simple("${exchangeProperty[customerType]} == 'NATURAL'")) .process(new FindIndividualCustomerByDocIdProcessorReq()) .setHeader(CaffeineConstants.ACTION, constant(CaffeineConstants.ACTION_GET)) .setHeader(CaffeineConstants.KEY).exchangeProperty("documentNumber") .toF("caffeine-cache://%s", "IndividualCache") .log("Hay Resultado en Cache de la consulta asociado al siguiente documento: ${exchangeProperty[userId]} ${header.CamelCaffeineActionHasResult}}") .log("CamelCaffeineActionSucceeded: ${header.CamelCaffeineActionSucceeded}") .choice().when(header(CaffeineConstants.ACTION_HAS_RESULT).isEqualTo(Boolean.FALSE)) .to(configureSsl.setupSSLContext(getCamelContext(), findIndividualCustomerByDocId)) .setHeader(CaffeineConstants.ACTION, constant(CaffeineConstants.ACTION_PUT)) .setHeader(CaffeineConstants.KEY).exchangeProperty("documentNumber") .toF("caffeine-cache://%s", "IndividualCache") .process(new FindIndividualCustomerByDocIdProcessorRes()) .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+"Salida del microservicio FindIndividualCustomerByDocId ${exchangeProperty[findIndividualCustomerByDocIdResponse]}") .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+"Salida del microservicio BSS FindCustomerByDocId ${exchangeProperty[findCustomerByDocIdResponse]}") .otherwise() .log("Cache is working") .process(new FindIndividualCustomerByDocIdProcessorRes()) .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+"Salida del microservicio FindIndividualCustomerByDocId ${exchangeProperty[findIndividualCustomerByDocIdResponse]}") .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+"Salida del microservicio BSS FindCustomerByDocId ${exchangeProperty[findCustomerByDocIdResponse]}") .when(simple("${exchangeProperty[customerType]} == 'JURIDICO'")) .process(new FindOrganizationCustomerByDocIdProcessorReq()) .to(configureSsl.setupSSLContext(getCamelContext(), findOrganizacionCustomerByDocId)) .process(new FindOrganizationCustomerByDocIdProcessorRes()) /*.log("\n["+getCurrentDate()+"]+"Entrada del microservicio FindOrganizationCustomerByDocId ${exchangeProperty[findOrganizationCustomerByDocIdRequest]}") */ .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+"Salida del microservicio FindOrganizationCustomerByDocId ${exchangeProperty[findOrganizationCustomerByDocIdResponse]}") .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+"Salida del microservicio BSS FindCustomerByDocId ${exchangeProperty[findCustomerByDocIdResponse]}") .endChoice() .endDoTry() .doCatch(RequiredValueException.class) .process(new FindCustomerByDocIdProcessorInvalidFormatException()) .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+MSG_EXCEPTION) .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+SALIDA_BSS_EXCEPTION) .doCatch(HttpHostConnectException.class) .process(new FindCustomerByDocIdProcessorHttpHostConectionException()) .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+MSG_EXCEPTION) .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+SALIDA_BSS_EXCEPTION) .doCatch(NotFoundDataException.class) .process(new FindCustomerByDocIdProcessorInformationSubscriber()) .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+MSG_EXCEPTION) .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+SALIDA_BSS_EXCEPTION) .doCatch(UnknownHostException.class) .process(new FindCustomerByDocIdProcessorHttpHostConectionException()) .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+MSG_EXCEPTION) .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+SALIDA_BSS_EXCEPTION) .doCatch(NoHttpResponseException.class) .process(new FindCustomerByDocIdProcessorHttpHostConectionException()) .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+MSG_EXCEPTION) .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+SALIDA_BSS_EXCEPTION) .doCatch(Exception.class) .process(new FindCustomerByDocIdProcessorException()) .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+MSG_EXCEPTION) .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+SALIDA_BSS_EXCEPTION); } }
原因分析
全局配置未作用于命名缓存实例
你配置的camel.component.caffeine-cache.*是全局默认配置,仅对未指定名称的默认缓存生效。而路由中使用的是命名缓存IndividualCache,该实例不会自动继承全局配置,导致过期规则未被应用。时间单位可能存在误解
Camel Caffeine组件的expire-after-write-time和expire-after-access-time默认单位为毫秒,如果配置值60被解析为60毫秒,但测试中240秒后仍命中缓存,说明核心问题是配置未关联到目标缓存,而非单位问题。
修复方案
1. 为命名缓存单独配置过期时间
修改配置文件,为IndividualCache添加专属配置:
# 全局默认配置(可选,用于未命名缓存) camel.component.caffeine-cache.expire-after-write-time=60000 camel.component.caffeine-cache.expire-after-access-time=60000 # 为IndividualCache实例单独配置(关键) camel.component.caffeine-cache.configuration.IndividualCache.expire-after-write-time=60000 camel.component.caffeine-cache.configuration.IndividualCache.expire-after-access-time=60000
注:
60000代表60秒(毫秒单位),若你的组件版本单位为秒,直接写60即可。
2. 直接在路由URI中指定参数
如果不想通过配置文件,可在Caffeine URI中直接添加参数(优先级最高):
.toF("caffeine-cache://%s?expireAfterWriteTime=60000&expireAfterAccessTime=60000", "IndividualCache")
3. 验证缓存配置
可在路由中添加日志打印缓存实际配置,确认过期策略是否生效:
// 在访问缓存后添加该处理器 .process(exchange -> { CaffeineCacheComponent component = exchange.getContext().getComponent("caffeine-cache", CaffeineCacheComponent.class); Cache<Object, Object> cache = component.getCache("IndividualCache"); // 获取写过期时间(纳秒),转换为秒方便查看 long expireTimeNs = cache.policy().expireAfterWrite().map(Expiry::expireAfterWrite).orElse(-1L); exchange.getIn().setHeader("CacheExpireTimeSec", expireTimeNs / 1_000_000_000); }) .log("IndividualCache写过期时间(秒):${header.CacheExpireTimeSec}")
内容的提问来源于stack exchange,提问作者Cesar Justo
相关产品推荐
相关产品推荐

