I write a complete reactive api with Spring boot and webflux and mongoDB.
Unfortunately on jmeter stress test time consuming start short then to be really long(stress test time processing)
I launched 100 threads in same time, if 10 first call are around 150ms, then it start to grow until Unbelievable times, i really do not understand what happen, as i have to go in production i am really stucked
controller
@Timed(value = "tokenization-service.tokenController.createNetworkToken.time", description = "time spent to create network token", longTask = true)
@Override
public Mono<ResponseEntity<NetworkTokenInformationResponse>> createNetworkToken(@Valid Mono<CardRequest> card, ServerWebExchange exchange) {
var start = System.currentTimeMillis();
return getTokenizationInformation.execute(card)
.doFinally(_ -> registry.counter("tokenization-service.tokenController.createNetworkToken").increment())
.tag("tokenization-service.controller", "createNetworkToken").metrics()
.map(token -> {
var finish = System.currentTimeMillis();
log.info("Time spent to create network token: {}", finish - start);
return ResponseEntity.created(URI.create(STR."/{token.getGatewayToken()}"))
.contentType(MediaType.APPLICATION_JSON)
.body(token);
}
);
}
my useCase(service)
import com.telr.tokenization.core.adapters.NetworkTokenTmsAdapter;
import com.telr.tokenization.core.adapters.TokenRepositoryAdapter;
import com.telr.tokenization.core.entities.CardRequest;
import com.telr.tokenization.core.entities.NetworkTokenInformationResponse;
import com.telr.tokenization.core.entities.cybersource.Card;
import com.telr.tokenization.core.entities.db.Token;
import com.telr.tokenization.infrastructure.exceptions.TokenizationServiceAlreadyExistsException;
import com.telr.tokenization.infrastructure.properties.ConfigProperties;
import lombok.AllArgsConstructor;
import lombok.NonNull;
import lombok.extern.log4j.Log4j2;
import org.bson.types.ObjectId;
import reactor.core.publisher.Mono;
@Log4j2
@AllArgsConstructor
public class GetTokenizationInformation {
private final ConfigProperties properties;
private final NetworkTokenTmsAdapter service;
private final TokenRepositoryAdapter repository;
public Mono<NetworkTokenInformationResponse> execute(@NonNull Mono<CardRequest> card) {
//log.info("Network token creation process starting");
return card.flatMap(c -> {
var hashedPan = Token.hashPan(c.getNumber(), properties.getHashing().getSecretKey());
return repository.findByHashedPan(hashedPan.trim())
.flatMap(_ -> {
//log.info("Token already existing for hashed pan {}, throwing exception", hashedPan);
return Mono.<NetworkTokenInformationResponse>error(new TokenizationServiceAlreadyExistsException("Token already existing for hashed pan"));
})
});
}
}
repository
@Repository
public interface TokenRepositoryAdapter extends ReactiveCrudRepository<Token, String> {
Mono<Token> findByGatewayToken(String gatewayToken);
Mono<Token> findByHashedPan(String hashedPan);
@Query(value = "{ 'tmsInstrumentIdentifier.tokenizedCard.expirationYear' : ?0, 'tmsInstrumentIdentifier.tokenizedCard.expirationMonth' : { $lt: ?1 } }")
Flux<Token> findByTokenizedCardExpiredDate(int year, int month);
}
what i am doing wrong ?
time given by controller
and by jmeter (morover we can see throughput is really low 20 query/s we should go 100 or more
As we can see i only execute a query on database that have index so should be fast, what is blocking ? any idea?