feat: integrate Redis for screen time caching with fallback to PostgreSQL

This commit is contained in:
Oliver Wallisch 2026-09-03 09:08:37 +02:00
parent 1ae05f0c36
commit 11dae7a57c
4 changed files with 64 additions and 5 deletions

View file

@ -31,4 +31,8 @@ dependencies {
implementation("org.jetbrains.exposed:exposed-jdbc:0.50.0")
testImplementation(kotlin("test"))
testImplementation(ktorLibs.server.testHost)
//redis
implementation("redis.clients:jedis:5.1.2")
}

View file

@ -0,0 +1,28 @@
package com.oliver.kidio.backend.data.database
import io.ktor.server.config.*
import redis.clients.jedis.JedisPool
import redis.clients.jedis.JedisPoolConfig
object RedisFactory {
private var jedisPool: JedisPool? = null
fun init(config: ApplicationConfig) {
val host = System.getenv("REDIS_HOST")
?: config.propertyOrNull("storage.redisHost")?.getString()
?: "localhost"
val port = (System.getenv("REDIS_PORT")
?: config.propertyOrNull("storage.redisPort")?.getString()
?: "6379").toInt()
val poolConfig = JedisPoolConfig().apply {
maxTotal = 32
maxIdle = 8
minIdle = 2
}
jedisPool = JedisPool(poolConfig, host, port)
}
fun getResource() = jedisPool?.resource
?: throw IllegalStateException("Redis Verbindungspool ist nicht initzialisiert")
}

View file

@ -2,6 +2,7 @@ package com.oliver.kidio.backend.domain.repository
import com.oliver.kidio.backend.Task
import com.oliver.kidio.backend.data.database.DatabaseFactory
import com.oliver.kidio.backend.data.database.RedisFactory
import com.oliver.kidio.backend.data.database.ScreentimeTable
import com.oliver.kidio.backend.data.database.TasksTable
import org.jetbrains.exposed.sql.*
@ -32,11 +33,35 @@ class ExposedKidioRepository : KidioRepository {
.singleOrNull()
}
override suspend fun getScreentime(userId: String): Int = DatabaseFactory.dbQuery {
ScreentimeTable.selectAll()
.where { ScreentimeTable.userId eq userId }
.map { it[ScreentimeTable.remainingSeconds] }
.singleOrNull() ?: 1800
override suspend fun getScreentime(userId: String): Int {
var redisKey = "screentime:$userId"
try {
RedisFactory.getResource().use { jedis ->
val cachedSeconds = jedis.get(redisKey)
if (cachedSeconds != null) {
println("DEBUG: Bildschirmzeit für $userId aus REDIS geladen: $cachedSeconds Sek")
return cachedSeconds.toInt()
}
}
} catch (e: Exception) {
println("WARNUNG: Konnte nicht aus Redis lesen (Postgres-Fallback genutzt): ${e.message}")
}
val dbSeconds = DatabaseFactory.dbQuery {
ScreentimeTable.selectAll()
.where { ScreentimeTable.userId eq userId }
.map { it[ScreentimeTable.remainingSeconds] }
.singleOrNull() ?: 1800
}
try {
RedisFactory.getResource().use { jedis ->
jedis.setex(redisKey, 3600, dbSeconds.toString())
println("DEBUG: Bildschirmzeit für $userId in REDIS gecacht.")
}
} catch (e: Exception) {
println("WARNUNG: Konnte Wert nicht in Redis speichern: ${e.message}")
}
return dbSeconds
}
override suspend fun updateScreentime(userId: String, seconds: Int): Unit = DatabaseFactory.dbQuery {

View file

@ -1,5 +1,6 @@
import com.oliver.kidio.backend.plugins.configureRouting
import com.oliver.kidio.backend.data.database.DatabaseFactory
import com.oliver.kidio.backend.data.database.RedisFactory
import com.oliver.kidio.backend.domain.repository.ExposedKidioRepository
import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.application.*
@ -8,6 +9,7 @@ import io.ktor.server.plugins.contentnegotiation.*
fun Application.module() {
// Datenbank initialisieren
DatabaseFactory.init(environment.config)
RedisFactory.init(environment.config)
// JSON aktivieren
install(ContentNegotiation) {