Skip to content

Commit

Permalink
Feil-behandler-app v1 (#377)
Browse files Browse the repository at this point in the history
* ny app: feil-behandler

* Legg til håndtering av bare bestemte typer feil, resten skal ignoreres
  • Loading branch information
mortenbyhring authored Dec 21, 2023
1 parent b5d91da commit 57564cf
Show file tree
Hide file tree
Showing 11 changed files with 286 additions and 0 deletions.
7 changes: 7 additions & 0 deletions config/feil-behandler/dev-gcp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
kafkaPool: nav-dev
azure:
enabled: true
database: im-error-recovery
envFrom:
- type: secret
name: google-sql-im-feil-behandler
7 changes: 7 additions & 0 deletions config/feil-behandler/prod-gcp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
kafkaPool: nav-prod
azure:
enabled: true
database: im-error-recovery
envFrom:
- type: secret
name: google-sql-im-feil-behandler
15 changes: 15 additions & 0 deletions feil-behandler/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
val exposedVersion: String by project
val flywayVersion: String by project
val hikariVersion: String by project
val postgresqlVersion: String by project
val testcontainersPostgresqlVersion: String by project

dependencies {
implementation("com.zaxxer:HikariCP:$hikariVersion")
implementation("org.flywaydb:flyway-core:$flywayVersion")
implementation("org.flywaydb:flyway-database-postgresql:$flywayVersion")

runtimeOnly("org.postgresql:postgresql:$postgresqlVersion")

testImplementation("org.testcontainers:postgresql:$testcontainersPostgresqlVersion")
}
5 changes: 5 additions & 0 deletions feil-behandler/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Dependency versions
flywayVersion=10.1.0
hikariVersion=5.1.0
postgresqlVersion=42.7.0
testcontainersPostgresqlVersion=1.19.3
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package no.nav.helsearbeidsgiver.inntektsmelding.feilbehandler

import com.zaxxer.hikari.HikariConfig
import no.nav.helse.rapids_rivers.RapidApplication
import no.nav.helse.rapids_rivers.RapidsConnection
import no.nav.helsearbeidsgiver.inntektsmelding.feilbehandler.config.Database
import no.nav.helsearbeidsgiver.inntektsmelding.feilbehandler.config.DatabaseConfig
import no.nav.helsearbeidsgiver.inntektsmelding.feilbehandler.config.mapHikariConfig
import no.nav.helsearbeidsgiver.inntektsmelding.feilbehandler.river.FeilLytter
import no.nav.helsearbeidsgiver.utils.log.logger
import no.nav.helsearbeidsgiver.utils.log.sikkerLogger

private val logger = "helsearbeidsgiver-im-feil-behandler".logger()
private val sikkerLogger = sikkerLogger()

fun main() {
buildApp(mapHikariConfig(DatabaseConfig()), System.getenv()).start()
}

fun buildApp(config: HikariConfig, env: Map<String, String>): RapidsConnection {
val database = Database(config)
sikkerLogger.info("Bruker database url: ${config.jdbcUrl}")
logger.info("Migrering starter...")
database.migrate()
logger.info("Migrering ferdig.")
return RapidApplication
.create(env)
.createFeilLytter(database)
}

fun RapidsConnection.createFeilLytter(database: Database): RapidsConnection =
also {
registerDbLifecycle(database)
FeilLytter(it)
}

private fun RapidsConnection.registerDbLifecycle(db: Database) {
register(object : RapidsConnection.StatusListener {
override fun onShutdown(rapidsConnection: RapidsConnection) {
logger.info("Mottatt stoppsignal, lukker databasetilkobling")
db.dataSource.close()
}
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package no.nav.helsearbeidsgiver.inntektsmelding.feilbehandler.config

import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import org.flywaydb.core.Flyway

class Database(
private val dbConfig: HikariConfig
) {
val dataSource by lazy { HikariDataSource(dbConfig) }
fun migrate() {
migrationConfig(dbConfig)
.let(::HikariDataSource)
.also {
Flyway.configure()
.dataSource(it)
.lockRetryCount(50)
.load()
.migrate()
}.close()
}
}

private fun migrationConfig(conf: HikariConfig): HikariConfig =
HikariConfig().apply {
jdbcUrl = conf.jdbcUrl
username = conf.username
password = conf.password
maximumPoolSize = 3
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package no.nav.helsearbeidsgiver.inntektsmelding.feilbehandler.config

import com.zaxxer.hikari.HikariConfig
import no.nav.helsearbeidsgiver.felles.fromEnv

private const val prefix = "NAIS_DATABASE_IM_FEIL_BEHANDLER_IM_ERROR_RECOVERY"

data class DatabaseConfig(
val host: String = "${prefix}_HOST".fromEnv(),
val port: String = "${prefix}_PORT".fromEnv(),
val name: String = "${prefix}_DATABASE".fromEnv(),
val username: String = "${prefix}_USERNAME".fromEnv(),
val password: String = "${prefix}_PASSWORD".fromEnv(),
val url: String = "jdbc:postgresql://%s:%s/%s".format(host, port, name)
)

fun mapHikariConfig(databaseConfig: DatabaseConfig): HikariConfig {
return HikariConfig().apply {
jdbcUrl = databaseConfig.url
username = databaseConfig.username
password = databaseConfig.password
maximumPoolSize = 5
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package no.nav.helsearbeidsgiver.inntektsmelding.feilbehandler.river

import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.serializer
import no.nav.helse.rapids_rivers.JsonMessage
import no.nav.helse.rapids_rivers.MessageContext
import no.nav.helse.rapids_rivers.RapidsConnection
import no.nav.helse.rapids_rivers.River
import no.nav.helsearbeidsgiver.felles.BehovType
import no.nav.helsearbeidsgiver.felles.Key
import no.nav.helsearbeidsgiver.felles.json.toMap
import no.nav.helsearbeidsgiver.felles.rapidsrivers.model.Fail
import no.nav.helsearbeidsgiver.felles.rapidsrivers.toPretty
import no.nav.helsearbeidsgiver.utils.json.fromJson
import no.nav.helsearbeidsgiver.utils.json.parseJson
import no.nav.helsearbeidsgiver.utils.log.sikkerLogger

class FeilLytter(rapidsConnection: RapidsConnection) : River.PacketListener {

private val sikkerLogger = sikkerLogger()
val behovSomHaandteres = listOf(
BehovType.LAGRE_FORESPOERSEL,
BehovType.OPPRETT_OPPGAVE,
BehovType.OPPRETT_SAK,
BehovType.PERSISTER_OPPGAVE_ID,
BehovType.PERSISTER_SAK_ID,
BehovType.JOURNALFOER,
BehovType.LAGRE_JOURNALPOST_ID,
BehovType.NOTIFIKASJON_HENT_ID
)

init {
sikkerLogger.info("Starter applikasjon - lytter på innkommende feil!")
River(rapidsConnection).apply {
validate { msg ->
msg.demandKey(Key.FAIL.str)
}
}
.register(this)
}

override fun onPacket(packet: JsonMessage, context: MessageContext) {
sikkerLogger.info("Mottok feil: ${packet.toPretty()}")
val fail = toFailOrNull(packet.toJson().parseJson())
if (fail == null) {
sikkerLogger.warn("Kunne ikke parse feil-objekt, ignorerer...")
} else if (skalHaandteres(fail)) {
sikkerLogger.info("Behandler feil")
} else {
sikkerLogger.info("Ignorerer feil")
}
}

fun skalHaandteres(fail: Fail): Boolean {
if (fail.forespoerselId == null) {
return false
}
val behovFraMelding = fail.utloesendeMelding.toMap()[Key.BEHOV]?.fromJson(BehovType.serializer())
return behovSomHaandteres.contains(behovFraMelding)
}

fun toFailOrNull(json: JsonElement): Fail? = // TODO: duplisert, lage felles metode?
json.toMap()[Key.FAIL]
?.runCatching {
fromJson(Fail.serializer())
}
?.getOrNull()
}
12 changes: 12 additions & 0 deletions feil-behandler/src/main/resources/db/migration/V1___tilganger.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
DO
$$
BEGIN
IF EXISTS (SELECT 1
FROM pg_roles
WHERE rolname = 'cloudsqliamuser')
THEN
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO cloudsqliamuser;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO cloudsqliamuser;
END IF;
END
$$;
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
create table bakgrunnsjobb
(
jobb_id uuid unique not null,
type text not null,
behandlet timestamp,
opprettet timestamp not null,

status text not null,
kjoeretid timestamp not null,

forsoek int not null default 0,
maks_forsoek int not null,
data jsonb
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package no.nav.helsearbeidsgiver.inntektsmelding.feilbehandler.river

import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import no.nav.helse.rapids_rivers.JsonMessage
import no.nav.helse.rapids_rivers.testsupport.TestRapid
import no.nav.helsearbeidsgiver.felles.BehovType
import no.nav.helsearbeidsgiver.felles.EventName
import no.nav.helsearbeidsgiver.felles.Key
import no.nav.helsearbeidsgiver.felles.rapidsrivers.model.Fail
import no.nav.helsearbeidsgiver.felles.utils.mapOfNotNull
import no.nav.helsearbeidsgiver.utils.json.parseJson
import java.util.UUID

class FeilLytterTest : FunSpec({

val handler = FeilLytter(TestRapid())

test("skal håndtere gyldige feil med spesifiserte behov") {

handler.behovSomHaandteres.forEach { handler.skalHaandteres(lagGyldigFeil(it)) shouldBe true }
}

test("skal ignorere gyldige feil med visse behov") {
val ignorerteBehov = BehovType.entries.filterNot { handler.behovSomHaandteres.contains(it) }
ignorerteBehov.forEach { handler.skalHaandteres(lagGyldigFeil(it)) shouldBe false }
}

test("skal ignorere feil uten behov") {
val uuid = UUID.randomUUID()
val feil = lagGyldigFeil(BehovType.JOURNALFOER).copy(
utloesendeMelding =
JsonMessage.newMessage(
mapOfNotNull(
Key.UUID.str to uuid,
Key.FORESPOERSEL_ID.str to uuid
)
).toJson().parseJson()
)
handler.skalHaandteres(feil) shouldBe false
}

test("skal ignorere feil uten forespørselId") {
val feil = lagGyldigFeil(BehovType.JOURNALFOER).copy(forespoerselId = null)
handler.skalHaandteres(feil) shouldBe false
}
})

fun lagGyldigFeil(behov: BehovType): Fail {
val uuid = UUID.randomUUID()
val jsonMessage = JsonMessage.newMessage(
EventName.OPPGAVE_OPPRETT_REQUESTED.name,
mapOfNotNull(
Key.BEHOV.str to behov,
Key.UUID.str to uuid,
Key.FORESPOERSEL_ID.str to uuid
)
)
return Fail("Feil", EventName.OPPGAVE_OPPRETT_REQUESTED, UUID.randomUUID(), UUID.randomUUID(), jsonMessage.toJson().parseJson())
}

0 comments on commit 57564cf

Please sign in to comment.