Skip to content

Commit

Permalink
Deler opp flyten i forskjellige steg (#26)
Browse files Browse the repository at this point in the history
Deler opp flyten i forskjellige steg
Mulighet for å stoppe på et gitt steg og tilrettelegger for å kunne gjenoppta kjøring fra et gitt steg. Resultat lagres mellom hvert steg slik at man ikke ruller tilbake mer enn gjeldende steg ved eventuelle feil.
  • Loading branch information
matiasvinjevoll authored Oct 7, 2024
1 parent c760487 commit d4b7570
Show file tree
Hide file tree
Showing 22 changed files with 493 additions and 27 deletions.
3 changes: 2 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ dependencies {
implementation("org.flywaydb:flyway-database-postgresql:10.18.0")
implementation("org.postgresql:postgresql:42.7.4")

testImplementation("org.junit.jupiter:junit-jupiter-api:5.11.1")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.11.0")
testImplementation("no.nav.aap.kelvin:dbtest:$komponenterVersjon")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.11.1")
testImplementation("org.assertj:assertj-core:3.26.3")
testImplementation("org.testcontainers:postgresql:1.20.1")
testImplementation("io.mockk:mockk:1.13.12")
Expand Down
9 changes: 7 additions & 2 deletions app/src/main/kotlin/no/nav/aap/brev/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import no.nav.aap.komponenter.server.commonKtorModule
import no.nav.aap.motor.Motor
import no.nav.aap.motor.api.motorApi
import no.nav.aap.motor.mdc.NoExtraLogInfoProvider
import no.nav.aap.motor.retry.RetryService
import no.nav.aap.tilgang.authorizedGetWithApprovedList
import no.nav.aap.tilgang.authorizedPostWithApprovedList
import no.nav.aap.tilgang.installerTilgangPluginWithApprovedList
Expand Down Expand Up @@ -106,7 +107,7 @@ internal fun Application.server(
behandlingsflytAzp
) { _, request ->
val referanse = dataSource.transaction { connection ->
BrevbestillingService.konstruer(connection).behandleBrevbestilling(
BrevbestillingService.konstruer(connection).opprettBestilling(
behandlingReferanse = request.behandlingReferanse,
brevtype = request.brevtype,
språk = request.sprak,
Expand All @@ -126,7 +127,7 @@ internal fun Application.server(
respond(brevbestilling)
}

put<BrevbestillingReferansePathParam, Unit, Brev>() { referanse, brev ->
put<BrevbestillingReferansePathParam, Unit, Brev> { referanse, brev ->
installerTilgangPluginWithApprovedList(listOf(behandlingsflytAzp))
dataSource.transaction { connection ->
BrevbestillingService.konstruer(connection)
Expand All @@ -152,6 +153,10 @@ private fun Application.module(dataSource: DataSource): Motor {
jobber = listOf(ProsesserBrevbestillingJobbUtfører),
)

dataSource.transaction { dbConnection ->
RetryService(dbConnection).enable()
}

environment.monitor.subscribe(ApplicationStarted) {
motor.start()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import no.nav.aap.brev.domene.Brevbestilling
import no.nav.aap.brev.domene.BrevbestillingReferanse
import no.nav.aap.brev.domene.Brevtype
import no.nav.aap.brev.domene.Språk
import no.nav.aap.brev.domene.ProsesseringStatus

interface BrevbestillingRepository {
fun opprettBestilling(
Expand All @@ -20,4 +21,9 @@ interface BrevbestillingRepository {
referanse: BrevbestillingReferanse,
brev: Brev,
)
}

fun oppdaterProsesseringStatus(
referanse: BrevbestillingReferanse,
prosesseringStatus: ProsesseringStatus,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import no.nav.aap.brev.domene.Brevbestilling
import no.nav.aap.brev.domene.BrevbestillingReferanse
import no.nav.aap.brev.domene.Brevtype
import no.nav.aap.brev.domene.Språk
import no.nav.aap.brev.domene.ProsesseringStatus
import no.nav.aap.brev.exception.BestillingForBehandlingEksistererException
import no.nav.aap.komponenter.dbconnect.DBConnection
import no.nav.aap.komponenter.httpklient.json.DefaultJsonMapper
Expand Down Expand Up @@ -61,6 +62,7 @@ class BrevbestillingRepositoryImpl(private val connection: DBConnection) : Brevb
behandlingReferanse = BehandlingReferanse(row.getUUID("BEHANDLING_REFERANSE")),
brevtype = row.getEnum("BREVTYPE"),
språk = row.getEnum("SPRAK"),
prosesseringStatus = row.getEnumOrNull("PROSESSERING_STATUS"),
)
}
}
Expand All @@ -80,4 +82,17 @@ class BrevbestillingRepositoryImpl(private val connection: DBConnection) : Brevb
}
}

override fun oppdaterProsesseringStatus(
referanse: BrevbestillingReferanse,
prosesseringStatus: ProsesseringStatus,
) {
connection.execute(
"UPDATE BREVBESTILLING SET PROSESSERING_STATUS = ? WHERE REFERANSE = ?"
) {
setParams {
setEnumName(1, prosesseringStatus)
setUUID(2, referanse.referanse)
}
}
}
}
4 changes: 2 additions & 2 deletions app/src/main/kotlin/no/nav/aap/brev/BrevbestillingService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class BrevbestillingService(

private val log = LoggerFactory.getLogger(BrevbestillingService::class.java)

fun behandleBrevbestilling(
fun opprettBestilling(
behandlingReferanse: BehandlingReferanse,
brevtype: Brevtype,
språk: Språk,
Expand All @@ -43,7 +43,7 @@ class BrevbestillingService(

val jobb =
JobbInput(ProsesserBrevbestillingJobbUtfører)
.medCallId()
.medCallId()
.medParameter(BESTILLING_REFERANSE_PARAMETER_NAVN, referanse.referanse.toString())

jobbRepository.leggTil(jobb)
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/kotlin/no/nav/aap/brev/domene/Brevbestilling.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ data class Brevbestilling(
val behandlingReferanse: BehandlingReferanse,
val brevtype: Brevtype,
val språk: Språk,
)
val prosesseringStatus: ProsesseringStatus?,
)
11 changes: 11 additions & 0 deletions app/src/main/kotlin/no/nav/aap/brev/domene/ProsesseringStatus.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package no.nav.aap.brev.domene

enum class ProsesseringStatus {
STARTET,
INNHOLD_HENTET,
FAKTAGRUNNLAG_HENTET,
BREV_FERDIGSTILT,
JOURNALFORT,
DISTRIBUERT,
FERDIG
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package no.nav.aap.brev.prosessering

import no.nav.aap.brev.BrevbestillingRepositoryImpl
import no.nav.aap.brev.domene.BrevbestillingReferanse
import no.nav.aap.brev.innhold.SanityBrevinnholdGateway
import no.nav.aap.komponenter.dbconnect.DBConnection
import no.nav.aap.motor.Jobb
import no.nav.aap.motor.JobbInput
Expand All @@ -15,7 +13,7 @@ class ProsesserBrevbestillingJobbUtfører(
override fun utfør(input: JobbInput) {
val referanse = BrevbestillingReferanse(UUID.fromString(input.parameter(BESTILLING_REFERANSE_PARAMETER_NAVN)))

prosesserStegService.prosesserBestilling(ProsesserStegService.Kontekst(referanse))
prosesserStegService.prosesserBestilling(referanse)
}

companion object : Jobb {
Expand All @@ -24,9 +22,8 @@ class ProsesserBrevbestillingJobbUtfører(

override fun konstruer(connection: DBConnection): JobbUtfører {
return ProsesserBrevbestillingJobbUtfører(
ProsesserStegService(
brevbestillingRepository = BrevbestillingRepositoryImpl(connection),
brevinnholdGateway = SanityBrevinnholdGateway(),
ProsesserStegService.konstruer(
connection = connection,
)
)
}
Expand All @@ -43,4 +40,4 @@ class ProsesserBrevbestillingJobbUtfører(
return "Ansvarlig for å gjennomføre bestilling av brev"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,62 @@
package no.nav.aap.brev.prosessering

import no.nav.aap.brev.BrevbestillingRepository
import no.nav.aap.brev.BrevbestillingRepositoryImpl
import no.nav.aap.brev.domene.BrevbestillingReferanse
import no.nav.aap.brev.innhold.BrevinnholdGateway
import no.nav.aap.brev.domene.ProsesseringStatus
import no.nav.aap.brev.prosessering.steg.DistribuerJournalpostSteg
import no.nav.aap.brev.prosessering.steg.FerdigSteg
import no.nav.aap.brev.prosessering.steg.FerdigstillBrevSteg
import no.nav.aap.brev.prosessering.steg.HentFaktagrunnlagSteg
import no.nav.aap.brev.prosessering.steg.HentInnholdSteg
import no.nav.aap.brev.prosessering.steg.JournalførBrevSteg
import no.nav.aap.brev.prosessering.steg.StarterSteg
import no.nav.aap.brev.prosessering.steg.Steg
import no.nav.aap.komponenter.dbconnect.DBConnection
import org.slf4j.LoggerFactory

class ProsesserStegService(
private val brevbestillingRepository: BrevbestillingRepository,
private val brevinnholdGateway: BrevinnholdGateway,
private val connection: DBConnection
) {

companion object {
fun konstruer(connection: DBConnection): ProsesserStegService {
return ProsesserStegService(connection)
}
}

private val log = LoggerFactory.getLogger(ProsesserStegService::class.java)
private val brevbestillingRepository = BrevbestillingRepositoryImpl(connection)

private val flyt = ProsesseringFlyt.Builder()
.med(steg = StarterSteg, utfall = ProsesseringStatus.STARTET)
.med(steg = HentInnholdSteg, utfall = ProsesseringStatus.INNHOLD_HENTET)
.med(steg = HentFaktagrunnlagSteg, utfall = ProsesseringStatus.FAKTAGRUNNLAG_HENTET)
.med(steg = FerdigstillBrevSteg, utfall = ProsesseringStatus.BREV_FERDIGSTILT)
.med(steg = JournalførBrevSteg, utfall = ProsesseringStatus.JOURNALFORT)
.med(steg = DistribuerJournalpostSteg, utfall = ProsesseringStatus.DISTRIBUERT)
.med(steg = FerdigSteg, utfall = ProsesseringStatus.FERDIG)
.build()

data class Kontekst(val referanse: BrevbestillingReferanse)
fun prosesserBestilling(referanse: BrevbestillingReferanse) {

fun prosesserBestilling(kontekst: Kontekst) {
val referanse = kontekst.referanse
val bestilling = brevbestillingRepository.hent(referanse)
val stegene = flyt.fraStatus(bestilling.prosesseringStatus)

if (stegene.isEmpty()) {
log.warn("Forsøkte å prosessere bestilling uten flere steg og status ${bestilling.prosesseringStatus}.")
return
}

stegene.forEach { steg ->
val stegResultat = steg.konstruer(connection).utfør(Steg.Kontekst(referanse))

if (stegResultat == Steg.Resultat.STOPP) {
return
}

log.info("Henter brevinnhold for bestillingsreferanse=$referanse")
val brev = brevinnholdGateway.hentBrevmal(bestilling.brevtype, bestilling.språk)
brevbestillingRepository.oppdaterProsesseringStatus(referanse, flyt.utfall(steg))

brevbestillingRepository.oppdaterBrev(referanse, brev)
connection.markerSavepoint()
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package no.nav.aap.brev.prosessering

import no.nav.aap.brev.domene.ProsesseringStatus
import no.nav.aap.brev.prosessering.steg.Steg

class ProsesseringFlyt private constructor(
private val rekkefølge: List<Steg>,
private val stegTilUtfall: HashMap<Steg, ProsesseringStatus>,
private val utfallTilSteg: HashMap<ProsesseringStatus, Steg>,
) {

fun fraStatus(prosesseringStatus: ProsesseringStatus?): List<Steg> {
if (prosesseringStatus == null) {
return rekkefølge
}
val stegForUtfall = utfallTilSteg[prosesseringStatus]
?: throw IllegalStateException("Uforventet oppslag av udefinert steg for status $prosesseringStatus")
return rekkefølge.dropWhile { it != stegForUtfall }.drop(1)
}

fun utfall(steg: Steg): ProsesseringStatus {
return stegTilUtfall[steg]
?: throw IllegalStateException("Uforventet oppslag av udefinert utfall for steg $steg")
}

class Builder {
private val rekkefølge = mutableListOf<Steg>()
private val stegTilUtfall = mutableMapOf<Steg, ProsesseringStatus>()
private val utfallTilSteg = mutableMapOf<ProsesseringStatus, Steg>()

fun med(steg: Steg, utfall: ProsesseringStatus): Builder {
if (rekkefølge.contains(steg)) {
throw IllegalArgumentException("Steg $steg er allerede lagt til.")
}
if (utfallTilSteg.keys.contains(utfall)) {
throw IllegalArgumentException("Utfall $utfall er allerede lagt til.")
}
rekkefølge.add(steg)
stegTilUtfall.put(steg, utfall)
utfallTilSteg.put(utfall, steg)

return this
}

fun build(): ProsesseringFlyt {
if (rekkefølge.isEmpty()) {
throw IllegalStateException("Ingen steg å prosessere.")
}

return ProsesseringFlyt(
rekkefølge = rekkefølge,
stegTilUtfall = HashMap(stegTilUtfall),
utfallTilSteg = HashMap(utfallTilSteg),
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package no.nav.aap.brev.prosessering.steg

import no.nav.aap.komponenter.dbconnect.DBConnection
import org.slf4j.LoggerFactory

class DistribuerJournalpostSteg() : Steg.Utfører {
private val log = LoggerFactory.getLogger(DistribuerJournalpostSteg::class.java)
override fun utfør(kontekst: Steg.Kontekst): Steg.Resultat {
log.info("DistribuerJournalpostSteg")
return Steg.Resultat.FULLFØRT
}

companion object : Steg {
override fun konstruer(connection: DBConnection): Steg.Utfører {
return DistribuerJournalpostSteg()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package no.nav.aap.brev.prosessering.steg

import no.nav.aap.komponenter.dbconnect.DBConnection
import org.slf4j.LoggerFactory

class FerdigSteg() : Steg.Utfører {
private val log = LoggerFactory.getLogger(FerdigSteg::class.java)
override fun utfør(kontekst: Steg.Kontekst): Steg.Resultat {
log.info("Prosessering er ferdig.")
return Steg.Resultat.FULLFØRT
}

companion object : Steg {
override fun konstruer(connection: DBConnection): Steg.Utfører {
return FerdigSteg()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package no.nav.aap.brev.prosessering.steg

import no.nav.aap.komponenter.dbconnect.DBConnection
import org.slf4j.LoggerFactory

class FerdigstillBrevSteg() : Steg.Utfører {
private val log = LoggerFactory.getLogger(FerdigstillBrevSteg::class.java)
override fun utfør(kontekst: Steg.Kontekst): Steg.Resultat {
log.info("FerdigstillBrevSteg")
return Steg.Resultat.FULLFØRT
}

companion object : Steg {
override fun konstruer(connection: DBConnection): Steg.Utfører {
return FerdigstillBrevSteg()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package no.nav.aap.brev.prosessering.steg

import no.nav.aap.komponenter.dbconnect.DBConnection
import org.slf4j.LoggerFactory

class HentFaktagrunnlagSteg() : Steg.Utfører {
private val log = LoggerFactory.getLogger(HentFaktagrunnlagSteg::class.java)
override fun utfør(kontekst: Steg.Kontekst): Steg.Resultat {
log.info("HentFaktagrunnlagSteg")
return Steg.Resultat.FULLFØRT
}

companion object : Steg {
override fun konstruer(connection: DBConnection): Steg.Utfører {
return HentFaktagrunnlagSteg()
}
}
}
Loading

0 comments on commit d4b7570

Please sign in to comment.