Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 627f017cdc | |||
| 10113fd057 |
@@ -708,3 +708,47 @@
|
|||||||
### Reverts
|
### Reverts
|
||||||
|
|
||||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||||
|
## (2026-06-23)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||||
|
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||||
|
* **analytics:** add Spark batch analytics module ([#70](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/70)) ([39f1657](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/39f1657e1db6e84889af338c43be8cb5c03c3ec3))
|
||||||
|
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||||
|
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||||
|
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||||
|
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||||
|
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||||
|
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||||
|
* **events:** migrate game-creation and bot flows to Redis Streams NCS-89 ([#62](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/62)) ([a24924c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a24924c23057db3d700a75dbc4333557789cd991))
|
||||||
|
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||||
|
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||||
|
* NCS-82 add Swiss-system tournament module ([#55](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/55)) ([c5661de](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c5661de4a0ebf4b33211f5a391840dcf744656b7))
|
||||||
|
* **official-bots:** consume GameOver stream for bot cleanup ([#67](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/67)) ([db9d153](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/db9d1533912f4b41c4d1ca80ccffdde5d23d6ff6))
|
||||||
|
* **official-bots:** make HybridBot veto actionable and use it for expert ([1df29cf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1df29cf3a6e21af3f396b2b7a6da67d978f941ae))
|
||||||
|
* **official-bots:** park expert bot on tournament server at startup ([#75](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/75)) ([30295a4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/30295a4bb95855ee8261c92278bb9ebc80ee12ee))
|
||||||
|
* **official-bots:** resolve tournament bot token from Redis and account service ([386ddc5](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/386ddc5c19f8f893b16c6422aa5393b54c872e45))
|
||||||
|
* **tournament:** auto-join external tournaments and publish created ones ([#77](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/77)) ([9978b7e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/9978b7ea78eb658a225a461b9cd339386c0c14f3))
|
||||||
|
* **tournament:** federate tournaments across clusters with DB replication ([5b000a6](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5b000a6e5f04ea6770d1c7ab6bfdaded77a99172))
|
||||||
|
* **tournament:** seed external server registry from env var on startup ([845dc9c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/845dc9c2935c8bc1be42541dfaf31c9a861d3272))
|
||||||
|
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* enable official bots to connect to external tournament server ([#71](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/71)) ([688d30e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/688d30e2b10026923372be5fca3c63eaaee2de2a))
|
||||||
|
* **official-bots:** configure JWT verification ([#72](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/72)) ([98c64fc](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/98c64fc0d56dc542beb31c75f4b9056d91de03cd))
|
||||||
|
* **official-bots:** correct parkOn path from /api/bots to /api/account/bots ([1be9949](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1be9949c0b5c6a1db535696620d77735050d6c93))
|
||||||
|
* **official-bots:** discover tournament games by polling, not just the stream ([10113fd](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/10113fd0579b614d15870798d933bc9c495d2049))
|
||||||
|
* **official-bots:** make botToken optional, fall back to env, fix 502 status ([f43d193](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f43d1930d80670d810c57b54eaa3789854fa082c))
|
||||||
|
* **official-bots:** NCS-70-auto-register official bots with account service ([#59](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/59)) ([7117a93](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7117a93376272094d0b1a6abf2121254ce396684))
|
||||||
|
* **official-bots:** park on external tournament servers using correct endpoint and token ([3188241](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/31882417377468b41bbe3ff94506aa4928024450))
|
||||||
|
* **official-bots:** play only own tournament games with correct color ([4651bb7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4651bb796f07a21bd013d9521b2dfe2e1078cebb))
|
||||||
|
* **official-bots:** prioritize Redis token over stale env var in joinTournament ([83dd2d4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/83dd2d4335ca48eb3e5aa234a75367574276ba63))
|
||||||
|
* **official-bots:** register with tournament server directly to get correct token ([64b5d55](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/64b5d5567f110c2fe152558c7de275a1e0b30e21))
|
||||||
|
* **official-bots:** resume tournaments already joined after restart ([285b73e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/285b73efbd6dd98cec410ade9eead9881d693a8f))
|
||||||
|
* **official-bots:** sync bots before token fetch on first startup after DB wipe ([b0ddb27](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b0ddb274d23bca8b1b3f691ce0d643f33e0b54cd))
|
||||||
|
|
||||||
|
### Reverts
|
||||||
|
|
||||||
|
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||||
|
|||||||
+53
-2
@@ -82,15 +82,64 @@ class TournamentBotGamePlayer:
|
|||||||
private def autoJoinScan(): Unit =
|
private def autoJoinScan(): Unit =
|
||||||
resolveAutoJoinToken().foreach { token =>
|
resolveAutoJoinToken().foreach { token =>
|
||||||
TournamentBotConfig.jwtSubject(token).foreach { botId =>
|
TournamentBotConfig.jwtSubject(token).foreach { botId =>
|
||||||
openTournaments().foreach { tournamentId =>
|
val open = openTournaments()
|
||||||
|
log.infof("Auto-join scan — server=%s open tournaments=%d bot=%s", autoJoinServerUrl, open.size, botId)
|
||||||
|
open.foreach { tournamentId =>
|
||||||
if joinedTournaments.add(tournamentId) then
|
if joinedTournaments.add(tournamentId) then
|
||||||
val cfg = TournamentBotConfig(autoJoinServerUrl, tournamentId, token, botId, hardestDifficulty)
|
val cfg = TournamentBotConfig(autoJoinServerUrl, tournamentId, token, botId, hardestDifficulty)
|
||||||
if joinedOrParticipating(cfg) then startAsync(cfg)
|
if joinedOrParticipating(cfg) then startAsync(cfg)
|
||||||
else joinedTournaments.remove(tournamentId)
|
else joinedTournaments.remove(tournamentId)
|
||||||
}
|
}
|
||||||
|
playPendingGames(token, botId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The tournament-server does not reliably replay gameStart to late subscribers, so we cannot
|
||||||
|
// depend on the event stream to discover games. Poll each joined tournament for our active game.
|
||||||
|
private def playPendingGames(token: String, botId: String): Unit =
|
||||||
|
joinedTournaments.forEach { tournamentId =>
|
||||||
|
val cfg = TournamentBotConfig(autoJoinServerUrl, tournamentId, token, botId, hardestDifficulty)
|
||||||
|
pendingGame(cfg).foreach { (gameId, color) =>
|
||||||
|
if activeGames.add(gameId) then
|
||||||
|
log.infof("Polled active game %s as %s in tournament %s", gameId, color, tournamentId)
|
||||||
|
workers.submit(new Runnable { def run(): Unit = playGame(cfg, gameId, color) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def pendingGame(cfg: TournamentBotConfig): Option[(String, String)] =
|
||||||
|
for
|
||||||
|
detail <- fetchJson(cfg, target(cfg))
|
||||||
|
if detail.path("status").asText() == "started"
|
||||||
|
round = detail.path("round").asInt(0)
|
||||||
|
if round > 0
|
||||||
|
pairings <- fetchJson(cfg, target(cfg).path("round").path(round.toString)).map(_.path("pairings"))
|
||||||
|
result <- findBotGame(pairings, cfg.botId)
|
||||||
|
yield result
|
||||||
|
|
||||||
|
private def findBotGame(pairings: JsonNode, botId: String): Option[(String, String)] =
|
||||||
|
pairings.elements().asScala
|
||||||
|
.flatMap { p =>
|
||||||
|
val whiteId = p.path("white").path("id").asText()
|
||||||
|
val blackId = p.path("black").path("id").asText()
|
||||||
|
val color = if whiteId == botId then Some("white") else if blackId == botId then Some("black") else None
|
||||||
|
color.flatMap(c => activeMatch(p.path("matches")).map(gameId => (gameId, c)))
|
||||||
|
}
|
||||||
|
.nextOption()
|
||||||
|
|
||||||
|
private def activeMatch(matches: JsonNode): Option[String] =
|
||||||
|
matches.elements().asScala
|
||||||
|
.find(m => m.path("gameId").asText().nonEmpty && !(m.has("outcome") && !m.path("outcome").isNull))
|
||||||
|
.map(_.path("gameId").asText())
|
||||||
|
|
||||||
|
private def fetchJson(cfg: TournamentBotConfig, t: jakarta.ws.rs.client.WebTarget): Option[JsonNode] =
|
||||||
|
Try {
|
||||||
|
val response = authed(cfg, t).get()
|
||||||
|
try
|
||||||
|
if response.getStatus == 200 then Some(objectMapper.readTree(response.readEntity(classOf[String])))
|
||||||
|
else None
|
||||||
|
finally response.close()
|
||||||
|
}.getOrElse(None)
|
||||||
|
|
||||||
private def resolveAutoJoinToken(): Option[String] =
|
private def resolveAutoJoinToken(): Option[String] =
|
||||||
autoJoinToken match
|
autoJoinToken match
|
||||||
case some @ Some(_) => some
|
case some @ Some(_) => some
|
||||||
@@ -291,10 +340,12 @@ class TournamentBotGamePlayer:
|
|||||||
private def onGameStart(cfg: TournamentBotConfig, gameId: String): Unit =
|
private def onGameStart(cfg: TournamentBotConfig, gameId: String): Unit =
|
||||||
if gameId.isEmpty then ()
|
if gameId.isEmpty then ()
|
||||||
else
|
else
|
||||||
|
log.infof("gameStart received — tournament=%s game=%s bot=%s", cfg.tournamentId, gameId, cfg.botId)
|
||||||
resolveColor(cfg, gameId) match
|
resolveColor(cfg, gameId) match
|
||||||
case None => log.debugf("Ignoring game %s — bot %s is not a participant", gameId, cfg.botId)
|
case None => log.infof("Skipping game %s — bot %s is not a participant", gameId, cfg.botId)
|
||||||
case Some(color) =>
|
case Some(color) =>
|
||||||
if activeGames.add(gameId) then
|
if activeGames.add(gameId) then
|
||||||
|
log.infof("Joining game %s as %s", gameId, color)
|
||||||
workers.submit(new Runnable { def run(): Unit = playGame(cfg, gameId, color) })
|
workers.submit(new Runnable { def run(): Unit = playGame(cfg, gameId, color) })
|
||||||
()
|
()
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
MAJOR=0
|
MAJOR=0
|
||||||
MINOR=30
|
MINOR=31
|
||||||
PATCH=0
|
PATCH=0
|
||||||
|
|||||||
Reference in New Issue
Block a user