Skip to content

Commit

Permalink
Cache for oppgavesøk (#1789)
Browse files Browse the repository at this point in the history
- BeskyttelseType som en type i kø, som joines mot pepcache ved henting av kø.
- Oppdaterer pepcache ved alle inkomne behandlingprosesseventer for å få med tilkomne aktører.
- Endret pepcacheoppdaterer til å hente eldste av åpne og ventende oppgaver, og kun etter 23 timer. Mulig med så stort forsinkelse fordi endring i aktør på sak vil fanges opp fortløpende som følge av nytt behandligprosessevent.

- Sjekker antall kall mot pep for å verifisere at det gjøres ekstra tilgangssjekk for oppgaver som vises til saksbehandler.
  • Loading branch information
baskevold authored Dec 12, 2023
1 parent 3b4d289 commit 60a87c8
Show file tree
Hide file tree
Showing 24 changed files with 990 additions and 129 deletions.
7 changes: 6 additions & 1 deletion src/main/kotlin/no/nav/k9/los/K9Los.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import no.nav.k9.los.eventhandler.sjekkReserverteJobb
import no.nav.k9.los.integrasjon.datavarehus.StatistikkProducer
import no.nav.k9.los.integrasjon.kafka.AsynkronProsesseringV1Service
import no.nav.k9.los.integrasjon.sakogbehandling.SakOgBehandlingProducer
import no.nav.k9.los.nyoppgavestyring.pep.PepCacheOppdaterer
import no.nav.k9.los.nyoppgavestyring.ko.OppgaveKoApis
import no.nav.k9.los.nyoppgavestyring.domeneadaptere.k9.OmrådeSetup
import no.nav.k9.los.nyoppgavestyring.domeneadaptere.k9.klagetillos.K9KlageTilLosAdapterTjeneste
import no.nav.k9.los.nyoppgavestyring.domeneadaptere.k9.klagetillos.K9KlageTilLosApi
Expand Down Expand Up @@ -159,6 +161,8 @@ fun Application.k9Los() {
oppgaveKøRepository = koin.get()
)

PepCacheOppdaterer(koin.get()).start()

val sjekkReserverteJobb =
sjekkReserverteJobb(saksbehandlerRepository = koin.get(), reservasjonRepository = koin.get())

Expand Down Expand Up @@ -191,7 +195,8 @@ fun Application.k9Los() {
config = koin.get(),
transactionalManager = koin.get(),
oppgaveRepositoryV2 = koin.get(),
k9SakBerikerKlient = koin.get()
k9SakBerikerKlient = koin.get(),
pepCacheService = koin.get()
).kjør(kjørSetup = false, kjørUmiddelbart = false)

K9KlageTilLosAdapterTjeneste(
Expand Down
18 changes: 16 additions & 2 deletions src/main/kotlin/no/nav/k9/los/KoinProfiles.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import no.nav.k9.los.integrasjon.pdl.PdlService
import no.nav.k9.los.integrasjon.pdl.PdlServiceLocal
import no.nav.k9.los.integrasjon.rest.RequestContextService
import no.nav.k9.los.integrasjon.sakogbehandling.SakOgBehandlingProducer
import no.nav.k9.los.nyoppgavestyring.pep.PepCacheRepository
import no.nav.k9.los.nyoppgavestyring.ko.db.OppgaveKoRepository
import no.nav.k9.los.nyoppgavestyring.domeneadaptere.k9.OmrådeSetup
import no.nav.k9.los.nyoppgavestyring.domeneadaptere.k9.klagetillos.K9KlageTilLosAdapterTjeneste
Expand All @@ -45,7 +46,6 @@ import no.nav.k9.los.nyoppgavestyring.domeneadaptere.k9.saktillos.K9SakTilLosAda
import no.nav.k9.los.nyoppgavestyring.domeneadaptere.k9.statistikk.*
import no.nav.k9.los.nyoppgavestyring.domeneadaptere.k9.statistikk.StatistikkRepository
import no.nav.k9.los.nyoppgavestyring.domeneadaptere.k9klagetillos.K9KlageTilLosHistorikkvaskTjeneste
import no.nav.k9.los.nyoppgavestyring.domeneadaptere.k9saktillos.EventTilDtoMapper
import no.nav.k9.los.nyoppgavestyring.domeneadaptere.k9saktillos.K9SakTilLosHistorikkvaskTjeneste
import no.nav.k9.los.nyoppgavestyring.domeneadaptere.k9saktillos.K9SakTilLosLukkeFeiloppgaverTjeneste
import no.nav.k9.los.nyoppgavestyring.mottak.feltdefinisjon.FeltdefinisjonRepository
Expand All @@ -55,6 +55,7 @@ import no.nav.k9.los.nyoppgavestyring.mottak.oppgave.OppgaveV3Repository
import no.nav.k9.los.nyoppgavestyring.mottak.oppgave.OppgaveV3Tjeneste
import no.nav.k9.los.nyoppgavestyring.mottak.oppgavetype.OppgavetypeRepository
import no.nav.k9.los.nyoppgavestyring.mottak.oppgavetype.OppgavetypeTjeneste
import no.nav.k9.los.nyoppgavestyring.pep.PepCacheService
import no.nav.k9.los.nyoppgavestyring.query.OppgaveQueryService
import no.nav.k9.los.nyoppgavestyring.query.db.OppgaveQueryRepository
import no.nav.k9.los.nyoppgavestyring.visningoguttrekk.OppgaveRepository
Expand Down Expand Up @@ -399,6 +400,7 @@ fun common(app: Application, config: Configuration) = module {
oppgaveRepositoryV2 = get(),
transactionalManager = get(),
k9SakBerikerKlient = get(),
pepCacheService = get()
)
}

Expand Down Expand Up @@ -464,6 +466,19 @@ fun common(app: Application, config: Configuration) = module {
k9SakBerikerKlient = get(),
)
}

single {
PepCacheRepository(dataSource = get())
}

single {
PepCacheService(
pepClient = get(),
pepCacheRepository = get(),
oppgaveRepository = get(),
transactionalManager = get()
)
}
}

fun localDevConfig() = module {
Expand Down Expand Up @@ -555,6 +570,5 @@ fun prodConfig(config: Configuration) = module {
accessTokenClient = get<AccessTokenClientResolver>().naisSts()
)
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import no.nav.k9.los.domene.lager.oppgave.Oppgave
import no.nav.k9.los.integrasjon.audit.*
import no.nav.k9.los.integrasjon.azuregraph.IAzureGraphService
import no.nav.k9.los.integrasjon.rest.NavHeaders
import no.nav.k9.los.nyoppgavestyring.pep.PepCacheService
import no.nav.k9.los.utils.Cache
import no.nav.k9.los.utils.CacheObject
import org.slf4j.Logger
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import no.nav.k9.los.nyoppgavestyring.mottak.oppgave.OppgaveV3
import no.nav.k9.los.nyoppgavestyring.mottak.oppgave.OppgaveV3Tjeneste
import no.nav.k9.los.nyoppgavestyring.mottak.oppgavetype.OppgavetypeTjeneste
import no.nav.k9.los.nyoppgavestyring.mottak.oppgavetype.OppgavetyperDto
import no.nav.k9.los.nyoppgavestyring.pep.PepCacheService
import no.nav.k9.sak.kontrakt.produksjonsstyring.los.BehandlingMedFagsakDto
import org.slf4j.Logger
import org.slf4j.LoggerFactory
Expand All @@ -32,6 +33,7 @@ class K9SakTilLosAdapterTjeneste(
private val transactionalManager: TransactionalManager,
private val oppgaveRepositoryV2: OppgaveRepositoryV2,
private val k9SakBerikerKlient: K9SakBerikerInterfaceKludge,
private val pepCacheService: PepCacheService
) {

private val log: Logger = LoggerFactory.getLogger(K9SakTilLosAdapterTjeneste::class.java)
Expand Down Expand Up @@ -131,9 +133,9 @@ class K9SakTilLosAdapterTjeneste(

if (oppgave == null) {
sisteOppgaveDtoTilHastesakvask = oppgaveDto
}
} else {
pepCacheService.oppdater(tx, oppgave.kildeområde, oppgave.eksternId)

oppgave?.let {
eventTeller++
loggFremgangForHver100(eventTeller, "Prosessert $eventTeller eventer")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package no.nav.k9.los.nyoppgavestyring.kodeverk

import com.fasterxml.jackson.annotation.JsonCreator

enum class BeskyttelseType(val kode: String, val beskrivelse: String) {
KODE6("KODE6", "Kode 6"),
KODE7("KODE7", "Kode 7"),
ORDINÆR("ORDINÆR", "Vanlig");

companion object {
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
@JvmStatic
fun fraKode(kode: String): BeskyttelseType {
return BeskyttelseType.entries.find { it.kode == kode } ?: throw IllegalStateException("Kjenner ikke igjen koden=$kode")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package no.nav.k9.los.nyoppgavestyring.kodeverk

import com.fasterxml.jackson.annotation.JsonCreator


enum class EgenAnsatt(val kode: String, val beskrivelse: String) {
JA("JA", "Egen ansatt"),
NEI("NEI", "Ikke egen ansatt");

companion object {
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
@JvmStatic
fun fraKode(kode: String): EgenAnsatt {
return EgenAnsatt.entries.find { it.kode == kode } ?: throw IllegalStateException("Kjenner ikke igjen koden=$kode")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package no.nav.k9.los.nyoppgavestyring.pep

import no.nav.k9.los.domene.repository.OppgaveKøRepository
import org.slf4j.LoggerFactory
import java.time.Duration
import java.util.*
import kotlin.concurrent.timer

class PepCacheOppdaterer(
val pepCacheService: PepCacheService,
val tidMellomKjøring: Duration = Duration.ofSeconds(1),
val alderForOppfriskning: Duration = Duration.ofHours(23),
val forsinketOppstart: Duration = Duration.ofMinutes(5)
) {
private val TRÅDNAVN = "k9los-pepcache-oppdaterer"
private val log = LoggerFactory.getLogger(PepCacheOppdaterer::class.java)

fun start(): Timer {
return timer(
daemon = true,
name = TRÅDNAVN,
period = tidMellomKjøring.toMillis(),
initialDelay = forsinketOppstart.toMillis()
) {
try {
pepCacheService.oppdaterCacheForOppgaverEldreEnn(alderForOppfriskning)
} catch (e: Exception) {
log.warn("Feil ved kjøring av PepCacheOppdaterer", e)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package no.nav.k9.los.nyoppgavestyring.pep

import kotliquery.LoanPattern.using
import kotliquery.Row
import kotliquery.TransactionalSession
import kotliquery.queryOf
import kotliquery.sessionOf
import java.time.Duration
import java.time.LocalDateTime
import javax.sql.DataSource

class PepCacheRepository(
val dataSource: DataSource
) {

fun lagre(cache: PepCache, tx: TransactionalSession) {
tx.run(
queryOf("""
INSERT INTO OPPGAVE_PEP_CACHE (kildeomrade, ekstern_id, kode6, kode7, egen_ansatt, oppdatert)
VALUES(:kildeomrade, :ekstern_id, :kode6, :kode7, :egen_ansatt, :oppdatert)
ON CONFLICT ON CONSTRAINT pep_kildeomrade_eksternid
DO UPDATE SET
kildeomrade = :kildeomrade,
ekstern_id = :ekstern_id,
kode6 = :kode6,
kode7 = :kode7,
egen_ansatt = :egen_ansatt,
oppdatert = :oppdatert
""", mapOf(
"kildeomrade" to cache.kildeområde,
"ekstern_id" to cache.eksternId,
"kode6" to cache.kode6,
"kode7" to cache.kode7,
"egen_ansatt" to cache.egenAnsatt,
"oppdatert" to cache.oppdatert
)).asUpdate
)
}

fun slett(kildeområde: String, eksternId: String, tx: TransactionalSession) {
tx.run(
queryOf("""
DELETE FROM OPPGAVE_PEP_CACHE WHERE kildeomrade = :kildeomrade AND ekstern_id = :ekstern_id
""", mapOf(
"kildeomrade" to kildeområde,
"ekstern_id" to eksternId
)
).asUpdate
)
}

fun hent(kildeområde: String, eksternId: String): PepCache? {
return using(sessionOf(dataSource)) {
it.transaction { tx -> hent(kildeområde, eksternId, tx) }
}
}

fun hent(kildeområde: String, eksternId: String, tx: TransactionalSession): PepCache? {
return tx.run(
queryOf("""
SELECT * FROM OPPGAVE_PEP_CACHE WHERE kildeomrade = :kildeomrade AND ekstern_id = :ekstern_id
""", mapOf(
"kildeomrade" to kildeområde,
"ekstern_id" to eksternId
)
).map { it.tilPepCache() }.asSingle
)
}

private fun Row.tilPepCache() = PepCache(
kildeområde = string("kildeomrade"),
eksternId = string("ekstern_id"),
kode6 = boolean("kode6"),
kode7 = boolean("kode7"),
egenAnsatt = boolean("egen_ansatt"),
oppdatert = localDateTime("oppdatert"),
)
}


data class PepCache(
val eksternId: String,
val kildeområde: String,
val kode6: Boolean,
val kode7: Boolean,
val egenAnsatt: Boolean,
val oppdatert: LocalDateTime
) {
fun erGyldig(maksimalAlder: Duration): Boolean {
return oppdatert < (LocalDateTime.now() - maksimalAlder)
}

fun oppdater(kode6: Boolean, kode7: Boolean, egenAnsatt: Boolean): PepCache {
return copy(
kode6 = kode6,
kode7 = kode7,
egenAnsatt = egenAnsatt,
oppdatert = LocalDateTime.now()
)
}

fun måSjekkes(): Boolean {
return kode6 || kode7 || egenAnsatt
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package no.nav.k9.los.nyoppgavestyring.pep

import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.runBlocking
import kotliquery.TransactionalSession
import no.nav.k9.los.domene.lager.oppgave.v2.TransactionalManager
import no.nav.k9.los.integrasjon.abac.IPepClient
import no.nav.k9.los.nyoppgavestyring.visningoguttrekk.Oppgave
import no.nav.k9.los.nyoppgavestyring.visningoguttrekk.OppgaveRepository
import java.time.Duration
import java.time.LocalDateTime

class PepCacheService(
private val pepClient: IPepClient,
private val pepCacheRepository: PepCacheRepository,
private val oppgaveRepository: OppgaveRepository,
private val transactionalManager: TransactionalManager,
) {

suspend fun hentOgOppdaterVedBehov(tx: TransactionalSession, oppgave: Oppgave, maksimalAlder: Duration = Duration.ofMinutes(30)): PepCache {
return pepCacheRepository.hent(kildeområde = oppgave.kildeområde, eksternId = oppgave.eksternId, tx).let { pepCache ->
if (pepCache?.erGyldig(maksimalAlder) != true) {
oppdater(tx, oppgave)
} else {
pepCache
}
}
}

fun oppdaterCacheForOppgaverEldreEnn(gyldighet: Duration = Duration.ofHours(23)) {
transactionalManager.transaction { tx ->
runBlocking {
val oppgaverSomMåOppdateres = oppgaveRepository.hentÅpneOgVentendeOppgaverMedPepCacheEldreEnn(
tidspunkt = LocalDateTime.now() - gyldighet,
antall = 1,
tx
)
oppgaverSomMåOppdateres.forEach { oppgave -> oppdater(tx, oppgave) }
}
}
}

fun oppdater(tx: TransactionalSession, kildeområde: String, eksternId: String): PepCache {
return runBlocking {
val oppgave = oppgaveRepository.hentNyesteOppgaveForEksternId(
tx,
kildeområde = kildeområde,
eksternId = eksternId
)
oppdater(tx, oppgave)
}
}

suspend fun oppdater(tx: TransactionalSession, oppgave: Oppgave): PepCache {
return lagPepCacheFra(oppgave).also { nyPepCache -> pepCacheRepository.lagre(nyPepCache, tx) }
}

private suspend fun lagPepCacheFra(oppgave: Oppgave): PepCache {
val pep = PepCache(
eksternId = oppgave.eksternId,
kildeområde = oppgave.kildeområde,
kode6 = true,
kode7 = true,
egenAnsatt = true,
oppdatert = LocalDateTime.now()
)

val saksnummer = oppgave.hentVerdi(oppgave.kildeområde, "saksnummer")
?: throw IllegalStateException("Kan ikke gjøre oppslag uten saksnummer ${oppgave.eksternId}")

return pep.oppdater(saksnummer)
}

private suspend fun PepCache.oppdater(saksnummer: String): PepCache {
return coroutineScope {
val kode6Request = async {
pepClient.erSakKode6(fagsakNummer = saksnummer)
}
val kode7EllerEgenAnsattRequest = async {
pepClient.erSakKode7EllerEgenAnsatt(fagsakNummer = saksnummer)
}
val kode7EllerEgenAnsatt = kode7EllerEgenAnsattRequest.await()

val oppdatertPepCache = oppdater(
kode6 = kode6Request.await(),
kode7 = kode7EllerEgenAnsatt,
egenAnsatt = kode7EllerEgenAnsatt,
)
oppdatertPepCache
}
}
}

Loading

0 comments on commit 60a87c8

Please sign in to comment.