diff --git a/src/main/kotlin/com/faforever/icebreaker/persistence/IceSessionEntity.kt b/src/main/kotlin/com/faforever/icebreaker/persistence/IceSessionEntity.kt index e0b7dd5..197e14d 100644 --- a/src/main/kotlin/com/faforever/icebreaker/persistence/IceSessionEntity.kt +++ b/src/main/kotlin/com/faforever/icebreaker/persistence/IceSessionEntity.kt @@ -6,8 +6,10 @@ import jakarta.inject.Singleton import jakarta.persistence.Entity import jakarta.persistence.Id import jakarta.persistence.Table +import org.slf4j.LoggerFactory import java.time.Instant import java.util.UUID +import java.util.concurrent.TimeoutException @Entity @Table(name = "ice_sessions") @@ -21,8 +23,11 @@ data class IceSessionEntity( ) : PanacheEntityBase +private val LOG = LoggerFactory.getLogger(IceSessionRepository::class.java) + @Singleton class IceSessionRepository : PanacheRepository { + fun findByGameId(gameId: Long) = find("gameId = ?1", gameId).firstResult() @@ -30,15 +35,25 @@ class IceSessionRepository : PanacheRepository { find("createdAt <= ?1", instant).list() fun acquireGameLock(gameId: Long, timeout: Int = 10) { - getEntityManager().createNativeQuery("SELECT GET_LOCK(:lockName,:timeout)", Boolean::class.java).apply { + val lockAcquired = getEntityManager().createNativeQuery("SELECT GET_LOCK(:lockName,:timeout)", Boolean::class.java).apply { setParameter("lockName", "game_id_$gameId") setParameter("timeout", timeout) - }.singleResult + }.singleResult as Boolean? + + if (lockAcquired != true) { + throw TimeoutException("Unable to acquire game lock for $gameId") + } } fun releaseGameLock(gameId: Long) { - getEntityManager().createNativeQuery("SELECT RELEASE_LOCK(:lockName)", Boolean::class.java).apply { + val lockReleased = getEntityManager().createNativeQuery("SELECT RELEASE_LOCK(:lockName)", Boolean::class.java).apply { setParameter("lockName", "game_id_$gameId") - }.singleResult + }.singleResult as Boolean? + + when (lockReleased) { + null -> LOG.warn("No lock exists for $gameId") + false -> LOG.warn("Not owner of lock for $gameId") + true -> LOG.debug("Lock released for $gameId") + } } } diff --git a/src/main/kotlin/com/faforever/icebreaker/service/SessionService.kt b/src/main/kotlin/com/faforever/icebreaker/service/SessionService.kt index 88f23c2..133e7a3 100644 --- a/src/main/kotlin/com/faforever/icebreaker/service/SessionService.kt +++ b/src/main/kotlin/com/faforever/icebreaker/service/SessionService.kt @@ -26,27 +26,27 @@ class SessionService( @Transactional fun getSession(gameId: Long): Session { + val session: IceSessionEntity try { iceSessionRepository.acquireGameLock(gameId) - - val session = iceSessionRepository.findByGameId(gameId) + session = iceSessionRepository.findByGameId(gameId) ?: IceSessionEntity(gameId = gameId, createdAt = Instant.now()).also { LOG.debug("Creating session for gameId $gameId") iceSessionRepository.persist(it) } - - val servers = activeSessionHandlers.flatMap { - it.createSession(session.id) - it.getIceServersSession(session.id) - } - - return Session( - id = session.id, - servers = servers, - ) } finally { iceSessionRepository.releaseGameLock(gameId) } + + val servers = activeSessionHandlers.flatMap { + it.createSession(session.id) + it.getIceServersSession(session.id) + } + + return Session( + id = session.id, + servers = servers, + ) } @Transactional