Skip to content

Commit

Permalink
Oppdaterte kafka streams tilstands klassen til bekreftelse-tjeneste
Browse files Browse the repository at this point in the history
  • Loading branch information
nilsmsa committed Oct 9, 2024
1 parent 2826440 commit 5172ab3
Show file tree
Hide file tree
Showing 21 changed files with 413 additions and 316 deletions.
2 changes: 1 addition & 1 deletion apps/bekreftelse-min-side-oppgaver/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ dependencies {
implementation(project(":domain:main-avro-schema"))
implementation(libs.jackson.datatypeJsr310)
implementation(libs.jackson.kotlin)
implementation(libs.arrowCore)
implementation(libs.arrow.core.core)
implementation(libs.hoplite.yaml)
implementation(libs.nav.common.log)
implementation(libs.logbackClassic)
Expand Down
2 changes: 1 addition & 1 deletion apps/bekreftelse-tjeneste/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ dependencies {
implementation(libs.jackson.datatypeJsr310)

// Tooling
implementation(libs.arrowCore)
implementation(libs.arrow.core.core)

// Logging
implementation(libs.logbackClassic)
Expand Down
2 changes: 1 addition & 1 deletion apps/bekreftelse-tjeneste/nais/nais-dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ spec:
port: 8080
env:
- name: KAFKA_STREAMS_ID_SUFFIX
value: "v2"
value: "v3"
- name: KAFKA_PAW_ARBEIDSSOKER_BEKREFTELSE_TOPIC
value: "paw.arbeidssoker-bekreftelse-beta-v1"
- name: KAFKA_PAW_ARBEIDSSOKER_BEKREFTELSE_HENDELSELOGG_TOPIC
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package no.nav.paw.bekreftelsetjeneste.tilstand

import arrow.core.NonEmptyList
import java.time.Duration
import java.time.Instant
import java.util.*

@JvmRecord
data class Bekreftelse(
val tilstandsLogg: BekreftelseTilstandsLogg,
val bekreftelseId: UUID,
val gjelderFra: Instant,
val gjelderTil: Instant
)

inline fun <reified T: BekreftelseTilstand> Bekreftelse.tilstand(): T? = tilstandsLogg.get()

inline fun <reified T: BekreftelseTilstand> Bekreftelse.has(): Boolean = tilstand<T>() != null

fun Bekreftelse.sisteTilstand(): BekreftelseTilstand = tilstandsLogg.siste

operator fun Bekreftelse.plus(bekreftelseTilstand: BekreftelseTilstand): Bekreftelse =
copy(tilstandsLogg = tilstandsLogg + bekreftelseTilstand)

fun opprettFoersteBekreftelse(
periode: PeriodeInfo,
interval: Duration,
): Bekreftelse =
Bekreftelse(
BekreftelseTilstandsLogg(IkkeKlarForUtfylling(periode.startet), emptyList()),
bekreftelseId = UUID.randomUUID(),
gjelderFra = periode.startet,
gjelderTil = fristForNesteBekreftelse(periode.startet, interval)
)


fun NonEmptyList<Bekreftelse>.opprettNesteTilgjengeligeBekreftelse(
tilgjengeliggjort: Instant,
interval: Duration
): Bekreftelse {
val sisteBekreftelse = maxBy { it.gjelderTil }
return Bekreftelse(
bekreftelseId = UUID.randomUUID(),
gjelderFra = sisteBekreftelse.gjelderTil,
gjelderTil = fristForNesteBekreftelse(sisteBekreftelse.gjelderTil, interval),
tilstandsLogg = BekreftelseTilstandsLogg(
siste = KlarForUtfylling(tilgjengeliggjort),
tidligere = emptyList()
)
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package no.nav.paw.bekreftelsetjeneste.tilstand

import com.fasterxml.jackson.annotation.JsonSubTypes
import com.fasterxml.jackson.annotation.JsonTypeInfo
import java.time.Instant

@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type"
)
@JsonSubTypes(
JsonSubTypes.Type(value = IkkeKlarForUtfylling::class, name = "IkkeKlarForUtfylling"),
JsonSubTypes.Type(value = KlarForUtfylling::class, name = "KlarForUtfylling"),
JsonSubTypes.Type(value = VenterSvar::class, name = "VenterSvar"),
JsonSubTypes.Type(value = GracePeriodeUtloept::class, name = "GracePeriodeUtloept"),
JsonSubTypes.Type(value = Levert::class, name = "Levert")
)
sealed interface BekreftelseTilstand {
val timestamp: Instant
}

data class GracePeriodeUtloept(override val timestamp: Instant) : BekreftelseTilstand
data class GracePeriodeVarselet(override val timestamp: Instant) : BekreftelseTilstand
data class IkkeKlarForUtfylling(override val timestamp: Instant) : BekreftelseTilstand
data class KlarForUtfylling(override val timestamp: Instant) : BekreftelseTilstand
data class Levert(override val timestamp: Instant) : BekreftelseTilstand
data class VenterSvar(override val timestamp: Instant) : BekreftelseTilstand
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package no.nav.paw.bekreftelsetjeneste.tilstand

import arrow.core.NonEmptyList
import arrow.core.nonEmptyListOf
import org.slf4j.LoggerFactory

@JvmRecord
data class BekreftelseTilstandsLogg(
val siste: BekreftelseTilstand,
val tidligere: List<BekreftelseTilstand>
)

private val bekreftelseTilstandsLoggProblemerLogger = LoggerFactory.getLogger(BekreftelseTilstandsLogg::class.java)
operator fun BekreftelseTilstandsLogg.plus(bekreftelseTilstand: BekreftelseTilstand): BekreftelseTilstandsLogg =
(tidligere + siste + bekreftelseTilstand)
.groupBy { it::class }
.values
.map { gruppe ->
if (gruppe.size == 1) gruppe.first()
else {
bekreftelseTilstandsLoggProblemerLogger.warn("Flere tilstander av samme type i tilstandslogg: $gruppe, beholder den nyeste")
gruppe.maxBy { it.timestamp }
}
}
.let { alle ->
val siste = alle.maxBy { it.timestamp }
val tidligere = alle.filterNot { it == siste }.sortedBy { it.timestamp }
BekreftelseTilstandsLogg(siste, tidligere)
}

inline fun <reified T : BekreftelseTilstand> BekreftelseTilstandsLogg.get(): T? =
tidligere.filterIsInstance<T>().firstOrNull() ?: siste as? T

fun BekreftelseTilstandsLogg.asList(): NonEmptyList<BekreftelseTilstand> = nonEmptyListOf(siste) + tidligere
Original file line number Diff line number Diff line change
@@ -1,62 +1,13 @@
package no.nav.paw.bekreftelsetjeneste.tilstand

import com.fasterxml.jackson.annotation.JsonSubTypes
import com.fasterxml.jackson.annotation.JsonTypeInfo
import no.nav.paw.arbeidssokerregisteret.api.v1.Periode
import java.time.Duration
import java.time.Instant
import java.util.*

@JvmRecord
data class InternTilstand(
val periode: PeriodeInfo,
val bekreftelser: List<Bekreftelse>
)

@JvmRecord
data class Bekreftelse(
val tilstand: Tilstand,
val tilgjengeliggjort: Instant?,
val fristUtloept: Instant?,
val sisteVarselOmGjenstaaendeGraceTid: Instant?,
val bekreftelseId: UUID,
val gjelderFra: Instant,
val gjelderTil: Instant
)

@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type"
)
@JsonSubTypes(
JsonSubTypes.Type(value = Tilstand.IkkeKlarForUtfylling::class, name = "IkkeKlarForUtfylling"),
JsonSubTypes.Type(value = Tilstand.KlarForUtfylling::class, name = "KlarForUtfylling"),
JsonSubTypes.Type(value = Tilstand.VenterSvar::class, name = "VenterSvar"),
JsonSubTypes.Type(value = Tilstand.GracePeriodeUtloept::class, name = "GracePeriodeUtloept"),
JsonSubTypes.Type(value = Tilstand.Levert::class, name = "Levert")
)
sealed class Tilstand {
data object IkkeKlarForUtfylling : Tilstand()
data object KlarForUtfylling : Tilstand()
data object VenterSvar : Tilstand()
data object GracePeriodeUtloept : Tilstand()
data object Levert : Tilstand()
}

@JvmRecord
data class PeriodeInfo(
val periodeId: UUID,
val identitetsnummer: String,
val arbeidsoekerId: Long,
val recordKey: Long,
val startet: Instant,
val avsluttet: Instant?
) {
val erAvsluttet: Boolean
get() = avsluttet != null
}

fun initTilstand(
id: Long,
key: Long,
Expand All @@ -73,33 +24,3 @@ fun initTilstand(
),
bekreftelser = emptyList()
)

fun initBekreftelsePeriode(
periode: PeriodeInfo,
interval: Duration,
): Bekreftelse =
Bekreftelse(
tilstand = Tilstand.IkkeKlarForUtfylling,
tilgjengeliggjort = null,
fristUtloept = null,
sisteVarselOmGjenstaaendeGraceTid = null,
bekreftelseId = UUID.randomUUID(),
gjelderFra = periode.startet,
gjelderTil = fristForNesteBekreftelse(periode.startet, interval)
)

fun List<Bekreftelse>.initNewBekreftelse(
tilgjengeliggjort: Instant,
interval: Duration
): Bekreftelse {
val sisteBekreftelse = maxBy { it.gjelderTil }

return sisteBekreftelse.copy(
tilstand = Tilstand.KlarForUtfylling,
tilgjengeliggjort = tilgjengeliggjort,
sisteVarselOmGjenstaaendeGraceTid = null,
bekreftelseId = UUID.randomUUID(),
gjelderFra = sisteBekreftelse.gjelderTil,
gjelderTil = fristForNesteBekreftelse(sisteBekreftelse.gjelderTil, interval)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,53 @@ import java.time.Instant
const val MAKS_ANTALL_UTSTEENDE_BEKREFTELSER: Int = 100
private val maksAntallLogger = LoggerFactory.getLogger("maksAntallLogger")
fun Bekreftelse.erKlarForUtfylling(now: Instant, tilgjengeligOffset: Duration): Boolean =
now.isAfter(gjelderTil.minus(tilgjengeligOffset))
when (sisteTilstand()) {
is IkkeKlarForUtfylling -> now.isAfter(gjelderTil.minus(tilgjengeligOffset))
else -> false
}


fun Bekreftelse.harFristUtloept(now: Instant, tilgjengeligOffset: Duration): Boolean =
now.isAfter(tilgjengeliggjort?.plus(tilgjengeligOffset) ?: gjelderTil)
when (val gjeldeneTilstand = sisteTilstand()) {
is KlarForUtfylling -> now.isAfter(gjeldeneTilstand.timestamp.plus(tilgjengeligOffset))
else -> false
}


fun Bekreftelse.erSisteVarselOmGjenstaaendeGraceTid(now: Instant, varselFoerGraceperiodeUtloept: Duration): Boolean =
sisteVarselOmGjenstaaendeGraceTid == null && now.isAfter(fristUtloept?.plus(varselFoerGraceperiodeUtloept) ?: gjelderTil.plus(
varselFoerGraceperiodeUtloept
))
when (val gjeldeneTilstand = sisteTilstand()) {
is VenterSvar -> !has<GracePeriodeVarselet>() && now.isAfter(
gjeldeneTilstand.timestamp.plus(
varselFoerGraceperiodeUtloept
)
)

fun Bekreftelse.harGraceperiodeUtloept(now: Instant, graceperiode: Duration): Boolean =
now.isAfter(fristUtloept?.plus(graceperiode) ?: gjelderTil.plus(graceperiode))
else -> false
}

fun NonEmptyList<Bekreftelse>.shouldCreateNewBekreftelse(now: Instant, interval: Duration, tilgjengeligOffset: Duration): Boolean =
fun Bekreftelse.harGraceperiodeUtloept(now: Instant, graceperiode: Duration): Boolean =
when (val gjeldeneTilstand = sisteTilstand()) {
is VenterSvar -> now.isAfter(gjeldeneTilstand.timestamp.plus(graceperiode))
is GracePeriodeVarselet -> tilstandsLogg.get<VenterSvar>()?.timestamp?.let { ts -> now.isAfter(ts.plus(graceperiode)) } ?: false
else -> false
}


fun NonEmptyList<Bekreftelse>.shouldCreateNewBekreftelse(
now: Instant,
interval: Duration,
tilgjengeligOffset: Duration
): Boolean =
(size < MAKS_ANTALL_UTSTEENDE_BEKREFTELSER)
.also { underGrense ->
if (!underGrense) {
maksAntallLogger.warn("Maks antall bekreftelser er nådd!")
}
} &&
maxBy { it.gjelderTil }
.let {
now.isAfter(it.gjelderTil.plus(interval.minus(tilgjengeligOffset)))
}
maxBy { it.gjelderTil }
.let {
now.isAfter(it.gjelderTil.plus(interval.minus(tilgjengeligOffset)))
}



Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package no.nav.paw.bekreftelsetjeneste.tilstand

import java.time.Instant
import java.util.*

@JvmRecord
data class PeriodeInfo(
val periodeId: UUID,
val identitetsnummer: String,
val arbeidsoekerId: Long,
val recordKey: Long,
val startet: Instant,
val avsluttet: Instant?
) {
val erAvsluttet: Boolean
get() = avsluttet != null
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fun fristForNesteBekreftelse(forrige: Instant, interval: Duration): Instant {
}

fun Bekreftelse.gjenstaendeGraceperiode(timestamp: Instant, graceperiode: Duration): Duration {
val utvidetGjelderTil = fristUtloept?.plus(graceperiode) ?: gjelderTil.plus(graceperiode)
val utvidetGjelderTil = tilstand<VenterSvar>()?.timestamp?.plus(graceperiode) ?: gjelderTil.plus(graceperiode)

return if (timestamp.isAfter(utvidetGjelderTil)) {
Duration.ZERO
Expand Down
Loading

0 comments on commit 5172ab3

Please sign in to comment.