-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* start leader elector service * update timetype * skip 404 oppgaver * update status to deleted if it is not found * Use another leader elector method * update error handling * Update build.gradle.kts * Log warn instead of error in LeaderElector
- Loading branch information
1 parent
738cfb0
commit ac53b1b
Showing
21 changed files
with
406 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
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>() | ||
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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
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() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,4 +28,5 @@ enum class ManuellOppgaveStatus { | |
APEN, | ||
FERDIGSTILT, | ||
FEILREGISTRERT, | ||
DELETED, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
92 changes: 92 additions & 0 deletions
92
src/main/kotlin/no/nav/syfo/oppgave/service/UpdateStatusService.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
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 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package no.nav.syfo.service | ||
|
||
interface UpdateService { | ||
suspend fun start() | ||
suspend fun stop() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.