You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
    }
}

原因分析

  1. 全局配置未作用于命名缓存实例
    你配置的camel.component.caffeine-cache.*是全局默认配置,仅对未指定名称的默认缓存生效。而路由中使用的是命名缓存IndividualCache,该实例不会自动继承全局配置,导致过期规则未被应用。

  2. 时间单位可能存在误解
    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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 00:23:11