feat(redis): migrate from Redisson to Quarkus Redis client and update configuration

This commit is contained in:
2026-04-28 22:44:10 +02:00
parent 0652dd2d2f
commit 5d97c3c8b5
58 changed files with 209 additions and 504 deletions
+1 -1
View File
@@ -62,7 +62,7 @@ dependencies {
implementation("io.quarkus:quarkus-smallrye-health")
implementation("io.quarkus:quarkus-smallrye-openapi")
implementation("com.fasterxml.jackson.module:jackson-module-scala_3:${versions["JACKSON_SCALA"]!!}")
implementation("org.redisson:redisson:${versions["REDISSON"]!!}")
implementation("io.quarkus:quarkus-redis-client")
implementation(project(":modules:api"))
@@ -3,6 +3,8 @@ quarkus:
port: 8087
application:
name: nowchess-bot-platform
redis:
hosts: redis://${REDIS_HOST:localhost}:${REDIS_PORT:6379}
smallrye-jwt:
enabled: true
log:
@@ -7,12 +7,6 @@ import scala.compiletime.uninitialized
@ApplicationScoped
class RedisConfig:
// scalafix:off DisableSyntax.var
@ConfigProperty(name = "nowchess.redis.host", defaultValue = "localhost")
var host: String = uninitialized
@ConfigProperty(name = "nowchess.redis.port", defaultValue = "6379")
var port: Int = uninitialized
@ConfigProperty(name = "nowchess.redis.prefix", defaultValue = "nowchess")
var prefix: String = uninitialized
// scalafix:on DisableSyntax.var
@@ -1,35 +0,0 @@
package de.nowchess.botplatform.config
import jakarta.annotation.PreDestroy
import jakarta.enterprise.context.ApplicationScoped
import jakarta.enterprise.inject.Produces
import jakarta.inject.Inject
import org.redisson.Redisson
import org.redisson.api.RedissonClient
import org.redisson.config.Config
import scala.compiletime.uninitialized
@ApplicationScoped
class RedissonProducer:
// scalafix:off DisableSyntax.var
@Inject
var redisConfig: RedisConfig = uninitialized
private var clientOpt: Option[RedissonClient] = None
// scalafix:on DisableSyntax.var
@Produces
@ApplicationScoped
def produceRedissonClient(): RedissonClient =
val config = new Config()
config.useSingleServer().setAddress(s"redis://${redisConfig.host}:${redisConfig.port}")
config.useSingleServer().setConnectionMinimumIdleSize(1)
config.useSingleServer().setConnectTimeout(500)
val client = Redisson.create(config)
clientOpt = Some(client)
client
@PreDestroy
def shutdown(): Unit =
clientOpt.foreach(_.shutdown())
@@ -1,43 +1,39 @@
package de.nowchess.botplatform.registry
import de.nowchess.botplatform.config.RedisConfig
import io.quarkus.redis.datasource.RedisDataSource
import io.quarkus.redis.datasource.pubsub.PubSubCommands
import io.smallrye.mutiny.subscription.MultiEmitter
import jakarta.enterprise.context.ApplicationScoped
import jakarta.inject.Inject
import org.redisson.api.RedissonClient
import org.redisson.api.listener.MessageListener
import scala.compiletime.uninitialized
import java.util.concurrent.ConcurrentHashMap
import java.util.function.Consumer
@ApplicationScoped
class BotRegistry:
// scalafix:off DisableSyntax.var
@Inject var redisson: RedissonClient = uninitialized
@Inject var redis: RedisDataSource = uninitialized
@Inject var redisConfig: RedisConfig = uninitialized
// scalafix:on DisableSyntax.var
private val connections = ConcurrentHashMap[String, (MultiEmitter[?], Int)]()
private val connections = ConcurrentHashMap[String, (MultiEmitter[?], PubSubCommands.RedisSubscriber)]()
def register(botId: String, emitter: MultiEmitter[? >: String]): Unit =
val topic = redisson.getTopic(s"${redisConfig.prefix}:bot:$botId:events")
val listenerId = topic.addListener(
classOf[String],
new MessageListener[String]:
def onMessage(channel: CharSequence, msg: String): Unit =
emitter.asInstanceOf[MultiEmitter[String]].emit(msg),
)
connections.put(botId, (emitter, listenerId))
val channel = s"${redisConfig.prefix}:bot:$botId:events"
val handler: Consumer[String] = msg => emitter.asInstanceOf[MultiEmitter[String]].emit(msg)
val subscriber = redis.pubsub(classOf[String]).subscribe(channel, handler)
connections.put(botId, (emitter, subscriber))
()
def unregister(botId: String): Unit =
Option(connections.remove(botId)).foreach { (_, listenerId) =>
redisson.getTopic(s"${redisConfig.prefix}:bot:$botId:events").removeListener(listenerId)
Option(connections.remove(botId)).foreach { (_, subscriber) =>
subscriber.unsubscribe(s"${redisConfig.prefix}:bot:$botId:events")
}
def dispatch(botId: String, event: String): Unit =
redisson.getTopic(s"${redisConfig.prefix}:bot:$botId:events").publish(event)
redis.pubsub(classOf[String]).publish(s"${redisConfig.prefix}:bot:$botId:events", event)
()
def registeredBots: List[String] =
@@ -2,6 +2,7 @@ package de.nowchess.botplatform.resource
import de.nowchess.botplatform.config.RedisConfig
import de.nowchess.botplatform.registry.BotRegistry
import io.quarkus.redis.datasource.RedisDataSource
import io.smallrye.mutiny.Multi
import jakarta.annotation.security.RolesAllowed
import jakarta.enterprise.context.ApplicationScoped
@@ -9,9 +10,8 @@ import jakarta.inject.Inject
import jakarta.ws.rs.*
import jakarta.ws.rs.core.{MediaType, Response}
import org.eclipse.microprofile.jwt.JsonWebToken
import org.redisson.api.RedissonClient
import org.redisson.api.listener.MessageListener
import scala.compiletime.uninitialized
import java.util.function.Consumer
@Path("/api/bot")
@ApplicationScoped
@@ -21,7 +21,7 @@ class BotEventResource:
// scalafix:off DisableSyntax.var
@Inject var registry: BotRegistry = uninitialized
@Inject var jwt: JsonWebToken = uninitialized
@Inject var redisson: RedissonClient = uninitialized
@Inject var redis: RedisDataSource = uninitialized
@Inject var redisConfig: RedisConfig = uninitialized
// scalafix:on DisableSyntax.var
@@ -44,14 +44,10 @@ class BotEventResource:
@Produces(Array(MediaType.SERVER_SENT_EVENTS))
def streamGame(@PathParam("gameId") gameId: String): Multi[String] =
Multi.createFrom().emitter[String] { emitter =>
val topicName = s"${redisConfig.prefix}:game:$gameId:s2c"
val topic = redisson.getTopic(topicName)
val listenerId = topic.addListener(
classOf[String],
new MessageListener[String]:
def onMessage(channel: CharSequence, msg: String): Unit = emitter.emit(msg),
)
emitter.onTermination(() => topic.removeListener(listenerId))
val topicName = s"${redisConfig.prefix}:game:$gameId:s2c"
val handler: Consumer[String] = msg => emitter.emit(msg)
val subscriber = redis.pubsub(classOf[String]).subscribe(topicName, handler)
emitter.onTermination(() => subscriber.unsubscribe(topicName))
}
@POST
@@ -63,5 +59,5 @@ class BotEventResource:
): Response =
val playerId = Option(jwt.getSubject).getOrElse("")
val moveMsg = s"""{"type":"MOVE","uci":"$uci","playerId":"$playerId"}"""
redisson.getTopic(s"${redisConfig.prefix}:game:$gameId:c2s").publish(moveMsg)
redis.pubsub(classOf[String]).publish(s"${redisConfig.prefix}:game:$gameId:c2s", moveMsg)
Response.ok().build()