Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Play 2.5 What is akka.stream.Materializer useful for?

Tags:

I started to use Play 2.5 recently, and I was wondering what the purpose of doing the following was:

@Inject() (implicit val mat: Materializer) 

I had several pieces of code not working and solved that issue thanks to this, but I still don't see what the materializer is doing.

Thanks

like image 568
Scipion Avatar asked Apr 27 '16 11:04

Scipion


1 Answers

Materializing means producing the results of a graph

A materializer makes actors execute a graph to produce those results.

A graph, in its simplest form, consists of a source that provides elements, and a sink that consumes elements.

Here's a source that provides a range of integers (in this example, integers are our elements):

val source = Source(1 to 10) 

And here's a sink that sums all the integers it gets from a source:

val sink = Sink.fold[Int, Int](0)(_ + _) 

We connect source and sink to get a graph:

val graph = source.toMat(sink)(Keep.right) 

Mind that no computation, addition in our case, is performed when creating a graph. The code is declarative, the graphs describe how we want to transform our data but it is someone else's job to actually perform the computation: Graphs are blueprints.

Now, what about the materializer? The materializer takes action when we run the graph:

implicit val materializer = ActorMaterializer() val futureResult = graph.run() 

When we run() the graph, the materializer takes the graph and makes actors execute the data transformations specified in the graph; in this example, that's adding integers.

It might be helpful to imagine the graph as a blueprint to build a house, the materializer as the foreman looking at the blueprint, telling the builders how to actually build the house according to the blueprint. The builders in this analogy correspond to actors in Akka.

The reason why several pieces of your code now work, is that with the materializer you provide a way to execute graphs. Graphs are heavily used in Akka HTTP which Play uses for HTTP requests and responses.

The WSClient you mentioned in your comment uses graphs to perform its requests and thus needs a materializer.


Here's a full example of creating and running a graph:

import akka.actor.ActorSystem import akka.stream.ActorMaterializer import akka.stream.scaladsl.{Keep, Sink, Source}  object Graphs extends App {   // The start of our simple graph. It provides elements, integers in our case   val source = Source(1 to 10)    // The end of our graph. It processes the source's elements   val sink = Sink.fold[Int, Int](0)(_ + _)   /*   * Connect source and sink.   * Keep only the output values (i.e., the graph's right side).   * Note that this is declarative: no result is computed until we run the graph.   */   val graph = source.toMat(sink)(Keep.right)    // The system coordinates actors and provides threads for them   implicit val actorSystem = ActorSystem()   // The materializer makes actors execute graphs   implicit val materializer = ActorMaterializer()    // Running the graph means that the materializer assigns actors to execute   // the graph from start (source) to end (sink)   val futureResult = graph.run()    // Use the actor system's execution context, which provides threads,   // to print the result of running the graph   implicit val executionContext = actorSystem.dispatcher   futureResult.foreach(res => println(s"Result of running the graph: $res"))    actorSystem.terminate().foreach(_ => println("System is shut down")) } 

Put this in your build.sbt to make Akka's stream library available in your code:

libraryDependencies += "com.typesafe.akka" %% "akka-stream" % "2.5.19" 

Here's more on sources and sinks.

like image 59
Matthias Braun Avatar answered Dec 24 '22 18:12

Matthias Braun