rename Trouper->SyncActor & Duct->AsyncActor
parent
5c9b22e389
commit
057495c26f
|
@ -80,7 +80,8 @@ final class ChallengeApi(
|
|||
Bus.publish(Event.Decline(c declineWith reason), "challenge")
|
||||
}
|
||||
|
||||
private val acceptQueue = new lila.hub.DuctSequencer(maxSize = 64, timeout = 5 seconds, "challengeAccept")
|
||||
private val acceptQueue =
|
||||
new lila.hub.AsyncActorSequencer(maxSize = 64, timeout = 5 seconds, "challengeAccept")
|
||||
|
||||
def accept(
|
||||
c: Challenge,
|
||||
|
|
|
@ -13,7 +13,7 @@ import lila.common.Template
|
|||
import lila.db.dsl._
|
||||
import lila.game.{ Game, Player }
|
||||
import lila.hub.actorApi.map.TellMany
|
||||
import lila.hub.DuctSequencers
|
||||
import lila.hub.AsyncActorSequencers
|
||||
import lila.rating.PerfType
|
||||
import lila.setup.SetupBulk.{ ScheduledBulk, ScheduledGame }
|
||||
import lila.user.User
|
||||
|
@ -40,7 +40,7 @@ final class ChallengeBulkApi(
|
|||
private val coll = colls.bulk
|
||||
|
||||
private val workQueue =
|
||||
new DuctSequencers(maxSize = 16, expiration = 10 minutes, timeout = 10 seconds, name = "challenge.bulk")
|
||||
new AsyncActorSequencers(maxSize = 16, expiration = 10 minutes, timeout = 10 seconds, name = "challenge.bulk")
|
||||
|
||||
def scheduledBy(me: User): Fu[List[ScheduledBulk]] =
|
||||
coll.list[ScheduledBulk]($doc("by" -> me.id))
|
||||
|
|
|
@ -169,7 +169,7 @@ object mon {
|
|||
object expiration {
|
||||
val count = counter("round.expiration.count").withoutTags()
|
||||
}
|
||||
val ductCount = gauge("round.duct.count").withoutTags()
|
||||
val asyncActorCount = gauge("round.asyncActor.count").withoutTags()
|
||||
}
|
||||
object playban {
|
||||
def outcome(out: String) = counter("playban.outcome").withTag("outcome", out)
|
||||
|
@ -201,8 +201,8 @@ object mon {
|
|||
)
|
||||
)
|
||||
}
|
||||
object duct {
|
||||
def overflow(name: String) = counter("duct.overflow").withTag("name", name)
|
||||
object asyncActor {
|
||||
def overflow(name: String) = counter("asyncActor.overflow").withTag("name", name)
|
||||
}
|
||||
object irc {
|
||||
object zulip {
|
||||
|
|
|
@ -20,7 +20,7 @@ final class Analyser(
|
|||
|
||||
val maxPlies = 200
|
||||
|
||||
private val workQueue = new lila.hub.DuctSequencer(maxSize = 256, timeout = 5 seconds, "fishnetAnalyser")
|
||||
private val workQueue = new lila.hub.AsyncActorSequencer(maxSize = 256, timeout = 5 seconds, "fishnetAnalyser")
|
||||
|
||||
def apply(game: Game, sender: Work.Sender): Fu[Boolean] =
|
||||
(game.metadata.analysed ?? analysisRepo.exists(game.id)) flatMap {
|
||||
|
|
|
@ -27,7 +27,7 @@ final class FishnetApi(
|
|||
import JsonApi.Request.{ CompleteAnalysis, PartialAnalysis }
|
||||
import BSONHandlers._
|
||||
|
||||
private val workQueue = new lila.hub.DuctSequencer(maxSize = 256, timeout = 5 seconds, name = "fishnetApi")
|
||||
private val workQueue = new lila.hub.AsyncActorSequencer(maxSize = 256, timeout = 5 seconds, name = "fishnetApi")
|
||||
|
||||
def keyExists(key: Client.Key) = repo.getEnabledClient(key).map(_.isDefined)
|
||||
|
||||
|
|
|
@ -11,11 +11,11 @@ import scala.concurrent.{ ExecutionContext, Promise }
|
|||
final class AskPipeline[A](compute: () => Fu[A], timeout: FiniteDuration, name: String)(implicit
|
||||
system: akka.actor.ActorSystem,
|
||||
ec: scala.concurrent.ExecutionContext
|
||||
) extends Trouper {
|
||||
) extends SyncActor {
|
||||
|
||||
private var state: State = Idle
|
||||
|
||||
protected val process: Trouper.Receive = {
|
||||
protected val process: SyncActor.Receive = {
|
||||
|
||||
case Get(promise) =>
|
||||
state match {
|
||||
|
|
|
@ -9,9 +9,9 @@ import scala.concurrent.Promise
|
|||
* Sequential like an actor, but for async functions,
|
||||
* and using an atomic backend instead of akka actor.
|
||||
*/
|
||||
abstract class Duct(implicit ec: scala.concurrent.ExecutionContext) extends lila.common.Tellable {
|
||||
abstract class AsyncActor(implicit ec: scala.concurrent.ExecutionContext) extends lila.common.Tellable {
|
||||
|
||||
import Duct._
|
||||
import AsyncActor._
|
||||
|
||||
// implement async behaviour here
|
||||
protected val process: ReceiveAsync
|
||||
|
@ -33,13 +33,13 @@ abstract class Duct(implicit ec: scala.concurrent.ExecutionContext) extends lila
|
|||
private[this] val stateRef: AtomicReference[State] = new AtomicReference(None)
|
||||
|
||||
private[this] def run(msg: Any): Unit =
|
||||
process.applyOrElse(msg, Duct.fallback) onComplete postRun
|
||||
process.applyOrElse(msg, AsyncActor.fallback) onComplete postRun
|
||||
|
||||
private[this] val postRun = (_: Any) =>
|
||||
stateRef.getAndUpdate(postRunUpdate) flatMap (_.headOption) foreach run
|
||||
}
|
||||
|
||||
object Duct {
|
||||
object AsyncActor {
|
||||
|
||||
type ReceiveAsync = PartialFunction[Any, Fu[Any]]
|
||||
|
||||
|
@ -53,7 +53,7 @@ object Duct {
|
|||
}
|
||||
|
||||
private val fallback = { msg: Any =>
|
||||
lila.log("Duct").warn(s"unhandled msg: $msg")
|
||||
lila.log("asyncActor").warn(s"unhandled msg: $msg")
|
||||
funit
|
||||
}
|
||||
}
|
|
@ -6,21 +6,21 @@ import ornicar.scalalib.Zero
|
|||
import scala.concurrent.{ ExecutionContext, Promise }
|
||||
import scala.jdk.CollectionConverters._
|
||||
|
||||
final class DuctConcMap[D <: Duct](
|
||||
mkDuct: String => D,
|
||||
final class AsyncActorConcMap[D <: AsyncActor](
|
||||
mkAsyncActor: String => D,
|
||||
initialCapacity: Int
|
||||
) extends TellMap {
|
||||
|
||||
def getOrMake(id: String): D = ducts.computeIfAbsent(id, loadFunction)
|
||||
def getOrMake(id: String): D = asyncActors.computeIfAbsent(id, loadFunction)
|
||||
|
||||
def getIfPresent(id: String): Option[D] = Option(ducts get id)
|
||||
def getIfPresent(id: String): Option[D] = Option(asyncActors get id)
|
||||
|
||||
def tell(id: String, msg: Any): Unit = getOrMake(id) ! msg
|
||||
|
||||
def tellIfPresent(id: String, msg: => Any): Unit = getIfPresent(id) foreach (_ ! msg)
|
||||
|
||||
def tellAll(msg: Any) =
|
||||
ducts.forEachValue(16, _ ! msg)
|
||||
asyncActors.forEachValue(16, _ ! msg)
|
||||
|
||||
def tellIds(ids: Seq[String], msg: Any): Unit = ids foreach { tell(_, msg) }
|
||||
|
||||
|
@ -34,21 +34,21 @@ final class DuctConcMap[D <: Duct](
|
|||
def askIfPresentOrZero[A: Zero](id: String)(makeMsg: Promise[A] => Any): Fu[A] =
|
||||
askIfPresent(id)(makeMsg) dmap (~_)
|
||||
|
||||
def exists(id: String): Boolean = ducts.get(id) != null
|
||||
def exists(id: String): Boolean = asyncActors.get(id) != null
|
||||
|
||||
def foreachKey(f: String => Unit): Unit =
|
||||
ducts.forEachKey(16, k => f(k))
|
||||
asyncActors.forEachKey(16, k => f(k))
|
||||
|
||||
def tellAllWithAck(makeMsg: Promise[Unit] => Any)(implicit ec: ExecutionContext): Fu[Int] =
|
||||
ducts.values.asScala
|
||||
asyncActors.values.asScala
|
||||
.map(_ ask makeMsg)
|
||||
.sequenceFu
|
||||
.map(_.size)
|
||||
|
||||
def size: Int = ducts.size()
|
||||
def size: Int = asyncActors.size()
|
||||
|
||||
def terminate(id: String, lastWill: Duct => Unit): Unit =
|
||||
ducts
|
||||
def terminate(id: String, lastWill: AsyncActor => Unit): Unit =
|
||||
asyncActors
|
||||
.computeIfPresent(
|
||||
id,
|
||||
(_, d) => {
|
||||
|
@ -58,10 +58,10 @@ final class DuctConcMap[D <: Duct](
|
|||
)
|
||||
.unit
|
||||
|
||||
private[this] val ducts = new ConcurrentHashMap[String, D](initialCapacity)
|
||||
private[this] val asyncActors = new ConcurrentHashMap[String, D](initialCapacity)
|
||||
|
||||
private val loadFunction = new Function[String, D] {
|
||||
def apply(k: String) = mkDuct(k)
|
||||
def apply(k: String) = mkAsyncActor(k)
|
||||
}
|
||||
|
||||
// used to remove entries
|
|
@ -0,0 +1,67 @@
|
|||
package lila.hub
|
||||
|
||||
import com.github.blemale.scaffeine.LoadingCache
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
import scala.concurrent.{ ExecutionContext, Promise }
|
||||
|
||||
import lila.base.LilaTimeout
|
||||
|
||||
final class AsyncActorSequencer(maxSize: Int, timeout: FiniteDuration, name: String, logging: Boolean = true)(
|
||||
implicit
|
||||
system: akka.actor.ActorSystem,
|
||||
ec: ExecutionContext
|
||||
) {
|
||||
|
||||
import AsyncActorSequencer._
|
||||
|
||||
def apply[A](fu: => Fu[A]): Fu[A] = run(() => fu)
|
||||
|
||||
def run[A](task: Task[A]): Fu[A] = asyncActor.ask[A](TaskWithPromise(task, _))
|
||||
|
||||
private[this] val asyncActor =
|
||||
new BoundedAsyncActor(maxSize, name, logging)({ case TaskWithPromise(task, promise) =>
|
||||
promise.completeWith {
|
||||
task()
|
||||
.withTimeout(timeout)
|
||||
.transform(
|
||||
identity,
|
||||
{
|
||||
case LilaTimeout(msg) =>
|
||||
val fullMsg = s"$name AsyncActorSequencer $msg"
|
||||
if (logging) lila.log("asyncActor").warn(fullMsg)
|
||||
LilaTimeout(fullMsg)
|
||||
case e => e
|
||||
}
|
||||
)
|
||||
}.future
|
||||
})
|
||||
}
|
||||
|
||||
// Distributes tasks to many sequencers
|
||||
final class AsyncActorSequencers(
|
||||
maxSize: Int,
|
||||
expiration: FiniteDuration,
|
||||
timeout: FiniteDuration,
|
||||
name: String,
|
||||
logging: Boolean = true
|
||||
)(implicit
|
||||
system: akka.actor.ActorSystem,
|
||||
ec: ExecutionContext,
|
||||
mode: play.api.Mode
|
||||
) {
|
||||
|
||||
def apply[A](key: String)(task: => Fu[A]): Fu[A] =
|
||||
sequencers.get(key).run(() => task)
|
||||
|
||||
private val sequencers: LoadingCache[String, AsyncActorSequencer] =
|
||||
lila.common.LilaCache
|
||||
.scaffeine(mode)
|
||||
.expireAfterAccess(expiration)
|
||||
.build(key => new AsyncActorSequencer(maxSize, timeout, s"$name:$key", logging))
|
||||
}
|
||||
|
||||
object AsyncActorSequencer {
|
||||
|
||||
private type Task[A] = () => Fu[A]
|
||||
private case class TaskWithPromise[A](task: Task[A], promise: Promise[A])
|
||||
}
|
|
@ -9,11 +9,13 @@ import scala.concurrent.Promise
|
|||
* Sequential like an actor, but for async functions,
|
||||
* and using an atomic backend instead of akka actor.
|
||||
*/
|
||||
final class BoundedDuct(maxSize: Int, name: String, logging: Boolean = true)(process: Duct.ReceiveAsync)(
|
||||
implicit ec: scala.concurrent.ExecutionContext
|
||||
final class BoundedAsyncActor(maxSize: Int, name: String, logging: Boolean = true)(
|
||||
process: AsyncActor.ReceiveAsync
|
||||
)(implicit
|
||||
ec: scala.concurrent.ExecutionContext
|
||||
) {
|
||||
|
||||
import BoundedDuct._
|
||||
import BoundedAsyncActor._
|
||||
|
||||
def !(msg: Any): Boolean =
|
||||
stateRef.getAndUpdate { state =>
|
||||
|
@ -30,8 +32,8 @@ final class BoundedDuct(maxSize: Int, name: String, logging: Boolean = true)(pro
|
|||
case Some(q) =>
|
||||
val success = q.size < maxSize
|
||||
if (!success) {
|
||||
lila.mon.duct.overflow(name).increment()
|
||||
if (logging) lila.log("duct").warn(s"[$name] queue is full ($maxSize)")
|
||||
lila.mon.asyncActor.overflow(name).increment()
|
||||
if (logging) lila.log("asyncActor").warn(s"[$name] queue is full ($maxSize)")
|
||||
}
|
||||
success
|
||||
}
|
||||
|
@ -39,7 +41,7 @@ final class BoundedDuct(maxSize: Int, name: String, logging: Boolean = true)(pro
|
|||
def ask[A](makeMsg: Promise[A] => Any): Fu[A] = {
|
||||
val promise = Promise[A]()
|
||||
val success = this ! makeMsg(promise)
|
||||
if (!success) promise failure new EnqueueException(s"The $name duct queue is full ($maxSize)")
|
||||
if (!success) promise failure new EnqueueException(s"The $name asyncActor queue is full ($maxSize)")
|
||||
promise.future
|
||||
}
|
||||
|
||||
|
@ -59,12 +61,12 @@ final class BoundedDuct(maxSize: Int, name: String, logging: Boolean = true)(pro
|
|||
stateRef.getAndUpdate(postRunUpdate) flatMap (_.headOption) foreach run
|
||||
|
||||
private[this] lazy val fallback = { msg: Any =>
|
||||
lila.log("duct").warn(s"[$name] unhandled msg: $msg")
|
||||
lila.log("asyncActor").warn(s"[$name] unhandled msg: $msg")
|
||||
funit
|
||||
}
|
||||
}
|
||||
|
||||
object BoundedDuct {
|
||||
object BoundedAsyncActor {
|
||||
|
||||
final class EnqueueException(msg: String) extends Exception(msg)
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
package lila.hub
|
||||
|
||||
import com.github.blemale.scaffeine.LoadingCache
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
import scala.concurrent.{ ExecutionContext, Promise }
|
||||
|
||||
import lila.base.LilaTimeout
|
||||
|
||||
final class DuctSequencer(maxSize: Int, timeout: FiniteDuration, name: String, logging: Boolean = true)(
|
||||
implicit
|
||||
system: akka.actor.ActorSystem,
|
||||
ec: ExecutionContext
|
||||
) {
|
||||
|
||||
import DuctSequencer._
|
||||
|
||||
def apply[A](fu: => Fu[A]): Fu[A] = run(() => fu)
|
||||
|
||||
def run[A](task: Task[A]): Fu[A] = duct.ask[A](TaskWithPromise(task, _))
|
||||
|
||||
private[this] val duct = new BoundedDuct(maxSize, name, logging)({ case TaskWithPromise(task, promise) =>
|
||||
promise.completeWith {
|
||||
task()
|
||||
.withTimeout(timeout)
|
||||
.transform(
|
||||
identity,
|
||||
{
|
||||
case LilaTimeout(msg) =>
|
||||
val fullMsg = s"$name DuctSequencer $msg"
|
||||
if (logging) lila.log("duct").warn(fullMsg)
|
||||
LilaTimeout(fullMsg)
|
||||
case e => e
|
||||
}
|
||||
)
|
||||
}.future
|
||||
})
|
||||
}
|
||||
|
||||
// Distributes tasks to many sequencers
|
||||
final class DuctSequencers(
|
||||
maxSize: Int,
|
||||
expiration: FiniteDuration,
|
||||
timeout: FiniteDuration,
|
||||
name: String,
|
||||
logging: Boolean = true
|
||||
)(implicit
|
||||
system: akka.actor.ActorSystem,
|
||||
ec: ExecutionContext,
|
||||
mode: play.api.Mode
|
||||
) {
|
||||
|
||||
def apply[A](key: String)(task: => Fu[A]): Fu[A] =
|
||||
sequencers.get(key).run(() => task)
|
||||
|
||||
private val sequencers: LoadingCache[String, DuctSequencer] =
|
||||
lila.common.LilaCache
|
||||
.scaffeine(mode)
|
||||
.expireAfterAccess(expiration)
|
||||
.build(key => new DuctSequencer(maxSize, timeout, s"$name:$key", logging))
|
||||
}
|
||||
|
||||
object DuctSequencer {
|
||||
|
||||
private type Task[A] = () => Fu[A]
|
||||
private case class TaskWithPromise[A](task: Task[A], promise: Promise[A])
|
||||
}
|
|
@ -9,11 +9,10 @@ import scala.concurrent.{ ExecutionContext, Future, Promise }
|
|||
* Like an actor, but not an actor.
|
||||
* Uses an Atomic Reference backend for sequentiality.
|
||||
* Has an unbounded (!) Queue of messages.
|
||||
* Like Duct, but for synchronous message processors.
|
||||
*/
|
||||
abstract class Trouper(implicit ec: ExecutionContext) extends lila.common.Tellable {
|
||||
abstract class SyncActor(implicit ec: ExecutionContext) extends lila.common.Tellable {
|
||||
|
||||
import Trouper._
|
||||
import SyncActor._
|
||||
|
||||
// implement async behaviour here
|
||||
protected val process: Receive
|
||||
|
@ -58,7 +57,7 @@ abstract class Trouper(implicit ec: ExecutionContext) extends lila.common.Tellab
|
|||
}
|
||||
}
|
||||
|
||||
object Trouper {
|
||||
object SyncActor {
|
||||
|
||||
type Receive = PartialFunction[Any, Unit]
|
||||
|
||||
|
@ -72,7 +71,7 @@ object Trouper {
|
|||
}
|
||||
|
||||
def stub(implicit ec: ExecutionContext) =
|
||||
new Trouper {
|
||||
new SyncActor {
|
||||
val process: Receive = { case msg =>
|
||||
lila.log("trouper").warn(s"stub trouper received: $msg")
|
||||
}
|
|
@ -8,20 +8,20 @@ import scala.concurrent.duration.FiniteDuration
|
|||
import scala.concurrent.Promise
|
||||
import scala.jdk.CollectionConverters._
|
||||
|
||||
final class TrouperMap[T <: Trouper](
|
||||
mkTrouper: String => T,
|
||||
final class SyncActorMap[T <: SyncActor](
|
||||
mkActor: String => T,
|
||||
accessTimeout: FiniteDuration
|
||||
)(implicit mode: Mode) {
|
||||
|
||||
def getOrMake(id: String): T = troupers get id
|
||||
def getOrMake(id: String): T = actors get id
|
||||
|
||||
def getIfPresent(id: String): Option[T] = Option(troupers getIfPresent id)
|
||||
def getIfPresent(id: String): Option[T] = Option(actors getIfPresent id)
|
||||
|
||||
def tell(id: String, msg: Any): Unit = getOrMake(id) ! msg
|
||||
|
||||
def tellIfPresent(id: String, msg: => Any): Unit = getIfPresent(id) foreach (_ ! msg)
|
||||
|
||||
def tellAll(msg: Any) = troupers.asMap.asScala.foreach(_._2 ! msg)
|
||||
def tellAll(msg: Any) = actors.asMap.asScala.foreach(_._2 ! msg)
|
||||
|
||||
def tellIds(ids: Seq[String], msg: Any): Unit = ids foreach { tell(_, msg) }
|
||||
|
||||
|
@ -35,32 +35,32 @@ final class TrouperMap[T <: Trouper](
|
|||
def askIfPresentOrZero[A: Zero](id: String)(makeMsg: Promise[A] => Any): Fu[A] =
|
||||
askIfPresent(id)(makeMsg) dmap (~_)
|
||||
|
||||
def exists(id: String): Boolean = troupers.getIfPresent(id) != null
|
||||
def exists(id: String): Boolean = actors.getIfPresent(id) != null
|
||||
|
||||
def size: Int = troupers.estimatedSize().toInt
|
||||
def size: Int = actors.estimatedSize().toInt
|
||||
|
||||
def kill(id: String): Unit = troupers invalidate id
|
||||
def kill(id: String): Unit = actors invalidate id
|
||||
|
||||
def killAll(): Unit = troupers.invalidateAll()
|
||||
def killAll(): Unit = actors.invalidateAll()
|
||||
|
||||
def touch(id: String): Unit = troupers.getIfPresent(id).unit
|
||||
def touch(id: String): Unit = actors.getIfPresent(id).unit
|
||||
|
||||
def touchOrMake(id: String): Unit = troupers.get(id).unit
|
||||
def touchOrMake(id: String): Unit = actors.get(id).unit
|
||||
|
||||
private[this] val troupers: LoadingCache[String, T] =
|
||||
private[this] val actors: LoadingCache[String, T] =
|
||||
lila.common.LilaCache
|
||||
.caffeine(mode)
|
||||
.recordStats
|
||||
.expireAfterAccess(accessTimeout.toMillis, TimeUnit.MILLISECONDS)
|
||||
.removalListener(new RemovalListener[String, T] {
|
||||
def onRemoval(id: String, trouper: T, cause: RemovalCause): Unit =
|
||||
trouper.stop()
|
||||
def onRemoval(id: String, actor: T, cause: RemovalCause): Unit =
|
||||
actor.stop()
|
||||
})
|
||||
.build[String, T](new CacheLoader[String, T] {
|
||||
def load(id: String): T = mkTrouper(id)
|
||||
def load(id: String): T = mkActor(id)
|
||||
})
|
||||
|
||||
def monitor(name: String) = lila.mon.caffeineStats(troupers, name)
|
||||
def monitor(name: String) = lila.mon.caffeineStats(actors, name)
|
||||
|
||||
def keys: Set[String] = troupers.asMap.asScala.keySet.toSet
|
||||
def keys: Set[String] = actors.asMap.asScala.keySet.toSet
|
||||
}
|
|
@ -23,7 +23,7 @@ final private class InsightIndexer(
|
|||
) {
|
||||
|
||||
private val workQueue =
|
||||
new lila.hub.DuctSequencer(maxSize = 128, timeout = 2 minutes, name = "insightIndexer")
|
||||
new lila.hub.AsyncActorSequencer(maxSize = 128, timeout = 2 minutes, name = "insightIndexer")
|
||||
|
||||
def all(userId: User.ID): Funit =
|
||||
workQueue {
|
||||
|
|
|
@ -5,7 +5,7 @@ import lila.game.{ Pov, Source }
|
|||
final private class AbortListener(
|
||||
userRepo: lila.user.UserRepo,
|
||||
seekApi: SeekApi,
|
||||
lobbyTrouper: LobbyTrouper
|
||||
lobbyTrouper: LobbySyncActor
|
||||
)(implicit ec: scala.concurrent.ExecutionContext) {
|
||||
|
||||
def apply(pov: Pov): Funit =
|
||||
|
|
|
@ -8,7 +8,7 @@ import scala.concurrent.duration._
|
|||
import lila.common.Bus
|
||||
|
||||
final class BoardApiHookStream(
|
||||
trouper: LobbyTrouper
|
||||
trouper: LobbySyncActor
|
||||
)(implicit ec: scala.concurrent.ExecutionContext, system: ActorSystem) {
|
||||
|
||||
private case object SetOnline
|
||||
|
|
|
@ -38,11 +38,11 @@ final class Env(
|
|||
|
||||
lazy val boardApiHookStream = wire[BoardApiHookStream]
|
||||
|
||||
private lazy val lobbyTrouper = LobbyTrouper.start(
|
||||
private lazy val lobbySyncActor = LobbySyncActor.start(
|
||||
broomPeriod = 2 seconds,
|
||||
resyncIdsPeriod = 25 seconds
|
||||
) { () =>
|
||||
wire[LobbyTrouper]
|
||||
wire[LobbySyncActor]
|
||||
}
|
||||
|
||||
private lazy val abortListener = wire[AbortListener]
|
||||
|
|
|
@ -7,7 +7,7 @@ import scala.concurrent.Promise
|
|||
|
||||
import lila.game.Pov
|
||||
import lila.hub.actorApi.timeline._
|
||||
import lila.hub.Trouper
|
||||
import lila.hub.SyncActor
|
||||
import lila.i18n.defaultLang
|
||||
import lila.pool.{ PoolApi, PoolConfig }
|
||||
import lila.rating.RatingRange
|
||||
|
@ -22,7 +22,7 @@ final class LobbySocket(
|
|||
biter: Biter,
|
||||
userRepo: lila.user.UserRepo,
|
||||
remoteSocketApi: lila.socket.RemoteSocket,
|
||||
lobby: LobbyTrouper,
|
||||
lobby: LobbySyncActor,
|
||||
relationApi: lila.relation.RelationApi,
|
||||
poolApi: PoolApi,
|
||||
system: akka.actor.ActorSystem
|
||||
|
@ -35,14 +35,14 @@ final class LobbySocket(
|
|||
private var lastCounters = LobbyCounters(0, 0)
|
||||
def counters = lastCounters
|
||||
|
||||
val trouper: Trouper = new Trouper {
|
||||
val trouper: SyncActor = new SyncActor {
|
||||
|
||||
private val members = scala.collection.mutable.AnyRefMap.empty[SriStr, Member]
|
||||
private val idleSris = collection.mutable.Set[SriStr]()
|
||||
private val hookSubscriberSris = collection.mutable.Set[SriStr]()
|
||||
private val removedHookIds = new collection.mutable.StringBuilder(1024)
|
||||
|
||||
val process: Trouper.Receive = {
|
||||
val process: SyncActor.Receive = {
|
||||
|
||||
case GetMember(sri, promise) => promise success members.get(sri.value)
|
||||
|
||||
|
@ -141,7 +141,7 @@ final class LobbySocket(
|
|||
}
|
||||
|
||||
// solve circular reference
|
||||
lobby ! LobbyTrouper.SetSocket(trouper)
|
||||
lobby ! LobbySyncActor.SetSocket(trouper)
|
||||
|
||||
private val poolLimitPerSri = new lila.memo.RateLimit[SriStr](
|
||||
credits = 14,
|
||||
|
|
|
@ -9,11 +9,11 @@ import scala.concurrent.Promise
|
|||
import lila.common.config.Max
|
||||
import lila.common.{ AtMost, Bus, Every }
|
||||
import lila.game.Game
|
||||
import lila.hub.Trouper
|
||||
import lila.hub.SyncActor
|
||||
import lila.socket.Socket.{ Sri, Sris }
|
||||
import lila.user.User
|
||||
|
||||
final private class LobbyTrouper(
|
||||
final private class LobbySyncActor(
|
||||
seekApi: SeekApi,
|
||||
biter: Biter,
|
||||
gameCache: lila.game.Cached,
|
||||
|
@ -22,17 +22,17 @@ final private class LobbyTrouper(
|
|||
poolApi: lila.pool.PoolApi,
|
||||
onStart: lila.round.OnStart
|
||||
)(implicit ec: scala.concurrent.ExecutionContext)
|
||||
extends Trouper {
|
||||
extends SyncActor {
|
||||
|
||||
import LobbyTrouper._
|
||||
import LobbySyncActor._
|
||||
|
||||
private val hookRepo = new HookRepo
|
||||
|
||||
private var remoteDisconnectAllAt = DateTime.now
|
||||
|
||||
private var socket: Trouper = Trouper.stub
|
||||
private var socket: SyncActor = SyncActor.stub
|
||||
|
||||
val process: Trouper.Receive = {
|
||||
val process: SyncActor.Receive = {
|
||||
|
||||
// solve circular reference
|
||||
case SetSocket(trouper) => socket = trouper
|
||||
|
@ -194,9 +194,9 @@ final private class LobbyTrouper(
|
|||
}
|
||||
}
|
||||
|
||||
private object LobbyTrouper {
|
||||
private object LobbySyncActor {
|
||||
|
||||
case class SetSocket(trouper: Trouper)
|
||||
case class SetSocket(trouper: SyncActor)
|
||||
|
||||
private case class Tick(promise: Promise[Unit])
|
||||
|
||||
|
@ -206,7 +206,7 @@ private object LobbyTrouper {
|
|||
broomPeriod: FiniteDuration,
|
||||
resyncIdsPeriod: FiniteDuration
|
||||
)(
|
||||
makeTrouper: () => LobbyTrouper
|
||||
makeTrouper: () => LobbySyncActor
|
||||
)(implicit ec: scala.concurrent.ExecutionContext, system: akka.actor.ActorSystem) = {
|
||||
val trouper = makeTrouper()
|
||||
Bus.subscribe(trouper, "lobbyTrouper")
|
|
@ -16,7 +16,7 @@ final class PerfStatIndexer(
|
|||
) {
|
||||
|
||||
private val workQueue =
|
||||
new lila.hub.DuctSequencer(maxSize = 64, timeout = 10 seconds, name = "perfStatIndexer")
|
||||
new lila.hub.AsyncActorSequencer(maxSize = 64, timeout = 10 seconds, name = "perfStatIndexer")
|
||||
|
||||
private[perfStat] def userPerf(user: User, perfType: PerfType): Fu[PerfStat] =
|
||||
workQueue {
|
||||
|
|
|
@ -18,7 +18,7 @@ final private class GameStarter(
|
|||
|
||||
import PoolApi._
|
||||
|
||||
private val workQueue = new lila.hub.DuctSequencer(maxSize = 32, timeout = 10 seconds, name = "gameStarter")
|
||||
private val workQueue = new lila.hub.AsyncActorSequencer(maxSize = 32, timeout = 10 seconds, name = "gameStarter")
|
||||
|
||||
def apply(pool: PoolConfig, couples: Vector[MatchMaking.Couple]): Funit =
|
||||
couples.nonEmpty ?? {
|
||||
|
|
|
@ -22,7 +22,7 @@ final private class FirebasePush(
|
|||
) {
|
||||
|
||||
private val workQueue =
|
||||
new lila.hub.DuctSequencer(maxSize = 512, timeout = 10 seconds, name = "firebasePush")
|
||||
new lila.hub.AsyncActorSequencer(maxSize = 512, timeout = 10 seconds, name = "firebasePush")
|
||||
|
||||
def apply(userId: User.ID, data: => PushApi.Data): Funit =
|
||||
credentialsOpt ?? { creds =>
|
||||
|
|
|
@ -60,7 +60,7 @@ final class PuzzleApi(
|
|||
object vote {
|
||||
|
||||
private val sequencer =
|
||||
new lila.hub.DuctSequencers(
|
||||
new lila.hub.AsyncActorSequencers(
|
||||
maxSize = 16,
|
||||
expiration = 5 minutes,
|
||||
timeout = 3 seconds,
|
||||
|
|
|
@ -22,7 +22,7 @@ final private[puzzle] class PuzzleFinisher(
|
|||
import BsonHandlers._
|
||||
|
||||
private val sequencer =
|
||||
new lila.hub.DuctSequencers(
|
||||
new lila.hub.AsyncActorSequencers(
|
||||
maxSize = 64,
|
||||
expiration = 5 minutes,
|
||||
timeout = 5 seconds,
|
||||
|
|
|
@ -47,7 +47,7 @@ final class RacerApi(colls: RacerColls, selector: StormSelector, userRepo: UserR
|
|||
}
|
||||
|
||||
private val rematchQueue =
|
||||
new lila.hub.DuctSequencer(
|
||||
new lila.hub.AsyncActorSequencer(
|
||||
maxSize = 32,
|
||||
timeout = 20 seconds,
|
||||
name = "racer.rematch"
|
||||
|
|
|
@ -17,7 +17,7 @@ final class RacerLobby(api: RacerApi)(implicit ec: ExecutionContext, system: akk
|
|||
}
|
||||
|
||||
private val workQueue =
|
||||
new lila.hub.DuctSequencer(
|
||||
new lila.hub.AsyncActorSequencer(
|
||||
maxSize = 128,
|
||||
timeout = 20 seconds,
|
||||
name = "racer.lobby"
|
||||
|
|
|
@ -536,7 +536,7 @@ final class ReportApi(
|
|||
object inquiries {
|
||||
|
||||
private val workQueue =
|
||||
new lila.hub.DuctSequencer(
|
||||
new lila.hub.AsyncActorSequencer(
|
||||
maxSize = 32,
|
||||
timeout = 20 seconds,
|
||||
name = "report.inquiries"
|
||||
|
|
|
@ -2,7 +2,7 @@ package lila.room
|
|||
|
||||
import lila.chat.{ BusChan, Chat, ChatApi, ChatTimeout, UserLine }
|
||||
import lila.hub.actorApi.shutup.PublicSource
|
||||
import lila.hub.{ Trouper, TrouperMap }
|
||||
import lila.hub.{ SyncActor, SyncActorMap }
|
||||
import lila.log.Logger
|
||||
import lila.socket.RemoteSocket.{ Protocol => P, _ }
|
||||
import lila.socket.Socket.{ makeMessage, GetVersion, SocketVersion }
|
||||
|
@ -22,11 +22,11 @@ object RoomSocket {
|
|||
|
||||
final class RoomState(roomId: RoomId, send: Send)(implicit
|
||||
ec: ExecutionContext
|
||||
) extends Trouper {
|
||||
) extends SyncActor {
|
||||
|
||||
private var version = SocketVersion(0)
|
||||
|
||||
val process: Trouper.Receive = {
|
||||
val process: SyncActor.Receive = {
|
||||
case GetVersion(promise) => promise success version
|
||||
case SetVersion(v) => version = v
|
||||
case nv: NotifyVersion[_] =>
|
||||
|
@ -48,8 +48,8 @@ object RoomSocket {
|
|||
ec: ExecutionContext,
|
||||
mode: play.api.Mode
|
||||
) =
|
||||
new TrouperMap(
|
||||
mkTrouper = roomId =>
|
||||
new SyncActorMap(
|
||||
mkActor = roomId =>
|
||||
new RoomState(
|
||||
RoomId(roomId),
|
||||
send
|
||||
|
@ -58,7 +58,7 @@ object RoomSocket {
|
|||
)
|
||||
|
||||
def roomHandler(
|
||||
rooms: TrouperMap[RoomState],
|
||||
rooms: SyncActorMap[RoomState],
|
||||
chat: ChatApi,
|
||||
logger: Logger,
|
||||
publicSource: RoomId => PublicSource.type => Option[PublicSource],
|
||||
|
@ -93,7 +93,7 @@ object RoomSocket {
|
|||
}
|
||||
}: Handler) orElse minRoomHandler(rooms, logger)
|
||||
|
||||
def minRoomHandler(rooms: TrouperMap[RoomState], logger: Logger): Handler = {
|
||||
def minRoomHandler(rooms: SyncActorMap[RoomState], logger: Logger): Handler = {
|
||||
case Protocol.In.KeepAlives(roomIds) =>
|
||||
roomIds foreach { roomId =>
|
||||
rooms touchOrMake roomId.value
|
||||
|
@ -109,7 +109,7 @@ object RoomSocket {
|
|||
|
||||
private val chatMsgs = Set("message", "chat_timeout", "chat_reinstate")
|
||||
|
||||
def subscribeChat(rooms: TrouperMap[RoomState], busChan: BusChan.Select) = {
|
||||
def subscribeChat(rooms: SyncActorMap[RoomState], busChan: BusChan.Select) = {
|
||||
import lila.chat.actorApi._
|
||||
lila.common.Bus.subscribeFun(busChan(BusChan).chan, BusChan.Global.chan) {
|
||||
case ChatLine(id, line: UserLine) =>
|
||||
|
|
|
@ -84,7 +84,7 @@ final class Env(
|
|||
|
||||
private lazy val proxyDependencies =
|
||||
new GameProxy.Dependencies(gameRepo, scheduler)
|
||||
private lazy val roundDependencies = wire[RoundDuct.Dependencies]
|
||||
private lazy val roundDependencies = wire[RoundAsyncActor.Dependencies]
|
||||
|
||||
lazy val roundSocket: RoundSocket = wire[RoundSocket]
|
||||
|
||||
|
@ -159,7 +159,7 @@ final class Env(
|
|||
lazy val getSocketStatus = (game: Game) => roundSocket.rounds.ask[SocketStatus](game.id)(GetSocketStatus)
|
||||
|
||||
private def isUserPresent(game: Game, userId: lila.user.User.ID): Fu[Boolean] =
|
||||
roundSocket.rounds.askIfPresentOrZero[Boolean](game.id)(RoundDuct.HasUserId(userId, _))
|
||||
roundSocket.rounds.askIfPresentOrZero[Boolean](game.id)(RoundAsyncActor.HasUserId(userId, _))
|
||||
|
||||
lazy val jsonView = wire[JsonView]
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ private object GameProxy {
|
|||
val scheduler: Scheduler
|
||||
)
|
||||
|
||||
// must be way under the round duct termination delay (60s)
|
||||
// must be way under the round asyncActor termination delay (60s)
|
||||
private val scheduleDelay = 30.seconds
|
||||
|
||||
private val emptyCancellable = new Cancellable {
|
||||
|
|
|
@ -21,7 +21,7 @@ final private class Player(
|
|||
private case object Flagged extends MoveResult
|
||||
private case class MoveApplied(progress: Progress, move: MoveOrDrop) extends MoveResult
|
||||
|
||||
private[round] def human(play: HumanPlay, round: RoundDuct)(
|
||||
private[round] def human(play: HumanPlay, round: RoundAsyncActor)(
|
||||
pov: Pov
|
||||
)(implicit proxy: GameProxy): Fu[Events] =
|
||||
play match {
|
||||
|
@ -47,7 +47,7 @@ final private class Player(
|
|||
}
|
||||
}
|
||||
|
||||
private[round] def bot(uci: Uci, round: RoundDuct)(pov: Pov)(implicit proxy: GameProxy): Fu[Events] =
|
||||
private[round] def bot(uci: Uci, round: RoundAsyncActor)(pov: Pov)(implicit proxy: GameProxy): Fu[Events] =
|
||||
pov match {
|
||||
case Pov(game, _) if game.turns > Game.maxPlies =>
|
||||
round ! TooManyPlies
|
||||
|
@ -67,7 +67,7 @@ final private class Player(
|
|||
}
|
||||
|
||||
private def postHumanOrBotPlay(
|
||||
round: RoundDuct,
|
||||
round: RoundAsyncActor,
|
||||
pov: Pov,
|
||||
progress: Progress,
|
||||
moveOrDrop: MoveOrDrop
|
||||
|
@ -110,7 +110,7 @@ final private class Player(
|
|||
)
|
||||
)
|
||||
|
||||
private[round] def requestFishnet(game: Game, round: RoundDuct): Funit =
|
||||
private[round] def requestFishnet(game: Game, round: RoundAsyncActor): Funit =
|
||||
game.playableByAi ?? {
|
||||
if (game.turns <= fishnetPlayer.maxPlies) fishnetPlayer(game)
|
||||
else fuccess(round ! actorApi.round.ResignAi)
|
||||
|
|
|
@ -21,23 +21,23 @@ import lila.hub.actorApi.round.{
|
|||
RematchYes,
|
||||
Resign
|
||||
}
|
||||
import lila.hub.Duct
|
||||
import lila.hub.AsyncActor
|
||||
import lila.room.RoomSocket.{ Protocol => RP, _ }
|
||||
import lila.socket.Socket.{ makeMessage, GetVersion, SocketVersion }
|
||||
import lila.socket.UserLagCache
|
||||
import lila.user.User
|
||||
|
||||
final private[round] class RoundDuct(
|
||||
dependencies: RoundDuct.Dependencies,
|
||||
final private[round] class RoundAsyncActor(
|
||||
dependencies: RoundAsyncActor.Dependencies,
|
||||
gameId: Game.ID,
|
||||
socketSend: String => Unit
|
||||
)(implicit
|
||||
ec: scala.concurrent.ExecutionContext,
|
||||
proxy: GameProxy
|
||||
) extends Duct {
|
||||
) extends AsyncActor {
|
||||
|
||||
import RoundSocket.Protocol
|
||||
import RoundDuct._
|
||||
import RoundAsyncActor._
|
||||
import dependencies._
|
||||
|
||||
private var takebackSituation: Option[TakebackSituation] = None
|
||||
|
@ -109,7 +109,7 @@ final private[round] class RoundDuct(
|
|||
def getGame: Fu[Option[Game]] = proxy.game
|
||||
def updateGame(f: Game => Game): Funit = proxy update f
|
||||
|
||||
val process: Duct.ReceiveAsync = {
|
||||
val process: AsyncActor.ReceiveAsync = {
|
||||
|
||||
case SetGameInfo(game, (whiteGoneWeight, blackGoneWeight)) =>
|
||||
fuccess {
|
||||
|
@ -541,7 +541,7 @@ final private[round] class RoundDuct(
|
|||
def roomId = RoomId(gameId)
|
||||
}
|
||||
|
||||
object RoundDuct {
|
||||
object RoundAsyncActor {
|
||||
|
||||
case class HasUserId(userId: User.ID, promise: Promise[Boolean])
|
||||
case class SetGameInfo(game: lila.game.Game, goneWeights: (Float, Float))
|
|
@ -17,7 +17,7 @@ import lila.hub.actorApi.map.{ Exists, Tell, TellAll, TellIfExists, TellMany }
|
|||
import lila.hub.actorApi.round.{ Abort, Berserk, RematchNo, RematchYes, Resign, TourStanding }
|
||||
import lila.hub.actorApi.socket.remote.TellSriIn
|
||||
import lila.hub.actorApi.tv.TvSelect
|
||||
import lila.hub.DuctConcMap
|
||||
import lila.hub.AsyncActorConcMap
|
||||
import lila.room.RoomSocket.{ Protocol => RP, _ }
|
||||
import lila.socket.RemoteSocket.{ Protocol => P, _ }
|
||||
import lila.socket.Socket.{ makeMessage, SocketVersion }
|
||||
|
@ -25,7 +25,7 @@ import lila.user.User
|
|||
|
||||
final class RoundSocket(
|
||||
remoteSocketApi: lila.socket.RemoteSocket,
|
||||
roundDependencies: RoundDuct.Dependencies,
|
||||
roundDependencies: RoundAsyncActor.Dependencies,
|
||||
proxyDependencies: GameProxy.Dependencies,
|
||||
scheduleExpiration: ScheduleExpiration,
|
||||
tournamentActor: lila.hub.actors.TournamentApi,
|
||||
|
@ -43,8 +43,8 @@ final class RoundSocket(
|
|||
|
||||
Lilakka.shutdown(shutdown, _.PhaseServiceUnbind, "Stop round socket") { () =>
|
||||
stopping = true
|
||||
rounds.tellAllWithAck(RoundDuct.LilaStop.apply) map { nb =>
|
||||
Lilakka.logger.info(s"$nb round ducts have stopped")
|
||||
rounds.tellAllWithAck(RoundAsyncActor.LilaStop.apply) map { nb =>
|
||||
Lilakka.logger.info(s"$nb round asyncActors have stopped")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,24 +69,24 @@ final class RoundSocket(
|
|||
_ updateGame f
|
||||
}
|
||||
|
||||
val rounds = new DuctConcMap[RoundDuct](
|
||||
mkDuct = id => {
|
||||
val rounds = new AsyncActorConcMap[RoundAsyncActor](
|
||||
mkAsyncActor = id => {
|
||||
val proxy = new GameProxy(id, proxyDependencies)
|
||||
val duct = new RoundDuct(
|
||||
val asyncActor = new RoundAsyncActor(
|
||||
dependencies = roundDependencies,
|
||||
gameId = id,
|
||||
socketSend = sendForGameId(id)
|
||||
)(ec, proxy)
|
||||
terminationDelay schedule Game.Id(id)
|
||||
duct.getGame dforeach {
|
||||
asyncActor.getGame dforeach {
|
||||
_ foreach { game =>
|
||||
scheduleExpiration(game)
|
||||
goneWeightsFor(game) dforeach { w =>
|
||||
duct ! RoundDuct.SetGameInfo(game, w)
|
||||
asyncActor ! RoundAsyncActor.SetGameInfo(game, w)
|
||||
}
|
||||
}
|
||||
}
|
||||
duct
|
||||
asyncActor
|
||||
},
|
||||
initialCapacity = 65536
|
||||
)
|
||||
|
@ -150,16 +150,16 @@ final class RoundSocket(
|
|||
case P.In.Ping(id) => send(P.Out.pong(id))
|
||||
case P.In.WsBoot =>
|
||||
logger.warn("Remote socket boot")
|
||||
// schedule termination for all game ducts
|
||||
// schedule termination for all game asyncActors
|
||||
// until players actually reconnect
|
||||
rounds foreachKey { id =>
|
||||
terminationDelay schedule Game.Id(id)
|
||||
}
|
||||
rounds.tellAll(RoundDuct.WsBoot)
|
||||
rounds.tellAll(RoundAsyncActor.WsBoot)
|
||||
}
|
||||
|
||||
private def finishRound(gameId: Game.Id): Unit =
|
||||
rounds.terminate(gameId.value, _ ! RoundDuct.Stop)
|
||||
rounds.terminate(gameId.value, _ ! RoundAsyncActor.Stop)
|
||||
|
||||
private lazy val send: Sender = remoteSocketApi.makeSender("r-out", parallelism = 8)
|
||||
|
||||
|
@ -204,10 +204,10 @@ final class RoundSocket(
|
|||
}
|
||||
|
||||
system.scheduler.scheduleWithFixedDelay(25 seconds, tickInterval) { () =>
|
||||
rounds.tellAll(RoundDuct.Tick)
|
||||
rounds.tellAll(RoundAsyncActor.Tick)
|
||||
}
|
||||
system.scheduler.scheduleWithFixedDelay(60 seconds, 60 seconds) { () =>
|
||||
lila.mon.round.ductCount.update(rounds.size).unit
|
||||
lila.mon.round.asyncActorCount.update(rounds.size).unit
|
||||
}
|
||||
|
||||
private val terminationDelay = new TerminationDelay(system.scheduler, 1 minute, finishRound)
|
||||
|
|
|
@ -5,7 +5,7 @@ import lila.common.Bus
|
|||
import lila.game.{ Event, Game, GameRepo, Pov, Progress, Rewind, UciMemo }
|
||||
import lila.pref.{ Pref, PrefApi }
|
||||
import lila.i18n.{ I18nKeys => trans, defaultLang }
|
||||
import RoundDuct.TakebackSituation
|
||||
import RoundAsyncActor.TakebackSituation
|
||||
|
||||
final private class Takebacker(
|
||||
messenger: Messenger,
|
||||
|
|
|
@ -30,7 +30,7 @@ final class SimulApi(
|
|||
) {
|
||||
|
||||
private val workQueue =
|
||||
new lila.hub.DuctSequencers(
|
||||
new lila.hub.AsyncActorSequencers(
|
||||
maxSize = 128,
|
||||
expiration = 10 minutes,
|
||||
timeout = 10 seconds,
|
||||
|
|
|
@ -3,7 +3,7 @@ package lila.study
|
|||
import ornicar.scalalib.Zero
|
||||
import scala.concurrent.duration._
|
||||
|
||||
import lila.hub.DuctSequencers
|
||||
import lila.hub.AsyncActorSequencers
|
||||
|
||||
final private class StudySequencer(
|
||||
studyRepo: StudyRepo,
|
||||
|
@ -15,7 +15,7 @@ final private class StudySequencer(
|
|||
) {
|
||||
|
||||
private val workQueue =
|
||||
new DuctSequencers(maxSize = 64, expiration = 1 minute, timeout = 10 seconds, name = "study")
|
||||
new AsyncActorSequencers(maxSize = 64, expiration = 1 minute, timeout = 10 seconds, name = "study")
|
||||
|
||||
def sequenceStudy[A: Zero](studyId: Study.Id)(f: Study => Fu[A]): Fu[A] =
|
||||
workQueue(studyId.value) {
|
||||
|
|
|
@ -140,7 +140,7 @@ final class StudyTopicApi(topicRepo: StudyTopicRepo, userTopicRepo: StudyUserTop
|
|||
private def docTopic(doc: Bdoc): Option[StudyTopic] =
|
||||
doc.getAsOpt[StudyTopic]("_id")
|
||||
|
||||
private val recomputeWorkQueue = new lila.hub.DuctSequencer(
|
||||
private val recomputeWorkQueue = new lila.hub.AsyncActorSequencer(
|
||||
maxSize = 1,
|
||||
timeout = 61 seconds,
|
||||
name = "studyTopicAggregation",
|
||||
|
@ -149,7 +149,7 @@ final class StudyTopicApi(topicRepo: StudyTopicRepo, userTopicRepo: StudyUserTop
|
|||
|
||||
def recompute(): Unit =
|
||||
recomputeWorkQueue(Future.makeItLast(60 seconds)(recomputeNow)).recover {
|
||||
case _: lila.hub.BoundedDuct.EnqueueException => ()
|
||||
case _: lila.hub.BoundedAsyncActor.EnqueueException => ()
|
||||
case e: Exception => logger.warn("Can't recompute study topics!", e)
|
||||
}.unit
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ final class SwissApi(
|
|||
) {
|
||||
|
||||
private val sequencer =
|
||||
new lila.hub.DuctSequencers(
|
||||
new lila.hub.AsyncActorSequencers(
|
||||
maxSize = 1024, // queue many game finished events
|
||||
expiration = 20 minutes,
|
||||
timeout = 10 seconds,
|
||||
|
|
|
@ -48,7 +48,7 @@ final class TournamentApi(
|
|||
) {
|
||||
|
||||
private val workQueue =
|
||||
new lila.hub.DuctSequencers(
|
||||
new lila.hub.AsyncActorSequencers(
|
||||
maxSize = 256,
|
||||
expiration = 1 minute,
|
||||
timeout = 10 seconds,
|
||||
|
|
|
@ -6,18 +6,18 @@ import scala.concurrent.Promise
|
|||
|
||||
import lila.common.LightUser
|
||||
import lila.game.Game
|
||||
import lila.hub.Trouper
|
||||
import lila.hub.SyncActor
|
||||
|
||||
final private[tv] class ChannelTrouper(
|
||||
final private[tv] class ChannelSyncActor(
|
||||
channel: Tv.Channel,
|
||||
onSelect: TvTrouper.Selected => Unit,
|
||||
onSelect: TvSyncActor.Selected => Unit,
|
||||
proxyGame: Game.ID => Fu[Option[Game]],
|
||||
rematchOf: Game.ID => Option[Game.ID],
|
||||
lightUserSync: LightUser.GetterSync
|
||||
)(implicit ec: scala.concurrent.ExecutionContext)
|
||||
extends Trouper {
|
||||
extends SyncActor {
|
||||
|
||||
import ChannelTrouper._
|
||||
import ChannelSyncActor._
|
||||
|
||||
// games featured on this channel
|
||||
// first entry is the current game
|
||||
|
@ -30,7 +30,7 @@ final private[tv] class ChannelTrouper(
|
|||
|
||||
private val candidateIds = new lila.memo.ExpireSetMemo(3 minutes)
|
||||
|
||||
protected val process: Trouper.Receive = {
|
||||
protected val process: SyncActor.Receive = {
|
||||
|
||||
case GetGameId(promise) => promise success oneId
|
||||
|
||||
|
@ -39,10 +39,10 @@ final private[tv] class ChannelTrouper(
|
|||
case GetGameIds(max, promise) => promise success manyIds.take(max)
|
||||
|
||||
case SetGame(game) =>
|
||||
onSelect(TvTrouper.Selected(channel, game))
|
||||
onSelect(TvSyncActor.Selected(channel, game))
|
||||
history = game.id :: history.take(2)
|
||||
|
||||
case TvTrouper.Select =>
|
||||
case TvSyncActor.Select =>
|
||||
candidateIds.keys
|
||||
.map(proxyGame)
|
||||
.sequenceFu
|
||||
|
@ -110,7 +110,7 @@ final private[tv] class ChannelTrouper(
|
|||
.flatMap(Tv.titleScores.get)
|
||||
}
|
||||
|
||||
object ChannelTrouper {
|
||||
object ChannelSyncActor {
|
||||
|
||||
case class GetGameId(promise: Promise[Option[Game.ID]])
|
||||
case class GetGameIds(max: Int, promise: Promise[List[Game.ID]])
|
|
@ -15,11 +15,11 @@ final class Env(
|
|||
rematches: lila.game.Rematches
|
||||
)(implicit ec: scala.concurrent.ExecutionContext) {
|
||||
|
||||
private val tvTrouper = wire[TvTrouper]
|
||||
private val tvSyncActor = wire[TvSyncActor]
|
||||
|
||||
lazy val tv = wire[Tv]
|
||||
|
||||
system.scheduler.scheduleWithFixedDelay(12 seconds, 3 seconds) { () =>
|
||||
tvTrouper ! TvTrouper.Select
|
||||
tvSyncActor ! TvSyncActor.Select
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,24 +2,24 @@ package lila.tv
|
|||
|
||||
import lila.common.LightUser
|
||||
import lila.game.{ Game, GameRepo, Pov }
|
||||
import lila.hub.Trouper
|
||||
import lila.hub.SyncActor
|
||||
|
||||
final class Tv(
|
||||
gameRepo: GameRepo,
|
||||
trouper: Trouper,
|
||||
trouper: SyncActor,
|
||||
gameProxyRepo: lila.round.GameProxyRepo
|
||||
)(implicit ec: scala.concurrent.ExecutionContext) {
|
||||
|
||||
import Tv._
|
||||
import ChannelTrouper._
|
||||
import ChannelSyncActor._
|
||||
|
||||
private def roundProxyGame = gameProxyRepo.game _
|
||||
|
||||
def getGame(channel: Tv.Channel): Fu[Option[Game]] =
|
||||
trouper.ask[Option[Game.ID]](TvTrouper.GetGameId(channel, _)) flatMap { _ ?? roundProxyGame }
|
||||
trouper.ask[Option[Game.ID]](TvSyncActor.GetGameId(channel, _)) flatMap { _ ?? roundProxyGame }
|
||||
|
||||
def getGameAndHistory(channel: Tv.Channel): Fu[Option[(Game, List[Pov])]] =
|
||||
trouper.ask[GameIdAndHistory](TvTrouper.GetGameIdAndHistory(channel, _)) flatMap {
|
||||
trouper.ask[GameIdAndHistory](TvSyncActor.GetGameIdAndHistory(channel, _)) flatMap {
|
||||
case GameIdAndHistory(gameId, historyIds) =>
|
||||
for {
|
||||
game <- gameId ?? roundProxyGame
|
||||
|
@ -40,14 +40,14 @@ final class Tv(
|
|||
}
|
||||
|
||||
def getGameIds(channel: Tv.Channel, max: Int): Fu[List[Game.ID]] =
|
||||
trouper.ask[List[Game.ID]](TvTrouper.GetGameIds(channel, max, _))
|
||||
trouper.ask[List[Game.ID]](TvSyncActor.GetGameIds(channel, max, _))
|
||||
|
||||
def getBestGame = getGame(Tv.Channel.Best) orElse gameRepo.random
|
||||
|
||||
def getBestAndHistory = getGameAndHistory(Tv.Channel.Best)
|
||||
|
||||
def getChampions: Fu[Champions] =
|
||||
trouper.ask[Champions](TvTrouper.GetChampions.apply)
|
||||
trouper.ask[Champions](TvSyncActor.GetChampions.apply)
|
||||
}
|
||||
|
||||
object Tv {
|
||||
|
|
|
@ -7,23 +7,23 @@ import scala.concurrent.Promise
|
|||
|
||||
import lila.common.{ Bus, LightUser }
|
||||
import lila.game.{ Game, Pov }
|
||||
import lila.hub.Trouper
|
||||
import lila.hub.SyncActor
|
||||
|
||||
final private[tv] class TvTrouper(
|
||||
final private[tv] class TvSyncActor(
|
||||
renderer: lila.hub.actors.Renderer,
|
||||
lightUserSync: LightUser.GetterSync,
|
||||
recentTvGames: lila.round.RecentTvGames,
|
||||
gameProxyRepo: lila.round.GameProxyRepo,
|
||||
rematches: lila.game.Rematches
|
||||
)(implicit ec: scala.concurrent.ExecutionContext)
|
||||
extends Trouper {
|
||||
extends SyncActor {
|
||||
|
||||
import TvTrouper._
|
||||
import TvSyncActor._
|
||||
|
||||
Bus.subscribe(this, "startGame")
|
||||
|
||||
private val channelTroupers: Map[Tv.Channel, ChannelTrouper] = Tv.Channel.all.map { c =>
|
||||
c -> new ChannelTrouper(c, onSelect = this.!, gameProxyRepo.game, rematches.of, lightUserSync)
|
||||
private val channelTroupers: Map[Tv.Channel, ChannelSyncActor] = Tv.Channel.all.map { c =>
|
||||
c -> new ChannelSyncActor(c, onSelect = this.!, gameProxyRepo.game, rematches.of, lightUserSync)
|
||||
}.toMap
|
||||
|
||||
private var channelChampions = Map[Tv.Channel, Tv.Champion]()
|
||||
|
@ -31,16 +31,16 @@ final private[tv] class TvTrouper(
|
|||
private def forward[A](channel: Tv.Channel, msg: Any) =
|
||||
channelTroupers get channel foreach { _ ! msg }
|
||||
|
||||
protected val process: Trouper.Receive = {
|
||||
protected val process: SyncActor.Receive = {
|
||||
|
||||
case GetGameId(channel, promise) =>
|
||||
forward(channel, ChannelTrouper.GetGameId(promise))
|
||||
forward(channel, ChannelSyncActor.GetGameId(promise))
|
||||
|
||||
case GetGameIdAndHistory(channel, promise) =>
|
||||
forward(channel, ChannelTrouper.GetGameIdAndHistory(promise))
|
||||
forward(channel, ChannelSyncActor.GetGameIdAndHistory(promise))
|
||||
|
||||
case GetGameIds(channel, max, promise) =>
|
||||
forward(channel, ChannelTrouper.GetGameIds(max, promise))
|
||||
forward(channel, ChannelSyncActor.GetGameIds(max, promise))
|
||||
|
||||
case GetChampions(promise) => promise success Tv.Champions(channelChampions)
|
||||
|
||||
|
@ -52,7 +52,7 @@ final private[tv] class TvTrouper(
|
|||
} foreach (_ addCandidate g)
|
||||
}
|
||||
|
||||
case s @ TvTrouper.Select => channelTroupers.foreach(_._2 ! s)
|
||||
case s @ TvSyncActor.Select => channelTroupers.foreach(_._2 ! s)
|
||||
|
||||
case Selected(channel, game) =>
|
||||
import lila.socket.Socket.makeMessage
|
||||
|
@ -99,12 +99,12 @@ final private[tv] class TvTrouper(
|
|||
}
|
||||
}
|
||||
|
||||
private[tv] object TvTrouper {
|
||||
private[tv] object TvSyncActor {
|
||||
|
||||
case class GetGameId(channel: Tv.Channel, promise: Promise[Option[Game.ID]])
|
||||
case class GetGameIds(channel: Tv.Channel, max: Int, promise: Promise[List[Game.ID]])
|
||||
|
||||
case class GetGameIdAndHistory(channel: Tv.Channel, promise: Promise[ChannelTrouper.GameIdAndHistory])
|
||||
case class GetGameIdAndHistory(channel: Tv.Channel, promise: Promise[ChannelSyncActor.GameIdAndHistory])
|
||||
|
||||
case object Select
|
||||
case class Selected(channel: Tv.Channel, game: Game)
|
Loading…
Reference in New Issue