Reputation: 71
I'm leaning webflux and reactor. Got three test methods as below. "documentOperations.findById" and "documentOperations.delete" are two database operations. I know test1 is bad as the two db operations are placed in one async method. My question is:
Do test2 and test3 have the same impact to system performace? Or in other words, which one is better?
private Mono<ServerResponse> test1(ServerRequest request, Contexts contexts) {
return request.body(bodyDocumentExtractor)
.flatMap(doc -> {
Document document = documentOperations.findById(doc.getId());
documentOperations.delete(document.getId());
return ServerResponse.noContent().build();
});
}
private Mono<ServerResponse> test2(ServerRequest request, Contexts contexts) {
return request.body(bodyDocumentExtractor)
.flatMap(doc -> {
return Mono.just(documentOperations.findById(doc.getId()))
.flatMap(document -> {
documentOperations.delete(document.getId());
return ServerResponse.noContent().build();
});
});
}
private Mono<ServerResponse> test3(ServerRequest request, Contexts contexts) {
return request.body(bodyDocumentExtractor)
.flatMap(doc -> {
return Mono.just(documentOperations.findById(doc.getId()));
}).flatMap(document -> {
documentOperations.delete(document.getId());
return ServerResponse.noContent().build();
});
}
Upvotes: 2
Views: 673
Reputation: 14819
None of the examples above are good. All your database calls return concrete types which means that they are all blocking calls.
// returns the concrete type
// thread does the call, needs to wait until we get the value (document)
Document document = documentOperations.findById("1");
If it is non blocking it returns a Mono<T>
or a Flux<T>
.
// Returns a mono, so we know it's not blocking.
// We can chain on actions with for example flatMap etc.
Mono<Document> document = documentOperations.findById("1");
If you have to use a blocking database like for instance oracle database etc. You need to place this on its entire own thread, so that it doesn't block any of the main worker threads. This can be done with a scheduler. So in this example when a client subscribes it will be placed on a separate thread.
Mono<Document> document = Mono.fromCallable(() -> documentOperations.findById("1"))
.subscribeOn(Schedulers.boundedElastic());;
So for your example:
private Mono<ServerResponse> test3(ServerRequest request, Contexts contexts) {
return request.body(bodyDocumentExtractor)
.flatMap(doc -> Mono.fromCallable(() -> documentOperations.findById(doc.getId()))
.flatMap(document -> Mono.fromCallable(() -> documentOperations.delete(document.getId()))
.then(ServerResponse.noContent().build());
).subscribeOn(Schedulers.boundedElastic());
}
Reactor documentation - Wrap blocking calls
Upvotes: 3
Reputation: 3005
I would expect the code to look something along the lines of the code below based on the assumption that DocumentOperations
is reactive.
private Mono<ServerResponse> test3(ServerRequest request, Contexts contexts) {
return request.body(bodyDocumentExtractor)
.flatMap(doc -> documentOperations.findById(doc.getId()))
.flatMap(document -> documentOperations.delete(document.getId()))
.then(ServerResponse.noContent().build());
}
Upvotes: 1