From 82027c122b4127c44201a48da251a76397d1f157 Mon Sep 17 00:00:00 2001 From: Andreas Date: Mon, 24 Jul 2023 11:31:26 +0200 Subject: [PATCH] remove service that updates statuses (#143) * remove service that updates statuses * remove more stuff --- naiserator-dev.yaml | 1 - naiserator-prod.yaml | 1 - src/main/kotlin/no/nav/syfo/Bootstrap.kt | 14 +-- src/main/kotlin/no/nav/syfo/Environment.kt | 1 - .../nav/syfo/application/ApplicationServer.kt | 3 - .../no/nav/syfo/elector/LeaderElector.kt | 35 ------- .../no/nav/syfo/elector/LeadershipHandling.kt | 78 ---------------- .../oppgave/service/UpdateStatusService.kt | 92 ------------------- .../no/nav/syfo/api/AuthenticateTest.kt | 1 - .../syfo/elector/LeadershipHandlingTest.kt | 49 ---------- .../service/UpdateStatusServiceDbTest.kt | 43 --------- .../service/UpdateStatusServiceTest.kt | 51 ---------- 12 files changed, 2 insertions(+), 367 deletions(-) delete mode 100644 src/main/kotlin/no/nav/syfo/elector/LeaderElector.kt delete mode 100644 src/main/kotlin/no/nav/syfo/elector/LeadershipHandling.kt delete mode 100644 src/main/kotlin/no/nav/syfo/oppgave/service/UpdateStatusService.kt delete mode 100644 src/test/kotlin/no/nav/syfo/elector/LeadershipHandlingTest.kt delete mode 100644 src/test/kotlin/no/nav/syfo/oppgave/service/UpdateStatusServiceDbTest.kt delete mode 100644 src/test/kotlin/no/nav/syfo/oppgave/service/UpdateStatusServiceTest.kt diff --git a/naiserator-dev.yaml b/naiserator-dev.yaml index 4a198089..a1680cbc 100644 --- a/naiserator-dev.yaml +++ b/naiserator-dev.yaml @@ -6,7 +6,6 @@ metadata: labels: team: teamsykmelding spec: - leaderElection: true gcp: sqlInstances: - name: syfosmmanuell-backend-instance diff --git a/naiserator-prod.yaml b/naiserator-prod.yaml index 18553016..bd22738d 100644 --- a/naiserator-prod.yaml +++ b/naiserator-prod.yaml @@ -6,7 +6,6 @@ metadata: labels: team: teamsykmelding spec: - leaderElection: true gcp: sqlInstances: - name: syfosmmanuell-backend-instance diff --git a/src/main/kotlin/no/nav/syfo/Bootstrap.kt b/src/main/kotlin/no/nav/syfo/Bootstrap.kt index a34665fc..96e24329 100644 --- a/src/main/kotlin/no/nav/syfo/Bootstrap.kt +++ b/src/main/kotlin/no/nav/syfo/Bootstrap.kt @@ -21,11 +21,8 @@ import no.nav.syfo.clients.HttpClients import no.nav.syfo.clients.KafkaConsumers import no.nav.syfo.clients.KafkaProducers import no.nav.syfo.db.Database -import no.nav.syfo.elector.LeaderElector -import no.nav.syfo.elector.LeadershipHandling import no.nav.syfo.oppgave.kafka.OppgaveHendelseConsumer import no.nav.syfo.oppgave.service.OppgaveService -import no.nav.syfo.oppgave.service.UpdateStatusService import no.nav.syfo.persistering.MottattSykmeldingService import no.nav.syfo.service.ManuellOppgaveService import no.nav.syfo.util.TrackableException @@ -109,15 +106,8 @@ fun main() { createListener(applicationState) { oppgaveHendelseConsumer.start() } - val leaderElectorService = LeadershipHandling( - updateService = UpdateStatusService( - database = database, - oppgaveClient = httpClients.oppgaveClient, - ), - LeaderElector(httpClient = httpClients.httpClient, env.electorPath), - ) - leaderElectorService.start() - ApplicationServer(applicationEngine, applicationState, leaderElectorService).start() + + ApplicationServer(applicationEngine, applicationState).start() } @DelicateCoroutinesApi diff --git a/src/main/kotlin/no/nav/syfo/Environment.kt b/src/main/kotlin/no/nav/syfo/Environment.kt index 429024c5..3375b8f8 100644 --- a/src/main/kotlin/no/nav/syfo/Environment.kt +++ b/src/main/kotlin/no/nav/syfo/Environment.kt @@ -26,7 +26,6 @@ data class Environment( val dbName: String = getEnvVar("DB_DATABASE"), val cluster: String = getEnvVar("NAIS_CLUSTER_NAME"), val oppgaveHendelseTopic: String = getEnvVar("OPPGAVE_HENDELSE_TOPIC"), - val electorPath: String = getEnvVar("ELECTOR_PATH"), ) fun getEnvVar(varName: String, defaultValue: String? = null) = diff --git a/src/main/kotlin/no/nav/syfo/application/ApplicationServer.kt b/src/main/kotlin/no/nav/syfo/application/ApplicationServer.kt index 76080e64..72c97a7b 100644 --- a/src/main/kotlin/no/nav/syfo/application/ApplicationServer.kt +++ b/src/main/kotlin/no/nav/syfo/application/ApplicationServer.kt @@ -1,20 +1,17 @@ package no.nav.syfo.application import io.ktor.server.engine.ApplicationEngine -import no.nav.syfo.elector.LeadershipHandling import java.util.concurrent.TimeUnit class ApplicationServer( private val applicationServer: ApplicationEngine, private val applicationState: ApplicationState, - private val leaderElectorService: LeadershipHandling, ) { init { Runtime.getRuntime().addShutdownHook( Thread { this.applicationState.ready = false - leaderElectorService.stop() this.applicationServer.stop(TimeUnit.SECONDS.toMillis(10), TimeUnit.SECONDS.toMillis(10)) }, ) diff --git a/src/main/kotlin/no/nav/syfo/elector/LeaderElector.kt b/src/main/kotlin/no/nav/syfo/elector/LeaderElector.kt deleted file mode 100644 index ab0c4b25..00000000 --- a/src/main/kotlin/no/nav/syfo/elector/LeaderElector.kt +++ /dev/null @@ -1,35 +0,0 @@ -package no.nav.syfo.elector - -import io.ktor.client.HttpClient -import io.ktor.client.call.body -import io.ktor.client.request.get -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import no.nav.syfo.log -import java.net.InetAddress - -class LeaderElector( - private val httpClient: HttpClient, - private val electorPath: String, -) { - suspend fun isLeader(): Boolean { - val hostname: String = withContext(Dispatchers.IO) { InetAddress.getLocalHost() }.hostName - - return try { - val leader = httpClient.get(getHttpPath(electorPath)).body() - leader.name == hostname - } catch (e: Exception) { - val message = "Kall mot elector feiler" - log.warn(message) - false - } - } - - private fun getHttpPath(url: String): String = - when (url.startsWith("http://")) { - true -> url - else -> "http://$url" - } - - private data class Leader(val name: String) -} diff --git a/src/main/kotlin/no/nav/syfo/elector/LeadershipHandling.kt b/src/main/kotlin/no/nav/syfo/elector/LeadershipHandling.kt deleted file mode 100644 index 8645ea8c..00000000 --- a/src/main/kotlin/no/nav/syfo/elector/LeadershipHandling.kt +++ /dev/null @@ -1,78 +0,0 @@ -package no.nav.syfo.elector - -import io.ktor.utils.io.CancellationException -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.cancel -import kotlinx.coroutines.delay -import kotlinx.coroutines.isActive -import kotlinx.coroutines.launch -import no.nav.syfo.service.UpdateService -import org.slf4j.LoggerFactory -import kotlin.time.Duration.Companion.seconds - -class LeadershipHandling( - private val updateService: UpdateService, - private val leaderElector: LeaderElector, - private val scope: CoroutineScope = CoroutineScope(Dispatchers.IO), -) { - private val logger = LoggerFactory.getLogger(LeadershipHandling::class.java) - private var isLeaderPreviously = false - - fun start() { - logger.info("Starting LeaderElectorService") - scope.launch { - while (isActive) { - try { - handleLeadership() - delay(5.seconds) - } catch (ex: Exception) { - when (ex) { - is CancellationException -> { - logger.warn("Job was cancelled, message: ${ex.message}") - throw ex - } - else -> { - logger.error("Error occurred in leadership handling loop delaying for 10 seconds", ex) - delay(10.seconds) - } - } - } - } - - if (isLeaderPreviously) { - logger.info("Not active, stopping") - updateService.stop() - } - } - } - - private suspend fun handleLeadership() { - var isLeaderNow = leaderElector.isLeader() - - if (isLeaderNow && !isLeaderPreviously) { - logger.info("Is leader, delay for 10 seconds") - delay(10.seconds) - isLeaderNow = leaderElector.isLeader() - - if (isLeaderNow) { - logger.info("Is still leader, starting service") - updateService.start() - } else { - logger.info("Is not leader after delay") - } - } - - if (!isLeaderNow && isLeaderPreviously) { - logger.info("Is not leader, stopping") - updateService.stop() - } - - isLeaderPreviously = isLeaderNow - } - - fun stop() { - logger.info("Shutting down LeadershipHandling") - scope.cancel() - } -} diff --git a/src/main/kotlin/no/nav/syfo/oppgave/service/UpdateStatusService.kt b/src/main/kotlin/no/nav/syfo/oppgave/service/UpdateStatusService.kt deleted file mode 100644 index 9860e81b..00000000 --- a/src/main/kotlin/no/nav/syfo/oppgave/service/UpdateStatusService.kt +++ /dev/null @@ -1,92 +0,0 @@ -package no.nav.syfo.oppgave.service - -import kotlinx.coroutines.CancellationException -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.cancelAndJoin -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.delay -import kotlinx.coroutines.isActive -import kotlinx.coroutines.joinAll -import kotlinx.coroutines.launch -import no.nav.syfo.db.DatabaseInterface -import no.nav.syfo.model.ManuellOppgaveStatus -import no.nav.syfo.oppgave.client.OppgaveClient -import no.nav.syfo.persistering.db.getOppgaveWithNullStatus -import no.nav.syfo.persistering.db.oppdaterOppgaveHendelse -import no.nav.syfo.service.UpdateService -import org.slf4j.LoggerFactory -import java.time.LocalDateTime -import kotlin.time.Duration.Companion.seconds - -class UpdateStatusService( - private val database: DatabaseInterface, - private val oppgaveClient: OppgaveClient, -) : UpdateService { - - private var updateJob: Job? = null - private val limit = 10 - private val logger = LoggerFactory.getLogger(UpdateStatusService::class.java) - - companion object { - private val statusMap = mapOf( - "FERDIGSTILT" to ManuellOppgaveStatus.FERDIGSTILT, - "FEILREGISTRERT" to ManuellOppgaveStatus.FEILREGISTRERT, - null to ManuellOppgaveStatus.DELETED, - ) - } - - override suspend fun start() = coroutineScope { - if (updateJob?.isActive != true) { - updateJob = launch(Dispatchers.IO) { - while (isActive) { - try { - val oppgaveList = database.getOppgaveWithNullStatus(limit) - - if (oppgaveList.isEmpty()) break - - val jobs = oppgaveList.map { (oppgaveId, id) -> - launch(Dispatchers.IO) { - processOppgave(oppgaveId, id) - } - } - jobs.joinAll() - } catch (ex: Exception) { - when (ex) { - is CancellationException -> { - logger.warn("Job was cancelled, message: ${ex.message}") - throw ex - } - else -> { - logger.error("Caught unexpected delaying for 10s $ex") - delay(10.seconds) - } - } - } - } - } - } - } - - private suspend fun processOppgave(oppgaveId: Int, id: String) { - try { - val oppgave = oppgaveClient.hentOppgave(oppgaveId, id) - if (oppgave == null) { - logger.warn("Could not find oppgave for oppgaveId $oppgaveId") - } - - database.oppdaterOppgaveHendelse( - oppgaveId = oppgaveId, - status = statusMap[oppgave?.status] ?: ManuellOppgaveStatus.APEN, - statusTimestamp = oppgave?.endretTidspunkt?.toLocalDateTime() ?: LocalDateTime.now(), - ) - } catch (ex: Exception) { - logger.error("Caught $ex for oppgaveId $oppgaveId") - } - } - - override suspend fun stop() { - updateJob?.cancelAndJoin() - updateJob = null - } -} diff --git a/src/test/kotlin/no/nav/syfo/api/AuthenticateTest.kt b/src/test/kotlin/no/nav/syfo/api/AuthenticateTest.kt index d42cfe53..eec47d50 100644 --- a/src/test/kotlin/no/nav/syfo/api/AuthenticateTest.kt +++ b/src/test/kotlin/no/nav/syfo/api/AuthenticateTest.kt @@ -102,7 +102,6 @@ class AuthenticateTest : FunSpec({ dbPort = "", cluster = "dev-gcp", oppgaveHendelseTopic = "oppgavehendlese", - electorPath = "Electorpath", ) with(TestApplicationEngine()) { start() diff --git a/src/test/kotlin/no/nav/syfo/elector/LeadershipHandlingTest.kt b/src/test/kotlin/no/nav/syfo/elector/LeadershipHandlingTest.kt deleted file mode 100644 index ab79e542..00000000 --- a/src/test/kotlin/no/nav/syfo/elector/LeadershipHandlingTest.kt +++ /dev/null @@ -1,49 +0,0 @@ -package no.nav.syfo.elector - -import io.kotest.core.spec.style.StringSpec -import io.mockk.coEvery -import io.mockk.coVerify -import io.mockk.mockk -import io.mockk.unmockkAll -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.TestScope -import kotlinx.coroutines.test.advanceTimeBy -import kotlinx.coroutines.test.runTest -import no.nav.syfo.service.UpdateService -import kotlin.time.Duration.Companion.seconds - -@OptIn(ExperimentalCoroutinesApi::class) -class LeadershipHandlingTest : StringSpec({ - var isLeader = true - val updateService = mockk(relaxed = true) - val leaderElector = mockk { - coEvery { isLeader() } answers { isLeader } - } - - "should star and stop" { - val leadershipHandling = LeadershipHandling(updateService, leaderElector) - leadershipHandling.start() - leadershipHandling.stop() - } - - "should start service when elected as leader" { - val scope = TestScope() - runTest { - val leadershipHandling = LeadershipHandling(updateService, leaderElector, scope) - leadershipHandling.start() - - scope.advanceTimeBy(11.seconds) - coVerify(exactly = 1) { updateService.start() } - - isLeader = false - scope.advanceTimeBy(6.seconds) - coVerify(exactly = 1) { updateService.stop() } - - leadershipHandling.stop() - } - } - - afterTest { // Clean up after every test - unmockkAll() - } -}) diff --git a/src/test/kotlin/no/nav/syfo/oppgave/service/UpdateStatusServiceDbTest.kt b/src/test/kotlin/no/nav/syfo/oppgave/service/UpdateStatusServiceDbTest.kt deleted file mode 100644 index a3960c90..00000000 --- a/src/test/kotlin/no/nav/syfo/oppgave/service/UpdateStatusServiceDbTest.kt +++ /dev/null @@ -1,43 +0,0 @@ -package no.nav.syfo.oppgave.service - -import io.kotest.core.spec.style.FunSpec -import io.mockk.coEvery -import io.mockk.mockk -import io.mockk.mockkStatic -import no.nav.syfo.db.DatabaseInterface -import no.nav.syfo.model.ManuellOppgave -import no.nav.syfo.model.ManuellOppgaveStatus -import no.nav.syfo.model.Status -import no.nav.syfo.model.ValidationResult -import no.nav.syfo.oppgave.client.OppgaveClient -import no.nav.syfo.persistering.db.opprettManuellOppgave -import no.nav.syfo.testutil.TestDB -import no.nav.syfo.testutil.okApprec -import no.nav.syfo.testutil.receivedSykmelding -import java.time.LocalDateTime -import java.util.UUID - -class UpdateStatusServiceDbTest : FunSpec({ - val database: DatabaseInterface = TestDB.database - val oppgaveClient: OppgaveClient = mockk() - val service: UpdateStatusService = UpdateStatusService(database, oppgaveClient) - mockkStatic("no.nav.syfo.persistering.db.PersisterManuellOppgaveQueriesKt") - coEvery { oppgaveClient.hentOppgave(any(), any()) } returns null - beforeTest { - database.opprettManuellOppgave( - manuellOppgave = ManuellOppgave( - receivedSykmelding = receivedSykmelding(UUID.randomUUID().toString()), - validationResult = ValidationResult(Status.OK, emptyList()), - apprec = okApprec(), - ), - okApprec(), - 0, - ManuellOppgaveStatus.APEN, - LocalDateTime.now(), - ) - } - - test("Update status") { - service.start() - } -}) diff --git a/src/test/kotlin/no/nav/syfo/oppgave/service/UpdateStatusServiceTest.kt b/src/test/kotlin/no/nav/syfo/oppgave/service/UpdateStatusServiceTest.kt deleted file mode 100644 index 26cef421..00000000 --- a/src/test/kotlin/no/nav/syfo/oppgave/service/UpdateStatusServiceTest.kt +++ /dev/null @@ -1,51 +0,0 @@ -package no.nav.syfo.oppgave.service - -import io.kotest.core.spec.style.FunSpec -import io.mockk.coEvery -import io.mockk.coVerify -import io.mockk.mockk -import io.mockk.mockkStatic -import kotlinx.coroutines.test.runTest -import no.nav.syfo.db.DatabaseInterface -import no.nav.syfo.model.ManuellOppgaveStatus -import no.nav.syfo.oppgave.OpprettOppgaveResponse -import no.nav.syfo.oppgave.client.OppgaveClient -import no.nav.syfo.persistering.db.getOppgaveWithNullStatus -import no.nav.syfo.persistering.db.oppdaterOppgaveHendelse -import java.time.ZonedDateTime - -class UpdateStatusServiceTest : FunSpec({ - val database: DatabaseInterface = mockk(relaxed = true) - val oppgaveClient: OppgaveClient = mockk() - lateinit var service: UpdateStatusService - mockkStatic("no.nav.syfo.persistering.db.PersisterManuellOppgaveQueriesKt") - - beforeTest { - service = UpdateStatusService(database, oppgaveClient) - } - - test("`start` should fetch oppgave and update their status") { - runTest { - val oppgaveId = 1 - val id = "id" - val status = "FERDIGSTILT" - val oppgaveList = listOf(oppgaveId to id) - val localTime = ZonedDateTime.now() - val oppgave = OpprettOppgaveResponse(oppgaveId, 1, status, endretTidspunkt = localTime) - - coEvery { database.getOppgaveWithNullStatus(10) } returns - oppgaveList andThen emptyList() - coEvery { oppgaveClient.hentOppgave(oppgaveId, id) } returns oppgave - - service.start() - - coVerify { - database.oppdaterOppgaveHendelse( - oppgaveId = oppgaveId, - status = ManuellOppgaveStatus.FERDIGSTILT, - statusTimestamp = oppgave.endretTidspunkt!!.toLocalDateTime(), - ) - } - } - } -})