generated from ministryofjustice/hmpps-template-kotlin
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* CPR-593 Add initial population endpoint for person match * CPR-593 Add feign client for person match * CPR-593 Format * CPR-593 Get Tests working * CPR-593 Test request is in correct format * CPR-593 Add runbook * CPR-593 Run format * CPR-593 Not required for message consumption to be paused * CPR-593 Add log statement * CPR-593 Add elapsed time to log * CPR-593 Run format * CPR-593 Add extra test + review comments * CPR-593 Remove wildcard import * CPR-593 Fix tests * CPR-593 Use helper methods * CPR-593 Update match id * CPR-593 Fix tests * CPR-593 Fix lint
- Loading branch information
1 parent
5b46403
commit c2f116c
Showing
17 changed files
with
426 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# 001 - Seeding Person Match | ||
|
||
This is the runbook to send person match all the person data that it needs to use to match with. | ||
|
||
## Prerequisites | ||
|
||
* Must have kubernetes access to the desired namespace | ||
* Must have `kubectl`, which can be installed [here](https://kubernetes.io/docs/tasks/tools/#kubectl) | ||
|
||
## Namespace | ||
|
||
For hmpps-person-record the namespaces are listed below: | ||
* `hmpps-person-record-dev` | ||
* `hmpps-person-record-preprod` | ||
* `hmpps-person-record-prod` | ||
|
||
## 1. Start Seeding Person Match | ||
|
||
To kick off the process you must connect to the hmpps-person-record pod first, by: | ||
|
||
```shell | ||
kubectl exec -it deployment/hmpps-person-record -n <namespace> -- bash | ||
``` | ||
|
||
Then within the pod run, to kick off the desired process: | ||
|
||
> WARNING: | ||
> You must not deploy to the environment that scheduled for seeding once the job has started. Otherwise, it will be cancelled. | ||
|
||
To trigger process: | ||
```shell | ||
curl -i -X POST http://localhost:8080/populatepersonmatch | ||
``` | ||
Once the process has completed it will output the number of pages and records to processed. | ||
It will notify once finished with: `Finished populating person-match, total pages: <totalPages>, total elements: <totalElements>, time elapsed: <time_elapsed>"` | ||
|
||
## Troubleshooting | ||
|
||
### Seeding Processing Fails | ||
|
||
If the processing of messages fails to create the new records. Either from a mapping issue or api issue. Prepare a fix then follow from step 2 to proceed with seeding the data. |
16 changes: 16 additions & 0 deletions
16
src/main/kotlin/uk/gov/justice/digital/hmpps/personrecord/client/PersonMatchClient.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package uk.gov.justice.digital.hmpps.personrecord.client | ||
|
||
import org.springframework.cloud.openfeign.FeignClient | ||
import org.springframework.web.bind.annotation.PostMapping | ||
import org.springframework.web.bind.annotation.RequestBody | ||
import uk.gov.justice.digital.hmpps.personrecord.client.model.match.PersonMatchRequest | ||
|
||
@FeignClient( | ||
name = "person-match", | ||
url = "\${person-match.base-url}", | ||
) | ||
interface PersonMatchClient { | ||
|
||
@PostMapping("/person/migrate") | ||
fun postPersonMigrate(@RequestBody personMatchRequest: PersonMatchRequest) | ||
} |
39 changes: 39 additions & 0 deletions
39
.../kotlin/uk/gov/justice/digital/hmpps/personrecord/client/model/match/PersonMatchRecord.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package uk.gov.justice.digital.hmpps.personrecord.client.model.match | ||
|
||
import uk.gov.justice.digital.hmpps.personrecord.jpa.entity.PersonEntity | ||
import uk.gov.justice.digital.hmpps.personrecord.jpa.entity.PersonEntity.Companion.getType | ||
import uk.gov.justice.digital.hmpps.personrecord.model.types.IdentifierType | ||
|
||
data class PersonMatchRecord( | ||
val matchId: String, | ||
val sourceSystem: String? = "", | ||
val firstName: String? = "", | ||
val middleNames: String? = "", | ||
val lastName: String? = "", | ||
val dateOfBirth: String? = "", | ||
val firstNameAliases: List<String> = listOf(), | ||
val lastNameAliases: List<String> = listOf(), | ||
val dateOfBirthAliases: List<String> = listOf(), | ||
val postcodes: List<String> = listOf(), | ||
val cros: List<String> = listOf(), | ||
val pncs: List<String> = listOf(), | ||
val sentenceDates: List<String> = listOf(), | ||
) { | ||
companion object { | ||
fun from(personEntity: PersonEntity): PersonMatchRecord = PersonMatchRecord( | ||
matchId = personEntity.matchId.toString(), | ||
sourceSystem = personEntity.sourceSystem.name, | ||
firstName = personEntity.firstName ?: "", | ||
middleNames = personEntity.middleNames ?: "", | ||
lastName = personEntity.lastName ?: "", | ||
dateOfBirth = personEntity.dateOfBirth?.toString() ?: "", | ||
firstNameAliases = personEntity.pseudonyms.mapNotNull { it.firstName }, | ||
lastNameAliases = personEntity.pseudonyms.mapNotNull { it.lastName }, | ||
dateOfBirthAliases = personEntity.pseudonyms.mapNotNull { it.dateOfBirth }.map { it.toString() }, | ||
postcodes = personEntity.addresses.mapNotNull { it.postcode }, | ||
cros = personEntity.references.getType(IdentifierType.CRO).mapNotNull { it.identifierValue }, | ||
pncs = personEntity.references.getType(IdentifierType.PNC).mapNotNull { it.identifierValue }, | ||
sentenceDates = personEntity.sentenceInfo.mapNotNull { it.sentenceDate }.map { it.toString() }, | ||
) | ||
} | ||
} |
5 changes: 5 additions & 0 deletions
5
...kotlin/uk/gov/justice/digital/hmpps/personrecord/client/model/match/PersonMatchRequest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package uk.gov.justice.digital.hmpps.personrecord.client.model.match | ||
|
||
data class PersonMatchRequest( | ||
val records: List<PersonMatchRecord> = listOf(), | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
85 changes: 85 additions & 0 deletions
85
src/main/kotlin/uk/gov/justice/digital/hmpps/personrecord/seeding/PopulatePersonMatch.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package uk.gov.justice.digital.hmpps.personrecord.seeding | ||
|
||
import jakarta.transaction.Transactional | ||
import kotlinx.coroutines.CoroutineScope | ||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.launch | ||
import org.slf4j.LoggerFactory | ||
import org.springframework.data.domain.Page | ||
import org.springframework.data.domain.PageRequest | ||
import org.springframework.web.bind.annotation.RequestMapping | ||
import org.springframework.web.bind.annotation.RequestMethod | ||
import org.springframework.web.bind.annotation.RestController | ||
import uk.gov.justice.digital.hmpps.personrecord.client.PersonMatchClient | ||
import uk.gov.justice.digital.hmpps.personrecord.client.model.match.PersonMatchRecord | ||
import uk.gov.justice.digital.hmpps.personrecord.client.model.match.PersonMatchRequest | ||
import uk.gov.justice.digital.hmpps.personrecord.jpa.entity.PersonEntity | ||
import uk.gov.justice.digital.hmpps.personrecord.jpa.repository.PersonRepository | ||
import uk.gov.justice.digital.hmpps.personrecord.service.RetryExecutor | ||
import kotlin.time.Duration | ||
import kotlin.time.measureTime | ||
|
||
private const val OK = "OK" | ||
|
||
@RestController | ||
class PopulatePersonMatch( | ||
private val personRepository: PersonRepository, | ||
private val personMatchClient: PersonMatchClient, | ||
private val retryExecutor: RetryExecutor, | ||
) { | ||
|
||
@RequestMapping(method = [RequestMethod.POST], value = ["/populatepersonmatch"]) | ||
suspend fun populate(): String { | ||
runPopulation() | ||
return OK | ||
} | ||
|
||
@Transactional | ||
suspend fun runPopulation() { | ||
CoroutineScope(Dispatchers.Default).launch { | ||
log.info("Starting population of person-match") | ||
val executionResults = forPage { page -> | ||
log.info("Populating person match, page: ${page.pageable.pageNumber + 1}") | ||
val personMatchRecords = page.content.map { PersonMatchRecord.from(it) } | ||
val personMatchRequest = PersonMatchRequest(records = personMatchRecords) | ||
retryExecutor.runWithRetryHTTP { personMatchClient.postPersonMigrate(personMatchRequest) } | ||
} | ||
log.info( | ||
"Finished populating person-match, total pages: ${executionResults.totalPages}, " + | ||
"total elements: ${executionResults.totalElements}, " + | ||
"elapsed time: ${executionResults.elapsedTime}", | ||
) | ||
} | ||
} | ||
|
||
private inline fun forPage(page: (Page<PersonEntity>) -> Unit): ExecutionResult { | ||
var pageNumber = 0 | ||
var personRecords: Page<PersonEntity> | ||
val elapsedTime: Duration = measureTime { | ||
do { | ||
val pageable = PageRequest.of(pageNumber, BATCH_SIZE) | ||
|
||
personRecords = personRepository.findAll(pageable) | ||
page(personRecords) | ||
|
||
pageNumber++ | ||
} while (personRecords.hasNext()) | ||
} | ||
return ExecutionResult( | ||
totalPages = personRecords.totalPages, | ||
totalElements = personRecords.totalElements, | ||
elapsedTime = elapsedTime, | ||
) | ||
} | ||
|
||
private data class ExecutionResult( | ||
val totalPages: Int, | ||
val totalElements: Long, | ||
val elapsedTime: Duration, | ||
) | ||
|
||
companion object { | ||
private const val BATCH_SIZE = 1000 | ||
private val log = LoggerFactory.getLogger(this::class.java) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
49 changes: 49 additions & 0 deletions
49
...lin/uk/gov/justice/digital/hmpps/personrecord/client/model/match/PersonMatchRecordTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package uk.gov.justice.digital.hmpps.personrecord.client.model.match | ||
|
||
import org.assertj.core.api.Assertions.assertThat | ||
import org.junit.jupiter.api.Test | ||
import uk.gov.justice.digital.hmpps.personrecord.jpa.entity.PersonEntity | ||
import uk.gov.justice.digital.hmpps.personrecord.jpa.entity.PseudonymEntity | ||
import uk.gov.justice.digital.hmpps.personrecord.jpa.entity.SentenceInfoEntity | ||
import uk.gov.justice.digital.hmpps.personrecord.model.types.NameType | ||
import uk.gov.justice.digital.hmpps.personrecord.model.types.SourceSystemType.DELIUS | ||
import java.time.LocalDate | ||
import java.util.UUID | ||
|
||
class PersonMatchRecordTest { | ||
|
||
@Test | ||
fun `should return empty strings when building request if is null`() { | ||
val personEntity = PersonEntity( | ||
matchId = UUID.randomUUID(), | ||
sourceSystem = DELIUS, | ||
) | ||
val personMatchRecord = PersonMatchRecord.from(personEntity) | ||
assertThat(personMatchRecord.firstName).isEmpty() | ||
assertThat(personMatchRecord.middleNames).isEmpty() | ||
assertThat(personMatchRecord.lastName).isEmpty() | ||
assertThat(personMatchRecord.dateOfBirth).isEmpty() | ||
assertThat(personMatchRecord.firstNameAliases).isEmpty() | ||
assertThat(personMatchRecord.lastNameAliases).isEmpty() | ||
assertThat(personMatchRecord.dateOfBirthAliases).isEmpty() | ||
assertThat(personMatchRecord.postcodes).isEmpty() | ||
assertThat(personMatchRecord.cros).isEmpty() | ||
assertThat(personMatchRecord.pncs).isEmpty() | ||
assertThat(personMatchRecord.sentenceDates).isEmpty() | ||
} | ||
|
||
@Test | ||
fun `should build dates in correct YYYY-MM-dd format`() { | ||
val date = LocalDate.of(1970, 1, 1) | ||
val personEntity = PersonEntity( | ||
dateOfBirth = date, | ||
pseudonyms = mutableListOf(PseudonymEntity(type = NameType.ALIAS, dateOfBirth = date)), | ||
sentenceInfo = mutableListOf(SentenceInfoEntity(sentenceDate = date)), | ||
sourceSystem = DELIUS, | ||
) | ||
val personMatchRecord = PersonMatchRecord.from(personEntity) | ||
assertThat(personMatchRecord.dateOfBirth).isEqualTo("1970-01-01") | ||
assertThat(personMatchRecord.dateOfBirthAliases).isEqualTo(listOf("1970-01-01")) | ||
assertThat(personMatchRecord.sentenceDates).isEqualTo(listOf("1970-01-01")) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.