fix(events): suppress stream poll loop in test profile
Build & Test (NowChessSystems) TeamCity build failed

CDI fires StartupEvent to all observer beans regardless of @InjectMock
substitution, causing GameCreationStreamClient and GameCreationStreamListener
to start their poll loops during @QuarkusTest even when mocked. Without
Redis configured in account tests, this floods logs with NPE stack traces
from the unconfigured RedisDataSource synthetic bean.

- Switch @Startup/@PostConstruct to @Observes StartupEvent on both beans
- Guard startup body with nowchess.game-creation-stream.enabled (default true)
- Disable the flag in modules/account/src/test/resources/application.yml

Mirrors the nowchess.coordinator.enabled pattern in InstanceHeartbeatService.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Janis Eccarius
2026-06-06 19:15:08 +02:00
parent e7a49a2f3e
commit 5f35318ebd
3 changed files with 28 additions and 22 deletions
@@ -8,10 +8,11 @@ import de.nowchess.api.player.PlayerType
import de.nowchess.api.event.{EventEnvelope, EventType}
import io.quarkus.redis.datasource.RedisDataSource
import io.quarkus.redis.datasource.stream.{StreamMessage, XAddArgs, XGroupCreateArgs, XReadGroupArgs}
import io.quarkus.runtime.Startup
import jakarta.annotation.PostConstruct
import io.quarkus.runtime.StartupEvent
import jakarta.enterprise.context.ApplicationScoped
import jakarta.enterprise.event.Observes
import jakarta.inject.Inject
import org.eclipse.microprofile.config.inject.ConfigProperty
import org.eclipse.microprofile.context.ManagedExecutor
import org.jboss.logging.Logger
import scala.compiletime.uninitialized
@@ -21,7 +22,6 @@ import java.time.Duration
import java.util.UUID
import java.util.concurrent.{CompletableFuture, ConcurrentHashMap, TimeUnit}
@Startup
@ApplicationScoped
class GameCreationStreamClient:
@@ -30,6 +30,8 @@ class GameCreationStreamClient:
@Inject var redisConfig: RedisConfig = uninitialized
@Inject var objectMapper: ObjectMapper = uninitialized
@Inject var executor: ManagedExecutor = uninitialized
@ConfigProperty(name = "nowchess.game-creation-stream.enabled", defaultValue = "true")
private var streamEnabled: Boolean = true
// scalafix:on DisableSyntax.var
private val log = Logger.getLogger(classOf[GameCreationStreamClient])
@@ -44,14 +46,14 @@ class GameCreationStreamClient:
private def requestStream: String = s"${redisConfig.prefix}:game-creation"
private def responseStream: String = s"${redisConfig.prefix}:game-creation-response"
@PostConstruct
def start(): Unit =
createGroupIfAbsent()
executor.submit(
new Runnable:
def run(): Unit = pollLoop(),
)
log.infof("Game-creation response listener started (consumer=%s)", consumerId)
def start(@Observes _ev: StartupEvent): Unit =
if streamEnabled then
createGroupIfAbsent()
executor.submit(
new Runnable:
def run(): Unit = pollLoop(),
)
log.infof("Game-creation response listener started (consumer=%s)", consumerId)
def createGame(req: CoreCreateGameRequest): GameCreationResponseDto =
val correlationId = UUID.randomUUID().toString
@@ -34,3 +34,5 @@ nowchess:
secret: test-secret
auth:
enabled: false
game-creation-stream:
enabled: false
@@ -7,10 +7,11 @@ import de.nowchess.chess.config.RedisConfig
import de.nowchess.chess.service.GameCreationService
import io.quarkus.redis.datasource.RedisDataSource
import io.quarkus.redis.datasource.stream.{StreamMessage, XAddArgs, XGroupCreateArgs, XReadGroupArgs}
import io.quarkus.runtime.Startup
import jakarta.annotation.PostConstruct
import io.quarkus.runtime.StartupEvent
import jakarta.enterprise.context.ApplicationScoped
import jakarta.enterprise.event.Observes
import jakarta.inject.Inject
import org.eclipse.microprofile.config.inject.ConfigProperty
import org.eclipse.microprofile.context.ManagedExecutor
import org.jboss.logging.Logger
import scala.compiletime.uninitialized
@@ -19,7 +20,6 @@ import scala.util.{Failure, Success, Try}
import java.time.Duration
import java.util.UUID
@Startup
@ApplicationScoped
class GameCreationStreamListener:
@@ -29,6 +29,8 @@ class GameCreationStreamListener:
@Inject var creationService: GameCreationService = uninitialized
@Inject var executor: ManagedExecutor = uninitialized
@Inject var redisConfig: RedisConfig = uninitialized
@ConfigProperty(name = "nowchess.game-creation-stream.enabled", defaultValue = "true")
private var streamEnabled: Boolean = true
// scalafix:on DisableSyntax.var
private val log = Logger.getLogger(classOf[GameCreationStreamListener])
@@ -41,14 +43,14 @@ class GameCreationStreamListener:
private def responseStream: String = s"${redisConfig.prefix}:game-creation-response"
private def dlqStream: String = s"${redisConfig.prefix}:dlq"
@PostConstruct
def start(): Unit =
createGroupIfAbsent()
executor.submit(
new Runnable:
def run(): Unit = pollLoop(),
)
log.infof("Game-creation request listener started (consumer=%s)", consumerId)
def start(@Observes _ev: StartupEvent): Unit =
if streamEnabled then
createGroupIfAbsent()
executor.submit(
new Runnable:
def run(): Unit = pollLoop(),
)
log.infof("Game-creation request listener started (consumer=%s)", consumerId)
private def createGroupIfAbsent(): Unit =
Try(