Simplify logic for batching bulk identity check request

This commit is contained in:
Ehren Kret 2022-06-20 10:28:20 -05:00
parent 47300c1d44
commit cc8dda28cc
2 changed files with 30 additions and 36 deletions

View File

@ -373,6 +373,10 @@
<artifactId>reactor-core</artifactId> <artifactId>reactor-core</artifactId>
<version>3.3.16.RELEASE</version> <version>3.3.16.RELEASE</version>
</dependency> </dependency>
<dependency>
<groupId>io.vavr</groupId>
<artifactId>vavr</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>

View File

@ -12,6 +12,7 @@ import io.dropwizard.auth.Auth;
import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Metrics; import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Tags; import io.micrometer.core.instrument.Tags;
import io.vavr.Tuple;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom; import java.security.SecureRandom;
@ -330,45 +331,34 @@ public class ProfileController {
@Path("/identity_check/batch") @Path("/identity_check/batch")
public CompletableFuture<BatchIdentityCheckResponse> runBatchIdentityCheck(@NotNull @Valid BatchIdentityCheckRequest request) { public CompletableFuture<BatchIdentityCheckResponse> runBatchIdentityCheck(@NotNull @Valid BatchIdentityCheckRequest request) {
return CompletableFuture.supplyAsync(() -> { return CompletableFuture.supplyAsync(() -> {
List<BatchIdentityCheckResponse.Element> responseElements = Collections.synchronizedList(new ArrayList<>()); List<BatchIdentityCheckResponse.Element> responseElements = Collections.synchronizedList(new ArrayList<>());
BatchIdentityCheckResponse response = new BatchIdentityCheckResponse(responseElements);
// for small requests only run one batch final int targetBatchCount = 10;
if (request.elements().size() <= 30) { // clamp the amount per batch to be in the closed range [30, 100]
MessageDigest sha256; final int batchSize = Math.min(Math.max(request.elements().size() / targetBatchCount, 30), 100);
try { // add 1 extra batch if there is any remainder to consume the final non-full batch
sha256 = MessageDigest.getInstance("SHA-256"); final int batchCount =
} catch (NoSuchAlgorithmException e) { request.elements().size() / batchSize + (request.elements().size() % batchSize != 0 ? 1 : 0);
throw new AssertionError(e);
}
for (final BatchIdentityCheckRequest.Element element : request.elements()) {
checkFingerprintAndAdd(element, responseElements, sha256);
}
} else {
final int batchCount = 10;
final int batchSize = request.elements().size() / batchCount;
@SuppressWarnings("rawtypes") CompletableFuture[] futures = new CompletableFuture[batchCount];
for (int i = 0; i < batchCount; i++) { @SuppressWarnings("rawtypes") CompletableFuture[] futures = new CompletableFuture[batchCount];
List<BatchIdentityCheckRequest.Element> batch = request.elements() for (int i = 0; i < batchCount; ++i) {
.subList(i * batchSize, Math.min((i + 1) * batchSize, request.elements().size())); List<BatchIdentityCheckRequest.Element> batch = request.elements()
futures[i] = CompletableFuture.runAsync(() -> { .subList(i * batchSize, Math.min((i + 1) * batchSize, request.elements().size()));
MessageDigest sha256; futures[i] = CompletableFuture.runAsync(() -> {
try { MessageDigest sha256;
sha256 = MessageDigest.getInstance("SHA-256"); try {
} catch (NoSuchAlgorithmException e) { sha256 = MessageDigest.getInstance("SHA-256");
throw new AssertionError(e); } catch (NoSuchAlgorithmException e) {
} throw new AssertionError(e);
for (final BatchIdentityCheckRequest.Element element : batch) { }
checkFingerprintAndAdd(element, responseElements, sha256); for (final BatchIdentityCheckRequest.Element element : request.elements()) {
} checkFingerprintAndAdd(element, responseElements, sha256);
}); }
} });
}
CompletableFuture.allOf(futures).join(); return Tuple.of(futures, responseElements);
} }).thenComposeAsync(tuple2 -> CompletableFuture.allOf(tuple2._1).thenApply((ignored) -> new BatchIdentityCheckResponse(tuple2._2)));
return response;
});
} }
private void checkFingerprintAndAdd(BatchIdentityCheckRequest.Element element, private void checkFingerprintAndAdd(BatchIdentityCheckRequest.Element element,