68 lines
1.8 KiB
Scala
68 lines
1.8 KiB
Scala
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])
|
|
}
|