I need to filter my flow based on some blacklist which can be changed outside of the flow execution. So, I see two option to do that:
Encapsulate blacklist in a separate service
class Blacklist(init: Set[String]) {
@volatile private var set: Set[String] = init
def get: Set[String] = set
def update(newSet: Set[String]): Unit = {
set = newSet
}
}
val blacklist = new Blacklist(Set.empty)
Flow[String]
.filterNot(blacklist.get)
Encapsulate blacklist in an actor
class Blacklist extends Actor {
import Blacklist._
private var set = Set.empty[String]
override def receive: Receive = {
case UpdateBlacklist(newset: Set[String]) =>
set = newset
case GetBlacklist =>
sender ! set
}
}
object Blacklist {
case class UpdateBlacklist(set: Set[String])
case object GetBlacklist
}
val parallelism: Int = ???
val blacklist = system.actorOf(Props(new Blacklist()))
Flow[String]
.mapAsync(parallelism) { str =>
val ask = blacklist ? Blacklist.GetBlacklist
ask.mapTo[Set[String]] map { str -> _ }
} filterNot { case (str, exclude) =>
exclude(str)
}
I’m afraid that actor holder solution with mapAsync introduce new asynchronous boundary which prevents operators fusing. So, which one should I prefer? Or is there a more idiomatic way?