DRAFT
Overview
This document has been created to show poor performance of requisition submit/save endpoints. It contains:
...
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
public RequisitionDto authorizeRequisition(updateRequisition(@RequestBody RequisitionDto requisitionDto, @PathVariable("id") UUID requisitionId) { permissionService.canAuthorizeRequisitioncanUpdateRequisition(requisitionId); if (isNotTrue(isNull(requisitionDto.getId())) (configurationSettingService.getBoolValue("skipAuthorization" && isNotTrue(requisitionId.equals(requisitionDto.getId()))) { throw new ValidationMessageException(new Message(ERROR_AUTHORIZATION_TO_BE_SKIPPEDID_MISMATCH)); } Requisition requisitionrequisitionToUpdate = requisitionRepository.findOne(requisitionId); if (requisition == null(isNull(requisitionToUpdate)) { throw new ContentNotFoundMessageException(new Message( new Message(MessageKeys.ERROR_REQUISITION_NOT_FOUND, requisitionId)); } Requisition requisition = RequisitionBuilder.newRequisition(requisitionDto, requisitionToUpdate.getTemplate(), requisitionToUpdate.getProgramId(), requisitionToUpdate.getStatus()); requisition.setId(requisitionId); requisitionVersionValidator.validateRequisitionTimestamps( requisition, requisitionToUpdate ); RequisitionStatus status = requisitionToUpdate.getStatus(); if (status != RequisitionStatus.APPROVED && status != RequisitionStatus.SKIPPED && status != RequisitionStatus.RELEASED) { LOGGER.debug("Updating requisition with id: {}", requisitionId); BindingResult bindingResult = new BeanPropertyBindingResult(requisition, REQUISITION); validatordraftValidator.validate(requisition, bindingResult); if (bindingResult.hasErrors()) { LOGGER.warn("Validation for requisition failed: {}", getErrors(bindingResult)); throw new BindingResultException(getErrors(bindingResult)); } facilitySupportsProgramHelper.checkIfFacilitySupportsProgram(requisition.getFacilityId(), requisitionToUpdate.updateFrom(requisition, stockAdjustmentReasonReferenceDataService.getStockAdjustmentReasonsByProgram( requisitionrequisitionToUpdate.getProgramId()), orderableReferenceDataService.findAll()); UserDto userrequisitionToUpdate = authenticationHelperrequisitionRepository.getCurrentUsersave(requisitionToUpdate); LOGGER.debug("Saved requisition.authorize(orderableReferenceDataService.findAll(), user.getId()); UUID supervisoryNode = supervisoryNodeReferenceDataService.findSupervisoryNode( requisition.getProgramId(), requisition.getFacilityId()).getId with id: " + requisitionToUpdate.getId()); return requisitionDtoBuilder.build(requisitionToUpdate); } else { throw new ValidationMessageException(new Message(ERROR_CANNOT_UPDATE_WITH_STATUS, requisitionToUpdate.getStatus())); } } |
Time consuming calls:
- Line 313: Build the response dto.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
public RequisitionDto submitRequisition(@PathVariable("id") UUID requisitionId) { permissionService.canSubmitRequisition(requisitionId); Requisition requisition = requisitionRepository.findOne(requisitionId); if (requisition == null) { throw new ContentNotFoundMessageException( new Message(MessageKeys.ERROR_REQUISITION_NOT_FOUND, requisitionId)); } BindingResult bindingResult = new BeanPropertyBindingResult(requisition, REQUISITION); validator.validate(requisition, bindingResult); if (bindingResult.hasErrors()) { LOGGER.warn("Validation for requisition failed: {}", getErrors(bindingResult)); throw new BindingResultException(getErrors(bindingResult)); } facilitySupportsProgramHelper.checkIfFacilitySupportsProgram(requisition.getFacilityId(), requisition.getProgramId()); LOGGER.debug("Submitting a requisition with id " + requisition.getId()); UserDto user = authenticationHelper.getCurrentUser(); requisition.setSupervisoryNodeId(supervisoryNode.submit(orderableReferenceDataService.findAll(), user.getId()); saveStatusMessage(requisition); requisitionRepository.save(requisition); requisitionStatusProcessor.statusChange(requisition); LOGGER.debug("Requisition: with id " + requisitionIdrequisition.getId() + " authorized.submitted"); return requisitionDtoBuilder.build(requisition); } |
Time consuming calls:
- Line 537237: Fetch Fetch all the orderables from reference data service.
- Line 549244: Build Build the response dto.
RequisitionDtoBuilder
Code Block | ||||
---|---|---|---|---|
| ||||
public RequisitionDto build(Requisition requisition) { if (null == requisition) { return null; } RequisitionDto requisitionDto = new RequisitionDto(); requisition.export(requisitionDto); List<RequisitionLineItemDto> requisitionLineItemDtoList = requisitionExportHelper.exportToDtos(requisition.getRequisitionLineItems()); requisitionDto.setTemplate(requisition.getTemplate()); requisitionDto.setFacility(facilityReferenceDataService.findOne(requisition.getFacilityId())); requisitionDto.setProgram(programReferenceDataService.findOne(requisition.getProgramId())); requisitionDto.setProcessingPeriod(periodService.getPeriod( requisition.getProcessingPeriodId())); requisitionDto.setRequisitionLineItems(requisitionLineItemDtoList); if (null != requisition.getAvailableNonFullSupplyProducts()) { requisitionDto.setAvailableNonFullSupplyProducts( requisition.getAvailableNonFullSupplyProducts() .stream() .filter(Objects::nonNull) .map(orderableReferenceDataService::findOne) .collect(Collectors.toSet()) ); } return requisitionDto; } |
...
- Lines 87-95: Fetch each of requisition's non full supply products from reference data service one by one.
Solutions
Both save and submit:
- Return only relevant information about a requisition to the client: Do we really need to return non full supply products in the response of authorize endpointthose endpoints? Perhaps we could keep this as a set of UUIDs instead of calling orderableReferenceDataService.findOne for each one of them, or, if really needed, Another solution would be to create a batch endpoint that returns all of them at once
Submit:
- We could reuse products that were previously retrieved in RequisitionController.
- Try not to fetch all the orderables, search them by facility/program instead.