2
I set up a test scenario to treat an error that was happening on my frontend.
Situation Problema:
The problem was that I was making a requisition for a route ‘/api/v1/telefones’
, Spring ends up returning me ‘/api/v1/perfis’
, as if the behavior were a cache. The data in the frontend, in some moments were not rendered, and it was when I decided to implement the stress test since I was not able to catch by the debug mode.
In addition to one having thought of being a cache problem, such as a route that returns a Phone API, it returns a Profile API, since endpoint is configured with relevant entities?
Stress test scenario
The tests performed captured the following amount of errors:
https://i.stack.Imgur.com/4x8B6.png
The time and amount of requests made are stored in the image below:
https://i.stack.Imgur.com/vMyfh.png
The scenario is a mass of requests made at alternating times, for two endpoins, the profile and the telephone, simulating parallel requests. View the Javascript code I implemented for testing:
setInterval(() => {
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if(request.readyState === 4) {
if(request.status === 200) {
// console.log(request.responseText);
} else {
console.log('An error occurred during your request: ' + request.status + ' ' + request.statusText);
}
}
}
request.open('Get', 'http://localhost:8080/api/v1/perfis');
request.send();
} , 225);
setInterval(() => {
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if(request.readyState === 4) {
if(request.status === 200) {
if (request.response !== '{"data":[{"id":"9040de2b-137a-45d3-902e-5ecdf4cf8c6d","codigoDeArea":"22","numero":"123654789"},{"id":"c5490c98-6a3f-4bd7-a7bc-b282750cec97","codigoDeArea":"22","numero":"997855566"}],"errors":[]}') {
console.log(request.responseText);
}
} else {
console.log('An error occurred during your request: ' + request.status + ' ' + request.statusText);
}
}
}
request.open('Get', 'http://localhost:8080/api/v1/telefones/lista');
request.send();
} , 300);
The problem was identified when the request was being made to the phone API. The Java code that implements the Endpoint it is quite simple this built in the following way:
@RestController
@RequestMapping(path = "api/v1/telefones")
public class TelefoneController implements ControllerTemplate<TelefoneDto> {
@Qualifier("telefoneServiceImpl")
@Autowired
private TelefoneService service;
@Autowired
private RestResponse<List<TelefoneDto>> responseList;
(...)
@GetMapping(path = "/lista")
public ResponseEntity<RestResponse<List<TelefoneDto>>> buscaTudoPorUsusarioCorrente(@AuthenticationPrincipal UserDetails userDetails) {
String apelido = userDetails.getUsername();
List<TelefoneDto> dtos = service.buscaTudoPorApelido(apelido);
responseList.setData(dtos);
return ResponseEntity.ok(responseList);
}
}
My method of service code is:
@Override
public List<TelefoneDto> buscaTudoPorApelido(String apelido) {
List<TelefoneEntity> entities = repository.buscaTudoPorApelidoDoUsuario(apelido);
return converter.toDtoList(entities);
}
My custom query is:
@Query("select t from Telefone t join Perfil p on p.pessoa = t.pessoa join Pessoa pe on pe = p.pessoa join Usuario u on p.usuario = u where u.apelido = :apelido")
List<TelefoneEntity> buscaTudoPorApelidoDoUsuario(@Param("apelido") String apelido);
My Profile control is:
@RestController
@RequestMapping(path = "api/v1/perfis")
public class PerfilController implements ControllerTemplate<PerfilDto> {
@Qualifier("perfilServiceImpl")
@Autowired
private PerfilService service;
@Autowired
private RestResponse<PerfilDto> response;
@Autowired
private RestResponse<List<PerfilDto>> responseList;
@Autowired
private PerfilValidator validator;
@Override
@GetMapping
public ResponseEntity<RestResponse<List<PerfilDto>>> buscaTudo() {
List<PerfilDto> entities = service.buscaTudo();
responseList.setData(entities);
return ResponseEntity.ok(responseList);
}
@Override
@GetMapping(path = "/{id}")
public ResponseEntity<RestResponse<PerfilDto>> buscaPorId(@PathVariable("id") String id) {
PerfilDto entity = service.buscaPorId(id);
response.setData(entity);
return ResponseEntity.ok(response);
}
@Override
@PostMapping
public ResponseEntity<RestResponse<PerfilDto>> salvar(@RequestBody PerfilDto perfilDto) {
validator.naoPodeAdicionar(perfilDto);
PerfilDto entity = service.salvar(perfilDto);
response.setData(entity);
return ResponseEntity.ok(response);
}
@Override
@PutMapping
public ResponseEntity<RestResponse<PerfilDto>> atualizar(@RequestBody PerfilDto perfilDto) {
validator.naoPodeAtualizar(perfilDto);
PerfilDto entity = service.atualizar(perfilDto);
response.setData(entity);
return ResponseEntity.ok(response);
}
@Override
@DeleteMapping
public ResponseEntity<?> removePorId(@PathParam("id") String id) {
validator.naoPodeRemover(id);
service.removePorId(id);
return ResponseEntity.ok(true);
}
@GetMapping(path = "/usuarioCorrente")
public ResponseEntity<RestResponse<?>> buscaPorApelidoUsuarioCorrente(@AuthenticationPrincipal UserDetails userDetails) {
PerfilDto resp = service.buscaPorApelidoUsuario(userDetails.getUsername());
response.setData(resp);
return ResponseEntity.ok(response);
}
}
Libraries and versions:
- Java 8 (I did Downgrade for Java 8, before it was 13, because I thought maybe it would be a version problem)
- Spring 2.2.2.RELEASE
- Lombok
- JPA
- Postgre
How to solve?
- I would like to know how to solve this problem?
- Because a request being made to phone api, returns an endpoint from the profile api?
OBS:
I’m NOT USING CACHE!
Video link with stress test: https://player.vimeo.com/video/384000413
Link to the complete project: https://github.com/thiagosantoscunha/salesiana-start-backend
That part I picked up in Debug mode, Jackson does the right entity Reflection and performs the query in the right way. The problem is still bigger!
– Thiago Cunha