Hdpi 6650 refactor org service to cache responses#2178
Conversation
…he ResumePossessionClaim event.
…rformance issues in the start method. This found only the single database connection for the retrieval of the draft.
…414-PerfTest-Env-Make-a-Claim-Baseline
…414-PerfTest-Env-Make-a-Claim-Baseline
…414-PerfTest-Env-Make-a-Claim-Baseline
…aim-Baseline' into HDPI-6650_refactor_org_service_to_cache_responses
…resent or older than 24 hour
…ith lower ttl locally and in preview
…sponses # Conflicts: # src/main/resources/application.yaml
DB breaking change scanRecommended reading: HMCTS zero-downtime database deployments No potentially breaking database changes were detected in the changed Flyway migration This check only scans changed Run details: https://github.com/hmcts/pcs-api/actions/runs/30100693784?check_suite_focus=true |
CCD diff summary👉 Full report: https://github.com/hmcts/pcs-api/actions/runs/30100693688?check_suite_focus=true No change |
tvr-hmcts
left a comment
There was a problem hiding this comment.
Looking good. Some initial comments.
| cachedOrganisationResponseRepository.findByIdamId(userIdam); | ||
|
|
||
| if (cachedResponse.isEmpty()) { | ||
| OrganisationDetailsResponse response = organisationDetailsService.getOrganisationDetails(userId); |
There was a problem hiding this comment.
perhaps a log in here to say "cache miss" or something along those lines?
| ex.getMessage(), ex); | ||
| // Return null instead of throwing to allow graceful degradation | ||
| log.error("Error retrieving organisation name and address from rd-professional API. Error: {}", | ||
| ex.getMessage(), ex); |
There was a problem hiding this comment.
Please remove the ex.getMessage() Exception on the end is ok to keep though.
See ticket HDPI-7594
|
|
||
| } catch (FeignException ex) { | ||
| log.error("Feign error retrieving organisation details for userId: {}. Status: {}, Message: {}", | ||
| userId, ex.status(), ex.getMessage(), ex); |
There was a problem hiding this comment.
Please remove the ex.getMessage() Exception on the end is ok to keep though.
See ticket HDPI-7594
| throw new OrganisationDetailsException("Failed to retrieve organisation details", ex); | ||
| } catch (Exception ex) { | ||
| log.error("Unexpected error retrieving organisation details for userId: {}. Error: {}", | ||
| userId, ex.getMessage(), ex); |
There was a problem hiding this comment.
Please remove the ex.getMessage() Exception on the end is ok to keep though.
See ticket HDPI-7594
| CREATE TABLE public.cached_organisation_response | ||
| ( | ||
| id UUID PRIMARY KEY, | ||
| idam_id UUID, |
There was a problem hiding this comment.
Think this should be NOT NULL
| id UUID PRIMARY KEY, | ||
| idam_id UUID, | ||
| organisation_id varchar(64), | ||
| last_modified_date TIMESTAMP, |
There was a problem hiding this comment.
Perhaps NOT NULL here also as it is needed in the checks.
There was a problem hiding this comment.
This timestamp 'may' need double checking as to the agreed approach as there is a splattering of different approaches in the code base - which I have gotten wrong before so pls take a look.
- remove exception message being logged
tvr-hmcts
left a comment
There was a problem hiding this comment.
Just some minors and small alterations from the save methods.
|
|
||
| CachedOrganisationResponseEntity newCachedResponse = mapResponseToEntity(userIdam, response); | ||
|
|
||
| cachedOrganisationResponseRepository.save(newCachedResponse); |
There was a problem hiding this comment.
normally fine but safer to return from this line itself incase we do anything else lower down.
| if (isDataRequiringResync(existingCachedResponse.getLastModifiedDate())) { | ||
| OrganisationDetailsResponse response = getOrganisationDetails(userId); | ||
| updateFields(existingCachedResponse, response, userId); | ||
| cachedOrganisationResponseRepository.save(existingCachedResponse); |
There was a problem hiding this comment.
safest to reasign existingCachedResponse = cachedOrgi...save(existingCachedResponse)
| * @param userId The user ID to get organisation details for | ||
| * @return OrganisationDetailsResponse containing organisation information | ||
| */ | ||
| private OrganisationDetailsResponse getOrganisationDetails(String userId) { |
There was a problem hiding this comment.
As this can return null then should it be Optional<...> then there can be a test on the Optional being empty as there is no test on the null return at the moment.
| import static org.mockito.Mockito.when; | ||
|
|
||
| @ExtendWith(MockitoExtension.class) | ||
| class CachingOrganisationDetailsServiceTest { |
There was a problem hiding this comment.
Think these should be assertThat(...).is... in this class
It is a bit missed at the moment.
| assertNull(actual.address().getAddressLine1()); | ||
|
|
||
| verify(cachedOrganisationResponseRepository).save(cachedEntity); | ||
| assertNull(cachedEntity.getAddressLine1()); |
There was a problem hiding this comment.
Perhaps all values of the existingCachedResponse can have an assertThat(x.y).isNull() To be sure to be sure.
| CachedOrganisationResponseEntity existingCachedResponse = cachedResponse.get(); | ||
|
|
||
| if (isDataRequiringResync(existingCachedResponse.getLastModifiedDate())) { | ||
| OrganisationDetailsResponse response = getOrganisationDetails(userId); |
There was a problem hiding this comment.
Minor : log in here to say it is resyncing.
| import uk.gov.hmcts.reform.pcs.service.FeatureFlag; | ||
| import uk.gov.hmcts.reform.pcs.service.FeatureToggleService; | ||
| import uk.gov.hmcts.reform.pcs.testingsupport.model.TestingSupportAccessCode; | ||
| import uk.gov.hmcts.reform.pcs.ccd.entity.ClaimEntity; |
There was a problem hiding this comment.
unused imports - wonder why the pipeline did not catch them
tvr-hmcts
left a comment
There was a problem hiding this comment.
Think it is good to go :)
| if (response.isPresent()) { | ||
| updateFields(existingCachedResponse, response.get(), userId); | ||
| } else { | ||
| clearCachedFields(existingCachedResponse); |
There was a problem hiding this comment.
This can still leave the NameAndAddress being returned with nulls set.
| caseData.setClaimantType(claimantTypeList); | ||
|
|
||
| contactPreferences.setOrganisationAddress(organisationService.getOrganisationAddressForCurrentUser()); | ||
| contactPreferences.setOrganisationAddress(null != nameAndAddress ? nameAndAddress.address() : null); |
There was a problem hiding this comment.
There is a slight difference here in that the AddressUK will not be null but the values within it now can be. Is that ok?
| id UUID PRIMARY KEY, | ||
| idam_id UUID NOT NULL, | ||
| organisation_id varchar(64), | ||
| last_modified_date TIMESTAMP NOT NULL, |
There was a problem hiding this comment.
Doesn't the date need to be with timezone ? In claim_issued_date and claim_submitted_date they're both timestamptz.
| AuthTokenGenerator authTokenGenerator, | ||
| @Qualifier("prdAdminTokenProvider") | ||
| IdamTokenProvider prdAdminTokenProvider) { | ||
| this(cachedOrganisationResponseRepository, ttlInMinutes, LocalDateTime::now, |
There was a problem hiding this comment.
Should we be using the same approach as in ClaimService to have similar date handling ?
…signed in) via postman
Jira link
See [HDPI-6550-](https://tools.hmcts.net/jira/browse/HDPI-6650)
Change description
Introduced a cache wrapper around organisationDetailsService.getOrganisationIdentifier.
Organisation details for a given user IdamId is stored in "cached_organisation_response"
Invocations to organisationService now will call the cached solution.
Cache service checks if a response exists for a idamId, if not present then calls rdProfessional.
If present but older than the configurable TTL then will be retrieved again otherwise the cached response is returned.
Testing done
Unit testing
Manual on preview, updating the "dbrefdata.organisation.id" in "rd-professional" for organisation with organisation_identifier='FHBG1F8' for user "possession-org-test-automation@test.com"
Security Vulnerability Assessment
CVE Suppression: Are there any CVEs present in the codebase (either newly introduced or pre-existing) that are being intentionally suppressed or ignored by this commit?
Checklist