Spring Boot 和 Spring Data with Cassandra:在数据库连接失败时继续
Posted
技术标签:
【中文标题】Spring Boot 和 Spring Data with Cassandra:在数据库连接失败时继续【英文标题】:Spring Boot and Spring Data with Cassandra: Continue on failed database connection 【发布时间】:2020-11-19 23:04:02 【问题描述】:我在 Cassandra 中使用 Spring Boot 和 Spring Data。在应用程序启动时,spring 建立与数据库的连接以设置模式并初始化 spring 数据存储库。如果数据库不可用,应用程序将无法启动。
我希望应用程序只记录错误并启动。当然,我不能再使用存储库了,但是独立于数据库的其他服务(休息控制器等)应该可以工作。如果在执行器运行状况检查中看到 cassandra 已关闭,那也很好。
对于 JDBC,有一个 spring.datasource.continue-on-error
属性。我找不到适合 Cassandra 的类似内容。
我还尝试创建自定义 cassandra 配置并尝试在创建 CqlSession 时捕获异常,但我无法实现所需的行为。
编辑:根据@adutra 的建议,我尝试设置advanced.reconnect-on-init,应用程序尝试建立连接,但应用程序未完全初始化(例如,无法访问 REST 控制器)
@Configuration
public class CustomCassandraConfiguration extends CassandraAutoConfiguration
@Bean
public DriverConfigLoaderBuilderCustomizer driverConfigLoaderBuilderCustomizer()
return builder -> builder.withBoolean(DefaultDriverOption.RECONNECT_ON_INIT, true);
EDIT2:我现在有工作示例(应用程序启动,cassandra 的自定义健康检查),但如果感觉很丑:
CustomCassandraAutoConfiguration
@Configuration
public class CustomCassandraAutoConfiguration extends CassandraAutoConfiguration
private final Logger logger = LoggerFactory.getLogger(getClass());
@Override
@Bean
public CqlSession cassandraSession(CqlSessionBuilder cqlSessionBuilder)
try
return super.cassandraSession(cqlSessionBuilder);
catch (AllNodesFailedException e)
logger.error("Failed to establish the database connection", e);
return new DatabaseNotConnectedFakeCqlSession();
@Bean
public CassandraReactiveHealthIndicator cassandraHealthIndicator(ReactiveCassandraOperations r, CqlSession session)
if (session instanceof DatabaseNotConnectedFakeCqlSession)
return new CassandraReactiveHealthIndicator(r)
@Override
protected Mono<Health> doHealthCheck(Health.Builder builder)
return Mono.just(builder.down().withDetail("connection", "was not available on startup").build());
;
return new CassandraReactiveHealthIndicator(r);
CustomCassandraDataAutoConfiguration
@Configuration
public class CustomCassandraDataAutoConfiguration extends CassandraDataAutoConfiguration
public CustomCassandraDataAutoConfiguration(CqlSession session)
super(session);
@Bean
public SessionFactoryFactoryBean cassandraSessionFactory(CqlSession session, Environment environment, CassandraConverter converter)
SessionFactoryFactoryBean sessionFactoryFactoryBean = super.cassandraSessionFactory(environment, converter);
// Disable schema action if database is not available
if (session instanceof DatabaseNotConnectedFakeCqlSession)
sessionFactoryFactoryBean.setSchemaAction(SchemaAction.NONE);
return sessionFactoryFactoryBean;
DatabaseNotConnectedFakeCqlSession(假会话实现)
public class DatabaseNotConnectedFakeCqlSession implements CqlSession
@Override
public String getName()
return null;
@Override
public Metadata getMetadata()
return null;
@Override
public boolean isSchemaMetadataEnabled()
return false;
@Override
public CompletionStage<Metadata> setSchemaMetadataEnabled( Boolean newValue)
return null;
@Override
public CompletionStage<Metadata> refreshSchemaAsync()
return null;
@Override
public CompletionStage<Boolean> checkSchemaAgreementAsync()
return null;
@Override
public DriverContext getContext()
return new DefaultDriverContext(new DefaultDriverConfigLoader(), ProgrammaticArguments.builder().build());
@Override
public Optional<CqlIdentifier> getKeyspace()
return Optional.empty();
@Override
public Optional<Metrics> getMetrics()
return Optional.empty();
@Override
public <RequestT extends Request, ResultT> ResultT execute( RequestT request, GenericType<ResultT> resultType)
return null;
@Override
public CompletionStage<Void> closeFuture()
return null;
@Override
public CompletionStage<Void> closeAsync()
return null;
@Override
public CompletionStage<Void> forceCloseAsync()
return null;
@Override
public Metadata refreshSchema()
return null;
有什么建议吗?
【问题讨论】:
“我还尝试创建自定义 cassandra 配置并尝试在创建 CqlSession 时捕获异常,但我无法实现所需的行为。”为什么?如果您声明另一个 CqlSession 类型的 bean,则不会使用在 CassandraAutoConfiguration 中声明的默认 bean;那么您可以随意创建会话,所以我很惊讶您无法捕获 SessionBuilder.build() 引发的异常。 @adutra:我创建了自己的 CqlSession 实现,但是有很多依赖项。许多 getter 必须返回有效值(否则为 NPE)。我认为,这将有可能实现所有必要的方法,但感觉就像一个 hack,我试图找到更优雅的解决方案。 你不需要实现CqlSession。我建议捕捉异常: public CqlSession cassandraSession(CqlSessionBuilder cqlSessionBuilder) try return cqlSessionBuilder.build(); 捕捉(异常 e) 返回空值; 如果将返回 null 而不是 CqlSession,这将破坏应用程序:无法实例化每个“自动装配”获取存储库的所有组件。 Spring自动配置也被破坏“通过方法'reactiveCassandraSession'表达的不满足的依赖关系”。 确实如此。如果你的 bean 可以为空,你不能直接注入它。您需要将其包装到可选的或更好的 ObjectProvider 中:docs.spring.io/spring-framework/docs/current/javadoc-api/org/… 【参考方案1】:你可以将选项datastax-java-driver.advanced.reconnect-on-init
设置为true来达到你想要的效果。它的用法在驱动程序文档中的configuration reference page 中进行了说明:
如果在第一次初始化尝试时所有接触点都无法访问,是否安排重新连接尝试。 如果这是真的,驱动程序将根据重新连接策略重试。
SessionBuilder.build()
调用 - 或SessionBuilder.buildAsync()
返回的未来 - 在到达联系点之前不会完成。如果这是错误的并且没有可用的联系点,则驱动程序将失败并返回AllNodesFailedException
。
但是要小心:如果将此选项设置为 true,如上所述,任何尝试访问 CqlSession
bean 的组件,即使会话 bean 是惰性的,都会阻塞,直到驱动程序可以连接,如果接触点错误可能会永远阻塞。
如果这对您来说不可接受,我建议您将 CqlSession
bean 包装在另一个 bean 中,该 bean 将检查 SessionBuilder.buildAsync()
返回的未来是否完成,并阻止、抛出或返回 null,具体取决于根据来电者的期望。
【讨论】:
感谢您的提示,我会尝试的。【参考方案2】:[编辑]昨晚我在内部联系了 DataStax 驱动程序团队,adutra 已做出回应,因此我撤回了我的回应。
【讨论】:
不,不是。可能有人需要应用程序在没有数据库、某些单体或动态数据库的情况下继续运行某些功能。此外,不依赖于一些像数据源这样的 bean 初始化也是可行的 这取决于用例:有时最好有一个“快速失败”系统,如果外部依赖项(数据库、消息提供程序等)不可用,应用程序启动应该立即失败.但有时你可能有一个应用程序,例如3种不同的外部依赖。并且如果一个不可用 -> 可以报告错误并开始。以上是关于Spring Boot 和 Spring Data with Cassandra:在数据库连接失败时继续的主要内容,如果未能解决你的问题,请参考以下文章
spring boot整合spring Data JPA和freemarker
使用 spring-boot 和 spring-data 全局启用休眠过滤器
Spring Boot 和 Spring Data MongoDB:在 ResponseBody 中隐藏字段
spring boot系列spring boot 配置spring data jpa (查询方法)
无法将 Spring Data MongoDB + Spring Data JPA 与 Spring Boot 一起使用