I'm using Play 2.6.x and the test helper for status(result) has the method:
def status(of: Accumulator[ByteString, Result])(implicit timeout: Timeout, mat: Materializer): Int = status(of.run())
Running tests throws when the compiler can't find the implicit value:
could not find implicit value for parameter mat: akka.stream.Materializer
What is the Materializer -- I'm assuming it's part of Akka-HTTP
And how can I provide one?
From akka streams docs:
The Materializer is a factory for stream execution engines, it is the
thing that makes streams run [...]
The Materializer is the cornerstone of Akka Streams, on which Akka HTTP is built on. You need one of these to be implicitly resolved to make your test compile.
Presently the ActorMaterializer is the only available implementation of Materializer. It is a Materializer based on Akka actors. This is the reason why, to create one, you need in turn to have an ActorSystem in scope.
The following code is what you need in your test:
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
implicit val sys = ActorSystem("MyTest")
implicit val mat = ActorMaterializer()
there's also a status method in the form:
def status(of: Future[Result])(implicit timeout: Timeout): Int
make sure the controller return type is correct so the action returns a Future[Result]
How about doing this:
implicit val materializer = ActorMaterializer()
As of Play 2.6.0 ActorMaterializer() is deprecated, but you can do this instead:
val as = ActorSystem()
implicit val materializer = Materializer(as)
Related
I'm looking at the akka streams quickstart tutorial and I wanted to understand how a piece of code works. The following code from the example prints out the values from 1 to 100 to the console:
import akka.stream.scaladsl._
import akka.{Done, NotUsed}
import akka.actor.ActorSystem
object Akka_Streams extends App{
implicit val system: ActorSystem = ActorSystem("QuickStart")
val source: Source[Int, NotUsed] = Source(1 to 100)
source.runForeach(i => println(i))
}
What I don't understand is, when I change the code to the following and remove the implicit, the code no longer works. I get a type mismatch error (shown below the following code):
object Akka_Streams extends App{
val system: ActorSystem = ActorSystem("QuickStart")
val source: Source[Int, NotUsed] = Source(1 to 100)
source.runForeach(i => println(i))(system)
}
Error:
type mismatch;
found : akka.actor.ActorSystem
required: akka.stream.Materializer
source.runForeach(i => println(i))(system)
Why did this work before but not now? the source.runForeach method takes a Materalizer type so I wonder why this was working at all to begin with? From what I can see, an ActorSystem is not a Materalizer or a sub-type of it so I'm confused.
It is related to how Scala compiler converts ActorSystem to a Materializer
It is done via implicit conversions with following method
/**
* Implicitly provides the system wide materializer from a classic or typed `ActorSystem`
*/
implicit def matFromSystem(implicit provider: ClassicActorSystemProvider): Materializer =
SystemMaterializer(provider.classicSystem).materializer
It requires parameter provider to be implicit.
So having implicit key is allowing the compiler to take an implicit actor system when it needs an instance of a Materializer, and such conversion is done without any need to explicitly define a materializer in the scope.
I've found that my Akka Streams program had unexpected CPU usage.
Here is a simple example:
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import akka.stream.scaladsl.{Sink, Source}
implicit val system: ActorSystem = ActorSystem.create("QuickStart")
implicit val materializer: ActorMaterializer = ActorMaterializer()
Source.repeat(Unit)
.to(Sink.ignore)
.run()
The code piece above will let source and sink runs in the same actor.
It uses about 105% CPU usage on my laptop. Works as expected.
And after I was added an async boundary:
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import akka.stream.scaladsl.{Sink, Source}
implicit val system: ActorSystem = ActorSystem.create("QuickStart")
implicit val materializer: ActorMaterializer = ActorMaterializer()
Source.repeat(Unit)
.async // <------ async boundary here
.to(Sink.ignore)
.run()
This code piece now will use about 600% of CPU usage on my 4c8t laptop.
I was expecting by adding an async boundary this stream will run in 2 separate actors and will cost a little more than 200% CPU. But it costs a lot more than 200%.
What may causes async boundary to use that much CPU?
Default akka.actor.default-dispatcher parameter is Java's ForkJoinPool. It's initialized via call to ThreadPoolConfig.scaledPoolSize. Thus it defaults to starting pool of size (number of processors * 3) and max = parallelism-max (64).
I'm coding a small Akka Streams sample where I want to write elements of a List to a local TXT file
implicit val ec = context.dispatcher
implicit val actorSystem = context.system
implicit val materializer = ActorMaterializer()
val source = Source(List("a", "b", "c"))
.map(char => ByteString(s"${char} \n"))
val runnableGraph = source.toMat(FileIO.toPath(Paths.get("~/Downloads/results.txt")))(Keep.right)
runnableGraph.run()
The file is already created by the location I set in the code.
I do not terminate the actor system, so definitely it has enough time to write all of List elements to the file.
But unfortunately, nothing happens
Use the expanded path to your home directory instead of the tilde (~). For example:
val runnableGraph =
source.toMat(
FileIO.toPath(Paths.get("/home/YourUserName/Downloads/results.txt")))(Keep.right)
runnableGraph.run()
I wanted to use Alpakka for handling S3 upload and download with Akka Steams. However, I got stuck with using Source produced by S3Client within Akka Http routes. The error message I get is:
[error] found : akka.stream.scaladsl.Source[akka.util.ByteString,_$1] where type _$1
[error] required: akka.http.scaladsl.marshalling.ToResponseMarshallable
[error] complete(source)
I assume that it is some annoying trivial thing, like missing implicit import, but I was not able to pinpoint what I am missing.
I've created some minimal example to illustrate the issue:
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Directives._
import akka.stream.ActorMaterializer
import akka.stream.scaladsl.Source
import akka.util.ByteString
import scala.concurrent.ExecutionContext
class Test {
implicit val actorSystem: ActorSystem = ActorSystem()
implicit val materializer: ActorMaterializer = ActorMaterializer()
implicit val executionContext: ExecutionContext = actorSystem.dispatcher
val route = (path("test") & get) {
def source: Source[ByteString, _] = ??? // just assume that I am able to get that value
complete(source) // here error happens
}
Http().bindAndHandle(route, "localhost", 8000)
}
Do you have some suggestions, what can I try? I am using
libraryDependencies += "com.typesafe.akka"%% "akka-http" % "10.0.5"
You need to create an HttpEntity from the source, and give it a content-type.
complete(HttpEntity(ContentTypes.`application/json`, source))
Here is a basic example of using schedule in Akka:
import akka.pattern
import akka.util.Timeout
import scala.concurrent.Await
import akka.actor.Actor
import akka.actor.Props
import akka.actor.ActorSystem
import akka.pattern.ask
import scala.concurrent.duration
object Application extends App {
val supervisor = ActorSystem().actorOf(Props[Supervisor])
implicit val timeout = Timeout(10 seconds)
import system.dispatcher
supervisor.scheduler.scheduleOnce(120 seconds) {
val future = supervisor ? Supervisor.Start
val resultIdList = Await.result(future, timeout.duration).asInstanceOf[List[MyIdList]]
supervisor ! resultIdList
}
}
I'm really confused of Akka's documentation. Here Having problems with Akka 2.1.2 Scheduler ('system' not recognized) was said that import system.dispatcher is not a package import but something else. What is that then?
What is system? Do I have to replace it with supervisor? Even if I didn't do that and keep using system, I'd have pretty much the same errors:
//(using system)
value scheduler is not a member of akka.actor.ActorRef
not found: value system
//or (using supervisor)
not found: value system
not found: value system
Try this ;)
val system = ActorSystem()
val supervisor = system.actorOf(Props[Supervisor])
(Posting as answer since does not fit as comment)
Marius, you were referring to another question which started with this line:
val system = akka.actor.ActorSystem("system")
That is the identifier 'system' the import statement is referring to.
The line
import system.dispatcher
means that the dispatcher member of the variable system will be available in scope (you can use the name 'dispatcher' to refer to 'system.dispatcher' from that point). This also means that since dispatcher is an implicit that it will be now available for implicit resolution. Please note that the signature of schedule is
scheduleOnce(delay: FiniteDuration, runnable: Runnable)(implicit executor: ExecutionContext): Cancellable
So it either needs an explicitly passed ExecutionContext, or an implicit one. By using the import statement you bring the dispatcher (which is an ExecutionContext) into scope, so you don't have to provide it manually.