リクエストに応じて何かを計算するREST APIがあり、同じリクエストが再度行われた場合、MongoDBに保存されたドキュメントで構成されるキャッシュから結果を返します。2 つのリクエストが同じかどうかを知るために、リクエスト内のいくつかの関連フィールドをハッシュしています。しかし、同じリクエストが立て続けに行われると、MongoDB でドキュメントが重複し、後で読み込もうとすると "IncorrectResultSizeDataAccessException" が発生します。
それを解決するために、次のコントローラーメソッドでハッシュ値を同期しようとしました(無関係な部分を切り取ろうとしました):
@PostMapping(
path = "/{myPath}",
consumes = {MediaType.APPLICATION_JSON_UTF8_VALUE},
produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
@Async("asyncExecutor")
public CompletableFuture<ResponseEntity<?>> retrieveAndCache( ... a,b,c,d various request parameters) {
//perform some validations on request...
//hash relevant equest parameters
int hash = Objects.hash(a, b, c, d);
synchronized (Integer.toString(hash).intern()) {
Optional<Result> resultOpt = cacheService.findByHash(hash);
if (resultOpt.isPresent()) {
return CompletableFuture.completedFuture(ResponseEntity.status(HttpStatus.OK).body(opt.get().getResult()));
} else {
Result result = ...//perform requests to external services and do some calculations...
cacheService.save(result);
return CompletableFuture.completedFuture(ResponseEntity.status(HttpStatus.OK).body(result));
}
}
}
//cacheService methods
@Transactional
public Optional<Result> findByHash(int hash) {
return repository.findByHash(hash); //this is the part that throws the error
}
ハッシュの競合が発生していないことは確かです。同じリクエストが立て続けに実行されたときに、レコードの重複が発生します。私の理解では、Spring Boot アプリケーションの実行中のインスタンスが 1 つしかない限り、発生しないはずです。本番環境で複数のインスタンスが実行されている以外に、何か理由はありますか?