Looking for something like a TestFlow analogous to TestSink and TestSource - scala

I am writing a class that takes a Flow (representing a kind of socket) as a constructor argument and that allows to send messages and wait for the respective answers asynchronously by returning a Future. Example:
class SocketAdapter(underlyingSocket: Flow[String, String, _]) {
def sendMessage(msg: MessageType): Future[ResponseType]
}
This is not necessarily trivial because there may be other messages in the socket stream that are irrelevant, so some filtering is required.
In order to test the class I need to provide something like a "TestFlow" analogous to TestSink and TestSource. In fact I can create a flow by combining both. However, the problem is that I only obtain the actual probes upon materialization and materialization happens inside the class under test.
The problem is similar to the one I described in this question. My problem would be solved if I could materialize the flow first and then pass it to a client to connect to it. Again, I'm thinking about using MergeHub and BroadcastHub and again I see the problem that the resulting stream would behave differently because it is not linear anymore.
Maybe I misunderstood how a Flow is supposed to be used. In order to feed messages into the flow when sendMessage() is called, I need a certain kind of Source anyway. Maybe a Source.actorRef(...) or Source.queue(...), so I could pass in the ActorRef or SourceQueue directly. However, I'd prefer if this choice was up to the SocketAdapter class. Of course, this applies to the Sink as well.
It feels like this is a rather common case when working with streams and sockets. If it is not possible to create a "TestFlow" like I need it, I'm also happy with some advice on how to improve my design and make it better testable.
Update: I browsed through the documentation and found SourceRef and SinkRef. It looks like these could solve my problem but I'm not sure yet. Is it reasonable to use them in my case or are there any drawbacks, e.g. different behaviour in the test compared to production where there are no such refs?

Indirect Answer
The nature of your question suggests a design flaw which you are bumping into at testing time. The answer below does not address the issue in your question, but it demonstrates how to avoid the situation altogether.
Don't Mix Business Logic with Akka Code
Presumably you need to test your Flow because you have mixed a substantial amount of logic into the materialization. Lets assume you are using raw sockets for your IO. Your question suggests that your flow looks like:
val socketFlow : Flow[String, String, _] = {
val socket = new Socket(...)
//business logic for IO
}
You need a complicated test framework for your Flow because your Flow itself is also complicated.
Instead, you should separate out the logic into an independent function that has no akka dependencies:
type MessageProcessor = MessageType => ResponseType
object BusinessLogic {
val createMessageProcessor : (Socket) => MessageProcessor = {
//business logic for IO
}
}
Now your flow can be very simple:
val socket : Socket = new Socket(...)
val socketFlow = Flow.map(BusinessLogic.createMessageProcessor(socket))
As a result: your unit testing can exclusively work with createMessageProcessor, there's no need to test akka Flow because it is a simple veneer around the complicated logic that is tested independently.
Don't Use Streams For Concurrency Around 1 Element
The other big problem with your design is that SocketAdapter is using a stream to process just 1 message at a time. This is incredibly wasteful and unnecessary (you're trying to kill a mosquito with a tank).
Given the separated business logic your adapter becomes much simpler and independent of akka:
class SocketAdapter(messageProcessor : MessageProcessor) {
def sendMessage(msg: MessageType): Future[ResponseType] = Future {
messageProcessor(msg)
}
}
Note how easy it is to use Future in some instances and Flow in other scenarios depending on the need. This comes from the fact that the business logic is independent of any concurrency framework.

This is what I came up with using SinkRef and SourceRef:
object TestFlow {
def withProbes[In, Out](implicit actorSystem: ActorSystem,
actorMaterializer: ActorMaterializer)
:(Flow[In, Out, _], TestSubscriber.Probe[In], TestPublisher.Probe[Out]) = {
val f = Flow.fromSinkAndSourceMat(TestSink.probe[In], TestSource.probe[Out])
(Keep.both)
val ((sinkRefFuture, (inProbe, outProbe)), sourceRefFuture) =
StreamRefs.sinkRef[In]()
.viaMat(f)(Keep.both)
.toMat(StreamRefs.sourceRef[Out]())(Keep.both)
.run()
val sinkRef = Await.result(sinkRefFuture, 3.seconds)
val sourceRef = Await.result(sourceRefFuture, 3.seconds)
(Flow.fromSinkAndSource(sinkRef, sourceRef), inProbe, outProbe)
}
}
This gives me a flow I can completely control with the two probes but I can pass it to a client that connects source and sink later, so it seems to solve my problem.
The resulting Flow should only be used once, so it differs from a regular Flow that is rather a flow blueprint and can be materialized several times. However, this restriction applies to the web socket flow I am mocking anyway, as described here.
The only issue I still have is that some warnings are logged when the ActorSystem terminates after the test. This seems to be due to the indirection introduced by the SinkRef and SourceRef.
Update: I found a better solution without SinkRef and SourceRef by using mapMaterializedValue():
def withProbesFuture[In, Out](implicit actorSystem: ActorSystem,
ec: ExecutionContext)
: (Flow[In, Out, _],
Future[(TestSubscriber.Probe[In], TestPublisher.Probe[Out])]) = {
val (sinkPromise, sourcePromise) =
(Promise[TestSubscriber.Probe[In]], Promise[TestPublisher.Probe[Out]])
val flow =
Flow
.fromSinkAndSourceMat(TestSink.probe[In], TestSource.probe[Out])(Keep.both)
.mapMaterializedValue { case (inProbe, outProbe) =>
sinkPromise.success(inProbe)
sourcePromise.success(outProbe)
()
}
val probeTupleFuture = sinkPromise.future
.flatMap(sink => sourcePromise.future.map(source => (sink, source)))
(flow, probeTupleFuture)
}
When the class under test materializes the flow, the Future is completed and I receive the test probes.

Related

using streams vs actors for periodic tasks

Im working with akka/scala/play stack.
Usually, im using stream to perform certain tasks. for example, I have a stream that wakes every minute, picks up something from the DB, and call another service to enrich its data using an API and save the enrichment to the DB.
something like this:
class FetcherAndSaveStream #Inject()(fetcherAndSaveGraph: FetcherAndSaveGraph, dbElementsSource: DbElementsSource)
(implicit val mat: Materializer,
implicit val exec: ExecutionContext) extends LazyLogging {
def graph[M1, M2](source: Source[BDElement, M1],
sink: Sink[BDElement, M2],
switch: SharedKillSwitch): RunnableGraph[(M1, M2)] = {
val fetchAndSaveDataFromExternalService: Flow[BDElement, BDElement, NotUsed] =
fetcherAndSaveGraph.fetchEndSaveEnrichment
source.viaMat(switch.flow)(Keep.left)
.via(fetchAndSaveDataFromExternalService)
.toMat(sink)(Keep.both).withAttributes(supervisionStrategy(resumingDecider))
}
def runGraph(switchSharedKill: SharedKillSwitch): (NotUsed, Future[Done]) = {
logger.info("FetcherAndSaveStream is now running")
graph(dbElementsSource.dbElements(), Sink.ignore, switchSharedKill).run()
}
}
I wonder, is this better than just using an actor that ticks every minute and do something like that? what is the comparison between using actors for this and stream?
trying to figure out still when should I choose which method (streams/actors). thanks!!
You can use both, depending on the requirements you have for your solution which are not listed there. The general concern you need to take into consideration - actors more low-level stuff than streams, so they require more code and debug.
Basically, streams are good for tasks where you have a relatively big amount of data you need to process with low memory consumption. With streams, you won't need to start to stream each n seconds, you can set this stream to run along with the application. That could make your code more concise by omitting scheduler logic.
I will omit your DI and architecture stuff, write solution with pseudocode:
val yourConsumer: Sink[YourDBRecord] = ???
val recordsSource: Source[YourDBRecord] =
val runnableGraph = (Source repeat ())
.throttle(1, n seconds)
.mapAsync(yourParallelism){_ =>
fetchReasonableAmountOfRecordsFromDB
} mapConcat identity to yourConsumer
This stream will do your stuff. You even can enhance it with more sophisticated logic to adapt the polling rate according to workloads using feedback loop in graph api. Also, you can add the error-handling strategy you need to resume in place your stream has crashed.
Moreover, there's alpakka connectors for DBS capable of doing so, you can see if solutions there fit your purpose, or check for implementation details.
What you can get by doing so - backpressure, ability to work with streams, clean and concise code with no timed automata managed directly by you.
https://doc.akka.io/docs/akka/current/stream/stream-rate.html
You can also create an actor, but then you should do all the things akka streams do for you by hand, i.e. back-pressure in case you want to interop with streams, scheduler, chunking and memory management(to not to load 100000 or so entries in one batch to memory), etc.

How to enforce a contract through an hidden/internal state while being purely functional?

Use case
Visitors of a website can send me an email by providing their email address and message. To avoid spams, only 2 emails per minute (arbitrary) are allowed before being rate-limited.
Note that this is a learning exercise for me to get more used to functional programming practices so while that might seem overkill, it's a step for me to extend this to more complex systems.
Implementation
To do so, the ContactMailer class I have so far exposes a single method, send, which sends an email based on provided info. It handles all of preparing the mailer/email, enforcing the rate-limit contract, and actually sending the email (using courier):
import courier._, Defaults._
import scala.collection.mutable.Queue
import scala.concurrent.Future
case class ContactMailer(host: String, port: Int, username: String, password: String) {
private val mailer = Mailer(host, port).auth(true).as(username, password).startTtls(true)()
private val envelope = Envelope.from("no-reply" `#` "example.com").to("astorije" `#` "example.com")
private val queue = Queue[Long]()
def send(from: String, subject: String, content: String): Future[String] = {
val now = System.currentTimeMillis()
// If queue is full and oldest known message is < 1 minute ago, rate
// limit, otherwise send email, drop oldest known timestamp and enqueue
// the new one
if (queue.length == 2) {
val oldest = queue.head
if (now - oldest < 60 * 1000) return Future("message rate limited")
else queue.dequeue()
}
queue.enqueue(now)
mailer(envelope.replyTo(from.addr).subject(subject).content(Text(content)))
.map(_ => "message delivered")
.recover { case ex => s"message failed: ${ex}" }
}
}
And consumer (another part of the application) calls it like this:
scala> val mailer = ContactMailer("smtp.example.com", 25, "username", "password")
mailer: ContactMailer = ContactMailer(smtp.example.com,25,username,password)
scala> mailer.send("foo#bar.com", "One", "...").foreach(println(_))
message delivered
scala> mailer.send("foo#bar.com", "Two", "...").foreach(println(_))
message delivered
scala> mailer.send("foo#bar.com", "Three", "...").foreach(println(_))
message rate limited
Problem
Perfect, it works. But because I have learned and exclusively used OOP so far, this has all its characteristics: a mutable state, side effects, no referential transparency as calling multiple times with the same inputs can result in different outputs, etc.
How can I keep this rate-limit in a purely functional programming style?
If I extract this internal state (the timestamp queue) outside of the mailer and request the consumer to provide it such as def send(previousQueue: Queue[Long], from: String, ...): (Queue[Long], Future[String]), how can I ensure that the consumer will always respect this rate limit and not send an empty queue to never be rate-limited?
Is there a way to keep ContactMailer focused on what it should do (send an email), and extract this rate limiting into a less specialized layer (a generic rate limiter, whatever it is trying to limit)? Is it agood idea in the first place?
I read about a lot of generic approaches for this, and still don't know what to choose from: IO monad? State monad? Free monad? Actor system? It seems to me the last one would only shift the problem and be inappropriate in this limited context.
In general, what would be a good structure for this use case in an FP manner?
In general, I do not know how to approach this. There are a lot of resources out there, but they are either too simplistic and explain the basics that can hardly apply in a real-world situation, or too abstract and theoretical for my little experience to translate them into this example.
I obviously have complete freedom to update the signature of the class(es)/function(s) since I control the whole sequence of operations myself.
I hope this will not be flagged as opinion-based. I understand why it would feel that way, but I am actually stuck on how to get to a better, concrete implementation. :)
Your system has two interactions with the outside world, sending emails and rate-limiting actions based on time. Both of these interactions have side effects.
The simplest way to model these would be as external services is using the IO monad.
// Assuming sending email cannot fail, IO[Either[EmailError, Unit]] otherwise
def sendEmail(email: Email): IO[Unit]
def rateLimit(): IO[Boolean]
Your implementation now simply "combines" these two:
case object RateLimitReached
def mySend(email: Email): IO[Either[RateLimitReached.type, Unit]] =
for {
token <- rateLimit()
result <- if (token)
IO(Left(RateLimitReached))
else
sendEmail(email).map(Right)
} yield result
If you call runAsync (assuming you use cats.effect.IO) on the result of mySend right away you might as well use Future instead of IO, the two will be equivalent for all intent and purposes.
How can I keep this rate-limit in a purely functional programming style?
Rate limiting is reading the time (a side effect) and mutating a local counter. You could do the latter with a State monad, but that would IMO be over engineered in Scala.
I read about a lot of generic approaches for this, and still don't know what to choose from: IO monad? State monad? Free monad? Actor system? It seems to me the last one would only shift the problem and be inappropriate in this limited context.
IO is the default answer. Actors are based on the Any => Unit function type, so if you like purity and type safety you are not going to be friend with actors. The main benefit of Free vs IO is to be able to get more precise type signature. Returning IO[Result] means you could be doing anything inside, with Free you could be as precise as you like:
def sendEmail(email: Email): Free[EmailEffect, Unit]
def rateLimit(): Free[ReadTheTime, Boolean]
// | |
// list of side effect |
// return type
type MyEffect[X] = Either[EmailEffect[X], ReadTheTime[X]]
def mySend(email: Email): Free[MyEffect, Either[RateLimitReached.type, Unit]] =
But that extra level of indirection comes with some complexity, and a lot of boilerplate because in the end everything still needs to be interpreted to an IO[Either[RateLimitReached.type, Unit]].

Scala/akka discrete event simulation

I am considering migrating a large code base to Scala and leveraging the Akka Actor model. I am running into the following conceptual issue almost immediately:
In the existing code base, business logic is tested using a discrete event simulation (DES) like SimPy with deterministic results. While the real-time program runs for hous, the DES takes a few minutes. The real time system can be asynchronous and need not follow the exact ordering of the testing setup. I'd like to leverage the same Akka code for both the testing setup and the real-time setup. Can this be achieved in Scala + Akka?
I have toyed with the idea of a central message queue Actor -- but feel this is not the correct approach.
A general approach to solving the problem you stated is to isolate your "business logic" from Akka code. This allows the business code to be unit tested, and event tested, independently of Akka which also allows you to write very lean Akka code.
As an example, say you're business logic is to process some Data:
object BusinessLogic {
type Data = ???
type Result = ???
def processData(data : Data) : Result = ???
}
This is a clean implementation that can be run in any concurrency environment, not just Akka (Scala Futures, Java threads, ...).
Historic Simulation
The core business logic can then be run in your discrete event simulation:
import BusinessLogic.processData
val someDate : Date = ???
val historicData : Iterable[Data] = querySomeDatabase(someDate)
//discrete event simulation
val historicResults : Iterable[Result] = historicData map processData
If concurrency is capable of making the event simulator faster then it is possible to use a non-Akka approach:
val concurrentHistoricResults : Future[Iterable[Result]] =
Future sequence {
historicData.map(data => Future(processData(data)))
}
Akka Realtime
At the same time the logic can be incorporated into Akka Actors. In general it is very helpful to make your receive method nothing more than a "data dispatcher", there shouldn't be any substantive code residing in the Actor definition:
class BusinessActor extends Actor {
override def receive = {
case data : Data => sender ! processData(data)
}
}
Similarly the business logic can be placed inside of akka streams for back-pressured stream processing:
val dataSource : Source[Data, _] = ???
val resultSource : Source[Result, _] =
dataSource via (Flow[Data] map processData)

Implementing long polling in scala and play 2.0 with akka

I'm implementing long polling in Play 2.0 in potentially a distributed environment. The way I understand it is that when Play gets a request, it should suspend pending notification of an update then go to the db to fetch new data and repeat. I started looking at the chat example that Play 2.0 offers but it's in websocket. Furthermore it doesn't look like it's capable of being distributed. So I thought I will use Akka's event bus. I took the eventstream implementation and replicated my own with LookupClassification. However I'm stumped as to how I'm gonna get a message back (or for that matter, what should be the subscriber instead of ActorRef)?
EventStream implementation:
https://github.com/akka/akka/blob/master/akka-actor/src/main/scala/akka/event/EventStream.scala
I am not sure that is what you are looking for, but there is quite a simple solution in the comet-clock sample, that you can adapt to use AKKA actors. It uses an infinite iframe instead of long polling. I have used an adapted version for a more complex application doing multiple DB calls and long computation in AKKA actors and it works fine.
def enum = Action {
//get your actor
val myActorRef = Akka.system.actorOf(Props[TestActor])
//do some query to your DB here. Promise.timeout is to simulate a blocking call
def getDatabaseItem(id: Int): Promise[String] = { Promise.timeout("test", 10 milliseconds) }
//test iterator, you will want something smarter here
val items1 = 1 to 10 toIterator
// this is a very simple enumerator that takes ints from an existing iterator (for an http request parameters for instance) and do some computations
def myEnum(it: Iterator[Int]): Enumerator[String] = Enumerator.fromCallback[String] { () =>
if (!items1.hasNext)
Promise.pure[Option[String]](None) //we are done with our computations
else {
// get the next int, query the database and compose the promise with a further query to the AKKA actor
getDatabaseItem(items1.next).flatMap { dbValue =>
implicit val timeout = new Timeout(10 milliseconds)
val future = (myActorRef ? dbValue) mapTo manifest[String]
// here we convert the AKKA actor to the right Promise[Option] output
future.map(v => Some(v)).asPromise
}
}
}
// finally we stream the result to the infinite iframe.
// console.log is the javascript callback, you will want something more interesting.
Ok.stream(myEnum(items1) &> Comet(callback = "console.log"))
}
Note that this fromCallback doesn't allow you to combine enumerators with "andThen", there is in the trunk version of play2 a generateM method that might be more appropriate if you want to use combinations.
It's not long polling, but it works fine.
I stumbled on your question while looking for the same thing.
I found the streaming solution unsatisfying as they caused "spinner of death" in webkit browser (i.e. shows it is loading all the time)
Anyhow, didn't have any luck finding good examples but I managed to create my own proof-of-concept using promises:
https://github.com/kallebertell/longpoll

Correct usage of mutable/immutable lists

At the moment, Im trying to understand Functional Programming in Scala and I came across a problem I cannot figure out myself.
Imagine the following situation:
You have two classes: Controller and Bot. A Bot is an independent Actor which is initiated by a Controller, does some expensive operation and returns the result to the Controller. The purpose of the Controller is therefore easy to describe: Instantiate multiple objects of Bot, start them and receive the result.
So far, so good; I can implement all this without using any mutable objects.
But what do I do, if I have to store the result that a Bot returns, to use it later as input for another Bot (and later on means that I don't know when at compile time!)?
Doing this with a mutable list or collection is fairly easy, but I add a lot of problems to my code (as we are dealing with concurrency here).
Is it possible, following the FP paradigm, to solve this by using immutable objects (lists...) safely?
BTW, im new to FP, so this question might sound stupid, but I cannot figure out how to solve this :)
Actors usually have internal state, being, themselves, mutable beasts. Note that actors are not a FP thing.
The setup you describe seems to rely on a mutable controller, and it is difficult to get around it in a language that is not non-strict by default. Depending on what you are doing, though, you could rely on futures. For example:
case Msg(info) =>
val v1 = new Bot !! Fn1(info)
val v2 = new Bot !! Fn2(info)
val v3 = new Bot !! Fn3(info)
val v4 = new Bot !! Fn4(v1(), v2(), v3())
reply(v4())
In this case -- because !! returns a Future -- v1, v2 and v3 will be computed in parallel. The message Fn4 is receiving as parameters the futures applied, meaning it will wait until all values are computed before it starts computing.
Likewise, the reply will only be sent after v4 has been computed, as the future has been applied for as well.
A really functional way of doing these things is the functional reactive programming, or FRP for short. It is a different model than actors.
The beauty of Scala, though, is that you can combine such paradigms to the extent that better fits your problem.
This is how an Erlang-like actor could look in Scala:
case class Actor[State](val s: State)(body: State => Option[State]) { // immutable
#tailrec
def loop(s1: State) {
body(s1) match {
case Some(s2) => loop(s2)
case None => ()
}
}
def act = loop(s)
}
def Bot(controller: Actor) = Actor(controller) {
s =>
val res = // do the calculations
controller ! (this, res)
None // finish work
}
val Controller = Actor(Map[Bot, ResultType]()) {s =>
// start bots, perhaps using results already stored in s
if (
// time to stop, e.g. all bots already finished
)
None
else
receive {
case (bot, res) => Some(s + (bot -> res)) // a bot has reported result
}
}
Controller.act