Spring 引导:如果 DataSource 关闭,则 ResponseEntity 中 return 503 HttpStatus 的最佳方法
Spring Boot: Best way to return 503 HttpStatus in ResponseEntity if the DataSource is DOWN
我正在使用 Spring Boot 2.2.4.RELEASE
并且我有一个 REST api,公开了几个端点。如果数据库出现故障,我想 return 一个 503 给来电者。
我可以使用 Spring Boot
免费提供的 DataSourceHealthIndicator
如果 DataSource
是这样配置的:
@Autowired
private DataSourceHealthIndicator d;
@PostMapping(value = "/{id}")
public ResponseEntity<jsonResponse> someMethod()(
@PathVariable String id,
@Valid @RequestBody SomeDto someDto) {
//some code
if("DOWN".equals(d.getHealth(false).getStatus().getCode())) {
return new ResponseEntity<>(jsonResponse, HttpStatus.SERVICE_UNAVAILABLE);
}
有没有更好的方法来做到这一点,因为我相信每次调用端点时它都会命中数据库,因此是一种昂贵的方法。
如果您预计会有大量请求,您可以考虑使用一个单独的线程(数据库健康状态),它每隔 X 秒对数据库执行一次 ping 操作。通过这种方式,如果您知道数据库不可用,则传入的 HTTP 请求无需访问数据库。
如果您的数据量不大,那么最好尝试连接并处理数据库不可用的情况,这样您就需要额外的线程,一旦数据库再次可用,请求就会恢复工作(根据您配置的时间间隔,使用线程可能会有轻微的延迟)。
DataSource 通常会为您验证连接并在无法获得连接时抛出异常,因此您可以为抛出的特定异常类型创建 custom error handler 并将其用于 return 带有 503 的自定义响应实体。
唯一需要注意的是 SQLException
例外,这可能是与连接无关的任意数量的问题。您的错误处理程序需要足够聪明才能理解 SQLException
中的哪些错误代码真正意味着不可用。
如果您想依赖 Spring 引导解决方案,那么我建议 Spring 缓存 https://spring.io/guides/gs/caching/
添加 Maven 依赖项 <artifactId>spring-boot-starter-cache</artifactId>
,使用 @EnableCaching
在 Spring 启动应用程序 class 中启用缓存,然后定义应缓存结果的方法。
此方法只会在第一次调用时命中数据库,所有其他调用都依赖于缓存值。
@Cacheable("records")
public Record getByName(String name) {
return getRecordRepository().findByName(name);
}
如果使用 Spring 本机(内存中)缓存,您需要在某个时间点逐出对象,以确保您不会持有陈旧数据(除非它是一个永不更改的只读对象,而不是可能是一个非常常见的用例)。
在你的场景中(如果我理解正确的话)你可以有一个线程,然后每 x 秒检查一次数据库,如果健康,你可以使用专用方法驱逐缓存:
@CacheEvict(allEntries = true, cacheNames = { "records"})
public void evictAllRecords() {
// evict all records every 10 minutes
}
我正在使用 Spring Boot 2.2.4.RELEASE
并且我有一个 REST api,公开了几个端点。如果数据库出现故障,我想 return 一个 503 给来电者。
我可以使用 Spring Boot
免费提供的 DataSourceHealthIndicator
如果 DataSource
是这样配置的:
@Autowired
private DataSourceHealthIndicator d;
@PostMapping(value = "/{id}")
public ResponseEntity<jsonResponse> someMethod()(
@PathVariable String id,
@Valid @RequestBody SomeDto someDto) {
//some code
if("DOWN".equals(d.getHealth(false).getStatus().getCode())) {
return new ResponseEntity<>(jsonResponse, HttpStatus.SERVICE_UNAVAILABLE);
}
有没有更好的方法来做到这一点,因为我相信每次调用端点时它都会命中数据库,因此是一种昂贵的方法。
如果您预计会有大量请求,您可以考虑使用一个单独的线程(数据库健康状态),它每隔 X 秒对数据库执行一次 ping 操作。通过这种方式,如果您知道数据库不可用,则传入的 HTTP 请求无需访问数据库。
如果您的数据量不大,那么最好尝试连接并处理数据库不可用的情况,这样您就需要额外的线程,一旦数据库再次可用,请求就会恢复工作(根据您配置的时间间隔,使用线程可能会有轻微的延迟)。
DataSource 通常会为您验证连接并在无法获得连接时抛出异常,因此您可以为抛出的特定异常类型创建 custom error handler 并将其用于 return 带有 503 的自定义响应实体。
唯一需要注意的是 SQLException
例外,这可能是与连接无关的任意数量的问题。您的错误处理程序需要足够聪明才能理解 SQLException
中的哪些错误代码真正意味着不可用。
如果您想依赖 Spring 引导解决方案,那么我建议 Spring 缓存 https://spring.io/guides/gs/caching/
添加 Maven 依赖项 <artifactId>spring-boot-starter-cache</artifactId>
,使用 @EnableCaching
在 Spring 启动应用程序 class 中启用缓存,然后定义应缓存结果的方法。
此方法只会在第一次调用时命中数据库,所有其他调用都依赖于缓存值。
@Cacheable("records")
public Record getByName(String name) {
return getRecordRepository().findByName(name);
}
如果使用 Spring 本机(内存中)缓存,您需要在某个时间点逐出对象,以确保您不会持有陈旧数据(除非它是一个永不更改的只读对象,而不是可能是一个非常常见的用例)。
在你的场景中(如果我理解正确的话)你可以有一个线程,然后每 x 秒检查一次数据库,如果健康,你可以使用专用方法驱逐缓存:
@CacheEvict(allEntries = true, cacheNames = { "records"})
public void evictAllRecords() {
// evict all records every 10 minutes
}