finish abandoned games after 10 days
parent
1003f7e14b
commit
49b0403352
|
@ -64,6 +64,9 @@ sudo ln -s /path/to/lila/bin/prod/archlinux/conf.d/lila ./
|
|||
- Configure the daemon in /etc/conf.d/lila
|
||||
- Add lila to DAEMONS in /etc/rc.conf
|
||||
|
||||
Optional
|
||||
ulimit -n 99999
|
||||
|
||||
Restart on timeout
|
||||
------------------
|
||||
|
||||
|
|
|
@ -154,6 +154,7 @@ final class CoreEnv private (application: Application, val settings: Settings) {
|
|||
lazy val titivate = new lila.core.Titivate(
|
||||
gameRepo = game.gameRepo,
|
||||
finisher = round.finisher,
|
||||
meddler = round.meddler,
|
||||
bookmarkApi = bookmark.api)
|
||||
|
||||
lazy val mod = new lila.mod.ModEnv(
|
||||
|
|
|
@ -40,11 +40,11 @@ object Cron {
|
|||
}
|
||||
}
|
||||
|
||||
effect(2 seconds, "fisherman cleanup") {
|
||||
effect(2 seconds, "fisherman: cleanup") {
|
||||
env.lobby.fisherman.cleanup
|
||||
}
|
||||
|
||||
effect(10 seconds, "lobby cleanup") {
|
||||
effect(10 seconds, "lobby: cleanup") {
|
||||
env.lobby.hookRepo.cleanupOld
|
||||
}
|
||||
|
||||
|
@ -56,18 +56,23 @@ object Cron {
|
|||
|
||||
if (current.mode != Mode.Dev) {
|
||||
|
||||
effect(4.1 hours, "game cleanup") {
|
||||
env.ai.clientDiagnose
|
||||
|
||||
effect(4.17 hours, "game: cleanup") {
|
||||
env.titivate.cleanupUnplayed flatMap { _ ⇒
|
||||
env.titivate.cleanupNext
|
||||
}
|
||||
}
|
||||
|
||||
effect(1 hour, "game finish") {
|
||||
effect(1.13 hour, "game: finish by clock") {
|
||||
env.titivate.finishByClock
|
||||
}
|
||||
|
||||
env.ai.clientDiagnose
|
||||
effect(1 minutes, "game: finish abandoned") {
|
||||
env.titivate.finishAbandoned
|
||||
}
|
||||
}
|
||||
|
||||
unsafe(10 seconds, "ai: diagnose") {
|
||||
env.ai.clientDiagnose
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package lila
|
|||
package core
|
||||
|
||||
import game.GameRepo
|
||||
import round.Finisher
|
||||
import round.{ Finisher, Meddler }
|
||||
import bookmark.BookmarkApi
|
||||
|
||||
import com.mongodb.casbah.query.Imports._
|
||||
|
@ -11,18 +11,26 @@ import org.scala_tools.time.Imports._
|
|||
import scalaz.effects._
|
||||
|
||||
final class Titivate(
|
||||
gameRepo: GameRepo,
|
||||
finisher: Finisher,
|
||||
bookmarkApi: BookmarkApi) {
|
||||
gameRepo: GameRepo,
|
||||
finisher: Finisher,
|
||||
meddler: Meddler,
|
||||
bookmarkApi: BookmarkApi) {
|
||||
|
||||
val finishByClock: IO[Unit] =
|
||||
for {
|
||||
games ← gameRepo.candidatesToAutofinish
|
||||
_ ← (finisher outoftimes games).sequence
|
||||
} yield ()
|
||||
val finishByClock: IO[Unit] = for {
|
||||
games ← gameRepo.candidatesToAutofinish
|
||||
_ ← putStrLn("[titivate] Finish %d games by clock" format games.size)
|
||||
_ ← (finisher outoftimes games).sequence
|
||||
} yield ()
|
||||
|
||||
val cleanupUnplayed = for {
|
||||
val finishAbandoned: IO[Unit] = for {
|
||||
games ← gameRepo abandoned 200
|
||||
_ ← putStrLn("[titivate] Finish %d abandoned games" format games.size)
|
||||
_ ← (games map meddler.finishAbandoned).sequence
|
||||
} yield ()
|
||||
|
||||
val cleanupUnplayed: IO[Unit] = for {
|
||||
ids ← gameRepo.unplayedIds
|
||||
_ ← putStrLn("[titivate] Remove %d unplayed games" format ids.size)
|
||||
_ ← gameRepo removeIds ids
|
||||
_ ← bookmarkApi removeByGameIds ids
|
||||
} yield ()
|
||||
|
|
|
@ -333,7 +333,7 @@ case class DbGame(
|
|||
def pgnList = pgn.split(' ').toList
|
||||
|
||||
def playerWhoDidNotMove: Option[DbPlayer] = turns match {
|
||||
case 0 ⇒ player(White).some
|
||||
case 0 ⇒ player(White).some
|
||||
case 1 ⇒ player(Black).some
|
||||
case _ ⇒ none
|
||||
}
|
||||
|
@ -356,6 +356,11 @@ case class DbGame(
|
|||
def isBeingPlayed =
|
||||
!finishedOrAborted && updatedAt.fold(_ > DateTime.now - 20.seconds, false)
|
||||
|
||||
def abandoned = updatedAt.fold(
|
||||
u ⇒ (status <= Status.Started) && (u <= DbGame.abandonedDate),
|
||||
false
|
||||
)
|
||||
|
||||
def hasBookmarks = bookmarks > 0
|
||||
|
||||
def showBookmarks = if (hasBookmarks) bookmarks else ""
|
||||
|
@ -408,6 +413,8 @@ object DbGame {
|
|||
val playerIdSize = 4
|
||||
val fullIdSize = 12
|
||||
|
||||
def abandonedDate = DateTime.now - 10.days
|
||||
|
||||
def takeGameId(fullId: String) = fullId take gameIdSize
|
||||
|
||||
def apply(
|
||||
|
|
|
@ -133,8 +133,8 @@ final class GameRepo(collection: MongoCollection)
|
|||
|
||||
val unplayedIds: IO[List[String]] = io {
|
||||
primitiveProjections[String](
|
||||
("turns" $lt 2) ++
|
||||
("createdAt" $lt (DateTime.now - 2.day) $gt (DateTime.now - 1.month)),
|
||||
("turns" $lt 2) ++
|
||||
("createdAt" $lt (DateTime.now - 2.day) $gt (DateTime.now - 1.month)),
|
||||
"_id"
|
||||
)
|
||||
}
|
||||
|
@ -148,7 +148,7 @@ final class GameRepo(collection: MongoCollection)
|
|||
remove("_id" $in ids)
|
||||
}
|
||||
|
||||
def candidatesToAutofinish: IO[List[DbGame]] = io {
|
||||
val candidatesToAutofinish: IO[List[DbGame]] = io {
|
||||
find(Query.playable ++
|
||||
Query.clock(true) ++
|
||||
("createdAt" $gt (DateTime.now - 1.day)) ++ // index
|
||||
|
@ -156,7 +156,13 @@ final class GameRepo(collection: MongoCollection)
|
|||
).toList.map(_.decode).flatten
|
||||
}
|
||||
|
||||
def featuredCandidates: IO[List[DbGame]] = io {
|
||||
def abandoned(max: Int): IO[List[DbGame]] = io {
|
||||
find(
|
||||
Query.notFinished ++ ("updatedAt" $lt DbGame.abandonedDate)
|
||||
).limit(max).toList.map(_.decode).flatten
|
||||
}
|
||||
|
||||
val featuredCandidates: IO[List[DbGame]] = io {
|
||||
find(Query.playable ++
|
||||
Query.clock(true) ++
|
||||
("turns" $gt 1) ++
|
||||
|
@ -177,7 +183,7 @@ final class GameRepo(collection: MongoCollection)
|
|||
find(Query.started ++ Query.turnsGt(1))
|
||||
.sort(Query.sortCreated)
|
||||
.limit(limit)
|
||||
.toList.map(_.decode).flatten
|
||||
.toList.map(_.decode).flatten
|
||||
}
|
||||
|
||||
def games(ids: List[String]): IO[List[DbGame]] = io {
|
||||
|
|
|
@ -27,7 +27,7 @@ object Query {
|
|||
|
||||
val finished: DBObject = "status" $in List(Status.Mate.id, Status.Resign.id, Status.Outoftime.id, Status.Timeout.id)
|
||||
|
||||
val notFinished: DBObject = DBObject("status" -> Status.Started.id)
|
||||
val notFinished: DBObject = "status" $lte Status.Started.id
|
||||
|
||||
val frozen: DBObject = "status" $gte Status.Mate.id
|
||||
|
||||
|
|
|
@ -36,4 +36,14 @@ final class Meddler(
|
|||
povOption ← gameRepo pov povRef
|
||||
_ ← povOption.fold(resign, putStrLn("Cannot resign missing game " + povRef))
|
||||
} yield ()
|
||||
|
||||
def finishAbandoned(game: DbGame): IO[Unit] = game.abandoned.fold(
|
||||
finisher.resign(Pov(game, game.player))
|
||||
.prefixFailuresWith("Finish abandoned game " + game.id)
|
||||
.fold(
|
||||
err ⇒ putStrLn(err.shows),
|
||||
_ map (_ ⇒ ()) // discard the events
|
||||
),
|
||||
putStrLn("Game is not abandoned")
|
||||
)
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ final class Indexer(
|
|||
def count(request: CountRequest): Int = request.in(indexName, typeName)(es)
|
||||
|
||||
val indexQueue: IO[Unit] = for {
|
||||
ids ← queue next 1000
|
||||
ids ← queue next 2000
|
||||
_ ← ids.toNel.fold(
|
||||
neIds ⇒ for {
|
||||
_ ← putStrLn("Search indexing %d games" format neIds.list.size)
|
||||
|
|
Loading…
Reference in New Issue