Compare commits

..

5 Commits

Author SHA1 Message Date
TeamCity 4377e05d5c ci: bump version with Build-138 2026-06-22 19:47:25 +00:00
Janis Eccarius 3188241737 fix(official-bots): park on external tournament servers using correct endpoint and token
Build & Test (NowChessSystems) TeamCity build finished
External tournament servers expose POST /api/bots (registry) not
POST /api/account/bots. They also require their own HMAC-HS256 token,
not the NowChessSystems RS256 account-service token.

parkOnStartup now:
- Parks on the local NowChessSystems account service via /api/account/bots
  using the resolved NowChessSystems token (unchanged)
- For each remote server from fetchRemoteServers(), calls
  registerWithServer(serverUrl, name) to obtain a server-specific token
  via POST /api/auth/register (public endpoint), then parks via
  POST /api/bots using that token

registerWithTournamentServer extracted into registerWithServer(url, name)
so it can be reused for both the primary tournament server (resolveToken)
and all remote servers (parkOnStartup).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 21:13:00 +02:00
Janis Eccarius 64b5d5567f fix(official-bots): register with tournament server directly to get correct token
Build & Test (NowChessSystems) TeamCity build finished
The TOURNAMENT_SERVICE_URL points to the NowChessTools tournament server
which uses its own HMAC-HS256 JWTs issued by POST /api/auth/register.
Tokens from the NowChessSystems account service (RS256) are rejected
with 401 by that server.

resolveToken now first calls POST {tournamentServiceUrl}/api/auth/register
(public endpoint, idempotent — finds existing identity by name or creates).
This returns the correct HMAC-HS256 token for the target server and is
stored in Redis. Falls back to the account service path for deployments
where TOURNAMENT_SERVICE_URL points to the NowChessSystems tournament module.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 21:02:14 +02:00
TeamCity 65c3fabd91 ci: bump version with Build-136 2026-06-22 18:45:10 +00:00
Janis Eccarius b0ddb274d2 fix(official-bots): sync bots before token fetch on first startup after DB wipe
Build & Test (NowChessSystems) TeamCity build finished
OfficialBotService.onStart fires on StartupEvent (after all @PostConstruct),
so official bot accounts do not exist in the account service DB yet when
TournamentBotGamePlayer.initialize() runs on a fresh DB. This caused
getBotToken to 404, falling back to the stale TOURNAMENT_BOT_TOKEN env
var which uses the old signing key and is rejected with 401.

fetchTokenFromAccountService now retries after syncing all official bot
accounts (creating them if missing), ensuring a fresh token with the
current signing key is always available on startup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 20:21:43 +02:00
3 changed files with 129 additions and 12 deletions
+74
View File
@@ -470,3 +470,77 @@
### Reverts
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
## (2026-06-22)
### 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:** 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:** 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:** 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:** 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))
## (2026-06-22)
### 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:** 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:** 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:** 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:** register with tournament server directly to get correct token ([64b5d55](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/64b5d5567f110c2fe152558c7de275a1e0b30e21))
* **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))
@@ -62,12 +62,11 @@ class TournamentBotGamePlayer:
private def resolveToken(difficulty: String): Option[String] =
val name = botName(difficulty)
val redisKey = s"${redisConfig.prefix}:tournament-bot:token:$name"
Try(accountServiceClient.getBotToken(name).token)
.toOption
.filter(_.nonEmpty)
registerWithServer(tournamentServiceUrl, name)
.orElse(fetchTokenFromAccountService(name))
.map { token =>
redis.value(classOf[String]).set(redisKey, token)
log.infof("Fetched fresh bot token for %s from account service", name)
log.infof("Refreshed bot token for %s — stored in Redis", name)
token
}
.orElse {
@@ -83,15 +82,45 @@ class TournamentBotGamePlayer:
}
}
private def registerWithServer(serverUrl: String, name: String): Option[String] =
Try {
val body = s"""{"name":"${name.replace("\"", "\\\"")}","isBot":true}"""
val response = client.target(serverUrl)
.path("api").path("auth").path("register")
.request(MediaType.APPLICATION_JSON)
.post(Entity.entity(body, MediaType.APPLICATION_JSON))
val status = response.getStatus
if status == 200 || status == 201 then
val token = objectMapper.readTree(response.readEntity(classOf[String])).path("token").asText()
response.close()
Option(token).filter(_.nonEmpty)
else { response.close(); None }
}.toOption.flatten
private def fetchTokenFromAccountService(name: String): Option[String] =
Try(accountServiceClient.getBotToken(name).token).toOption.filter(_.nonEmpty)
.orElse {
Try {
val allNames = BotController.listBots.map(botName)
accountServiceClient.syncBots(de.nowchess.bot.client.SyncOfficialBotsRequest(allNames))
accountServiceClient.getBotToken(name).token
}.toOption.filter(_.nonEmpty)
}
private def parkOnStartup(token: Option[String]): Unit =
val localAccountUrl = System.getenv().asScala.getOrElse("ACCOUNT_SERVICE_URL", "http://localhost:8083")
token match
case None => log.warn("No bot token resolved — skipping park")
case None => log.warn("No bot token resolved — skipping local park")
case Some(tok) =>
val localAccountUrl = System.getenv().asScala.getOrElse("ACCOUNT_SERVICE_URL", "http://localhost:8083")
BotController.listBots.foreach(diff => parkOn(localAccountUrl, diff, tok))
fetchRemoteServers().foreach { serverUrl =>
BotController.listBots.foreach(diff => parkOn(serverUrl, diff, tok))
}
BotController.listBots.foreach(diff => parkOnAccountService(localAccountUrl, diff, tok))
fetchRemoteServers().foreach { serverUrl =>
BotController.listBots.foreach { diff =>
val name = botName(diff)
registerWithServer(serverUrl, name) match
case None => log.warnf("Could not register %s on %s — skipping park", name, serverUrl)
case Some(tok) => parkOnTournamentServer(serverUrl, name, tok)
}
}
private def fetchRemoteServers(): List[String] =
Try {
@@ -105,7 +134,7 @@ class TournamentBotGamePlayer:
else { response.close(); Nil }
}.getOrElse(Nil)
private def parkOn(serverUrl: String, difficulty: String, token: String): Unit =
private def parkOnAccountService(serverUrl: String, difficulty: String, token: String): Unit =
Try {
val body = s"""{"name":"${botName(difficulty)}"}"""
val response = client.target(serverUrl).path("api").path("account").path("bots")
@@ -119,6 +148,20 @@ class TournamentBotGamePlayer:
response.close()
}.failed.foreach(ex => log.warnf(ex, "Failed to park %s on %s", botName(difficulty), serverUrl))
private def parkOnTournamentServer(serverUrl: String, name: String, token: String): Unit =
Try {
val body = s"""{"name":"${name.replace("\"", "\\\"")}"}"""
val response = client.target(serverUrl).path("api").path("bots")
.request(MediaType.APPLICATION_JSON)
.header("Authorization", s"Bearer $token")
.post(Entity.entity(body, MediaType.APPLICATION_JSON))
if response.getStatus == 201 || response.getStatus == 200 then
val id = objectMapper.readTree(response.readEntity(classOf[String])).path("id").asText()
log.infof("Parked bot %s on tournament server %s as id %s", name, serverUrl, id)
else log.warnf("Park %s on tournament server %s returned status %d", name, serverUrl, response.getStatus)
response.close()
}.failed.foreach(ex => log.warnf(ex, "Failed to park %s on tournament server %s", name, serverUrl))
private def botName(difficulty: String): String = s"NowChess ${difficulty.capitalize}"
def joinTournament(
+1 -1
View File
@@ -1,3 +1,3 @@
MAJOR=0
MINOR=24
MINOR=26
PATCH=0