diff --git a/docs/schema.dbml b/docs/schema.dbml index 37a716dd..8a7e0b4c 100644 --- a/docs/schema.dbml +++ b/docs/schema.dbml @@ -255,6 +255,8 @@ Table game_matches { started_at timestamp finished_at timestamp + times_scheduled integer [not null, default: 0] + ~user_audit_template } diff --git a/src/main/java/org/bytefight/webserver/gamematch/application/GameMatchService.java b/src/main/java/org/bytefight/webserver/gamematch/application/GameMatchService.java index 9c9eccce..b0ce529b 100755 --- a/src/main/java/org/bytefight/webserver/gamematch/application/GameMatchService.java +++ b/src/main/java/org/bytefight/webserver/gamematch/application/GameMatchService.java @@ -131,6 +131,7 @@ public GameMatch scheduleMatch(GameMatch match) { match.setStatus(MatchStatus.waiting); match.setScheduledAt(Instant.now()); + match.setTimesScheduled(match.getTimesScheduled() + 1); return gameMatchRepository.save(match); } @@ -302,90 +303,12 @@ public Page getFullPaginatedQueue(Competition competition, Pageable p page); } - public GameMatchDto getDTOById(Long id) { - return GameMatchDto.fromEntity(gameMatchRepository.getReferenceById(id)); - } - public Optional getDTOByUuid(String uuid) { Optional dto = gameMatchRepository.findByUuid(UUID.fromString(uuid)); if (dto.isEmpty()) return Optional.empty(); return Optional.of(GameMatchDto.fromEntity(dto.get())); } - - public GameMatch getReferenceById(Long id) { - return gameMatchRepository.getReferenceById(id); - } - - public Optional getReferenceByUuid(String uuid) { - return gameMatchRepository.findByUuid(UUID.fromString(uuid)); - } - - public boolean isGameMatchIdExist(Long id) { - return gameMatchRepository.existsById(id); - } - - public boolean isGameMatchUuidExist(String uuid) { - return gameMatchRepository.existsByUuid(UUID.fromString(uuid)); - } - - public boolean isGameMatchWaiting(String uuid) { - return false; - // return gameMatchRepository.findByUuid(UUID.fromString(uuid)).orElseThrow().getStatus() - // == MatchStatus.WAITING; - } - - public List getFailedMatches() { - return null; - // return gameMatchRepository - // .findByStatus(MatchStatus.FAILED) - // .stream() - // .toList(); - } - - @Transactional - public void rescheduleStaleMatches(boolean isIgnoreLimit) { - LocalDateTime thresholdTime = - LocalDateTime.now(clock).minusMinutes(gameMatchProperties.getStaleThresholdMinutes()); - - // This atomically marks all stale matches as RESCHEDULING and returns their ids - List matchesToReschedule = gameMatchRepository.claimAndMarkStaleMatches(thresholdTime); - log.info("Found {} matches to reschedule", matchesToReschedule.size()); - matchesToReschedule.forEach(id -> rescheduleMatch(id, isIgnoreLimit)); - log.info("Rescheduling completed"); - } - - @Transactional - public void adminRescheduleMatches(List matchIds) { - log.info("Admin {} matches to reschedule", matchIds.size()); - matchIds.forEach(id -> rescheduleMatch(id, true)); - log.info("Rescheduling completed"); - } - - @Transactional - public GameMatchJob rescheduleMatch(Long gameMatchId, boolean isIgnoreLimit) { - GameMatch gameMatch = gameMatchRepository.getReferenceById(gameMatchId); - // Integer timesQueued = gameMatch.getTimesQueued(); - // if (!isIgnoreLimit && timesQueued == 3) { - // throw new IllegalStateException("Match " + gameMatch.getId() + " has exceeded - // maximum retry attempts (3)"); - // } - // - // if(gameMatch.getStatus() != MatchStatus.WAITING) { - // throw new IllegalArgumentException("Match " + gameMatch.getId() + " cannot be - // rescheduled."); - // } - // - // gameMatch.setQueuedAt(LocalDateTime.now(clock)); - // gameMatch.incrementTimesQueued(); - // gameMatch.setStatus(MatchStatus.WAITING); - GameMatchJob job = GameMatchJob.from(gameMatch); - gameMatchRepository.save(gameMatch); - rabbitMQService.enqueueGameMatchJob(job); - log.info("rescheduled match {}", job); - return job; - } - public long countTeamQueuedMatchesByLadder(Team team, Ladder ladder) { return gameMatchRepository.countTeamMatchesByLadderAndStatus( team, ladder.getLadder(), Set.of(MatchStatus.waiting, MatchStatus.in_progress)); diff --git a/src/main/java/org/bytefight/webserver/gamematch/domain/GameMatch.java b/src/main/java/org/bytefight/webserver/gamematch/domain/GameMatch.java index 1391c2f6..8422cd54 100644 --- a/src/main/java/org/bytefight/webserver/gamematch/domain/GameMatch.java +++ b/src/main/java/org/bytefight/webserver/gamematch/domain/GameMatch.java @@ -80,4 +80,7 @@ public class GameMatch extends AuditableEntity { @Column(name = "finished_at") private Instant finishedAt; + + @Column(name = "times_scheduled", nullable = false) + private Integer timesScheduled = 0; } diff --git a/src/main/java/org/bytefight/webserver/gamematch/infra/AdminGameMatchController.java b/src/main/java/org/bytefight/webserver/gamematch/infra/AdminGameMatchController.java index 91cb9a8c..4d6ecd6b 100644 --- a/src/main/java/org/bytefight/webserver/gamematch/infra/AdminGameMatchController.java +++ b/src/main/java/org/bytefight/webserver/gamematch/infra/AdminGameMatchController.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.Set; +import java.util.UUID; import org.bytefight.webserver.common.web.RestPageRequest; import org.bytefight.webserver.gamematch.application.AdminGameMatchService; @@ -40,18 +41,14 @@ public AdminGameMatchController( this.gameMatchService = gameMatchService; } - @PostMapping("/reschedule-stale") - @PreAuthorize("hasRole('ADMIN')") - public ResponseEntity reschduleStaleMatches() { - gameMatchService.rescheduleStaleMatches(false); + @PostMapping("/schedule") + public ResponseEntity adminScheduleMatches(@RequestBody List matchUuids) { + for(String uuid : matchUuids) { + GameMatch gameMatch = gameMatchService.getGameMatch(UUID.fromString(uuid)).orElse(null); + if(gameMatch == null) continue; - return ResponseEntity.ok().build(); - } - - @PostMapping("/reschedule") - @PreAuthorize("hasRole('ADMIN')") - public ResponseEntity adminRescheduleMatches(@RequestBody List matchIds) { - gameMatchService.adminRescheduleMatches(matchIds); + gameMatchService.scheduleMatch(gameMatch); + } return ResponseEntity.ok().build(); } diff --git a/src/main/resources/db/migration/V13__add_times_scheduled_field_to_gm.sql b/src/main/resources/db/migration/V13__add_times_scheduled_field_to_gm.sql new file mode 100644 index 00000000..f76f3e9c --- /dev/null +++ b/src/main/resources/db/migration/V13__add_times_scheduled_field_to_gm.sql @@ -0,0 +1,4 @@ +BEGIN; +ALTER TABLE IF EXISTS public.game_matches + ADD COLUMN times_scheduled integer NOT NULL DEFAULT 0; +END; \ No newline at end of file