关闭 Spring 当数据库丢失

huangapple go评论78阅读模式
英文:

Shutown Spring when DB is lost

问题

使用案例

我们的 spring-boot-backend(版本 2.3.1)使用 postgres 数据库,并使用 HikariCP 作为连接池。
应用程序正在运行,管理员意外关闭了数据库。

期望的行为

Spring 注意到与数据库的连接丢失。应用程序将会优雅地关闭。

实际行为

Spring 仍然在运行。所有需要数据库的方法最终都会出现异常。
为了恢复到完全良好的状态,我们需要手动重新启动 Spring。

备注
我们有许多异步的工作程序,当数据库恢复正常时,它们无法正确恢复。
而且 Docker/Kubernetes 会注意到应用程序的关闭,并可以自动重新启动它。

问题

我如何实现期望的行为?
遗憾的是,我在网上找不到类似的解决方案。

英文:

Use case

Our spring-boot-backend (v 2.3.1) using a postgres-database with HikariCP as connection pool.
The application is online and a admin accidentally kills the database.

Expected behavior

Spring notice that the connection to DB was lost. The application will gracefully shutdown.

Actual behavior

Spring is still running. All methods, which needs the db, ending up in exceptions.
To recover a complete good state, we need manually to restart spring.

Notes
We have a lot of async workers and they cannot recover correctly, when the database is going back online.
And docker/kubernetes will notice when the application shutdown and can automatically restart it.

Question

How can I reach the expected behavior?
Sadly I found nothing similar in the web.

答案1

得分: 3

通过 @Zubair 的提示,我构建了一个新的小型解决方案。
我正在使用 Spring-Actuator 包,因为它们有一些适用于这种用例的现成类。

我所需要的就是一个 HealthIndicator Bean,就像这样:

@Bean
public HealthIndicator dataSourceHealthIndicator(final DataSource dataSource) {
  return new DataSourceHealthIndicator(dataSource, "SELECT 1;");
}

以及一个定时的监视器(因为 HikariCP 和 HealthIndicators 都没有任何事件)。

@Scheduled(fixedRate = 10000L)
public void checkDBHealth() {
  final Status status = this.dataSourceHealthIndicator.health().getStatus();
  if (!Status.UP.equals(status)) {
    log.error("DATABASE IS OFFLINE! SHUTTING DOWN!");
    System.exit(1);
  }
}

我希望这对其他人有用。

编辑

我不得不更改 HikariCP 的配置。否则,健康检查器会等待几乎无限的数据库连接。

@Bean
public DataSource dataSource() {
  final HikariConfig config = new HikariConfig();
  // 默认设置包括用户、密码、jdbc等...
  config.setInitializationFailTimeout(1000);
  config.setConnectionTimeout(1000);
  config.setValidationTimeout(1000);

  return new HikariDataSource(config);
}
英文:

With the hints from @Zubair I build a new small solution.
Iam using the Spring-Actuator-package, because they have some ready classes for this use-case.

All what I need was a HealthIndicator-Bean, like this

@Bean
public HealthIndicator dataSourceHealthIndicator(final DataSource dataSource) {
  return new DataSourceHealthIndicator(dataSource, "SELECT 1;");
}

and scheduled watcher (because HikariCP nor the HealthIndicators has any events).

@Scheduled(fixedRate = 10000L)
public void checkDBHealth() {
  final Status status = this.dataSourceHealthIndicator.health().getStatus();
  if (!Status.UP.equals(status)) {
    log.error("DATABASE IS OFFLINE! SHUTTING DOWN!");
    System.exit(1);
  }
}

I hope that will be useful for others.

Edit

I had to change the config of HikariCP. Otherwise the health-checker waiting almost endless for database-connection.

@Bean
public DataSource dataSource() {
  final HikariConfig config = new HikariConfig();
  // default settings with user, password, jdbc, ...
  config.setInitializationFailTimeout(1000);
  config.setConnectionTimeout(1000);
  config.setValidationTimeout(1000);

  return new HikariDataSource(config);
}

</details>



# 答案2
**得分**: 1

如果是 Spring 2.0 版本您可以从某个监控服务调用关闭执行器

<details>
<summary>英文:</summary>

If its spring 2.0, you may call the shut-down actuator from some monitoring service.

</details>



# 答案3
**得分**: 1

你可以在属性文件中禁用默认提供的执行器健康指示器并通过将自定义的 [DatasourceHealthIndicator][1] 注册为 bean 来替换它

```java
@Bean
public DataSourceHealthIndicator dataSourceHealthIndicator(){
   return new DataSourceHealthIndicator(dataSource, "SELECT 1");
}
@Component
@RequiredArgsConstructor
public class CustomHealth implements HealthIndicator {

   private final DataSourceHealthIndicator healthIndicator;

   @Override
   public Health health() {
      // ...
      return Health.status(healthIndicator.health().getStatus()).build();
   }
}

并且像这样设置你的属性。

application.yaml

management:
   health:
      db:
         enabled: false

application.properties

management.health.db.enabled: false
英文:

You can disable the actuator default provided health indicators in your property files and replace your custom DatasourceHealthIndicator by register it as bean.

@Bean
public DataSourceHealthIndicator dataSourceHealthIndicator(){
   return new DataSourceHealthIndicator(dataSource, &quot;SELECT 1&quot;);
}
@Component
@RequiredArgsConstructor
public class CustomHealth implements HealthIndicator {

   private final DataSourceHealthIndicator healthIndicator;

   @Override
   public Health health() {
      // ...
      return Health.status(healthIndicator.health().getStatus()).build();
   }
}

And set your properties like this.

application.yaml

management:
   health:
      db:
         enabled: false

application.properties

management.health.db.enabled: false

huangapple
  • 本文由 发表于 2020年9月22日 20:01:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/64009328.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定