Introduction to Akka Streams

Reading Time: 3 minutes
Akka Streams Image

Introduction

Lets discuss about streams first. Streams help us to ingest, process, analyze and store data in a quick and responsive manner. Also, it provides us a declarative way of describing, handling and hiding details that we don’t care about in the data.

As we know, actors are the core of the Akka toolkit. Akka Streams are built on top of Akka actors which makes ingestion and processing of streams easy. This library allow us to write systems in which data is being recieved in pieces, rather than all at once. This allows us to write our logic and forget about the code that is required to manage the actors in different scenarios. Akka Streams implementation uses the reactive stream interfaces internally to pass data between different operators. The main advantage of Akka Streams is non-blocking nature. It means that a certain thread does not hinder the progress of calling thread.

Terminology Used in Akka Streams

  1. Source : This is the entry point to every stream. We can also create multiple instance to read from different sources. Source takes two type parameters. The first one represents the type of value of it emits and the second one is the type of auxiliary value it can produce when materialised. It is also considered as a publisher.
  2. Flow : It is the processing block of our stream. Every flow has one input and one output value. It connects the upstream and downstream by transforming the elements passing through it. Flow connected with both source and Sink results in a RunnableFlow.
  3. Sink : Sink is the last element of our stream. There must be atleast one in every stream. When we are building a flow, it is not executed until we register a sink operation on it. It is a terminal operation that triggers all computations in the entire flow. It is also called as subscriber.

Basic and working of Flows

Back-Pressure : There might be a case when a Source produces data too fast for sink to handle. In this case, as it gets more data so its not able to process the data at the moment and will be buffering for processing it in future. In this case, Akka streams uses asynchronous and non blocking backpressure and inform the source to slow the rate of pushing the data.

Graph : A description of a stream processing topology, defining the pathways through which elements shall flow when the stream is running.

Runnable Graph : A flow having both ends attached to source and sink and is ready to execute the run.

Basic Code of Akka Streams

import akka.{Done, NotUsed}

import akka.actor.ActorSystem

import akka.stream.ActorMaterializer

import akka.stream.scaladsl._ 

import scala.concurrent.Future

object StreamExample {

  def main(args: Array[String]): Unit = { 
   
    implicit val system = ActorSystem("Sys") 

    implicit val materializer = ActorMaterializer() 
    
    val numbers = 1 to 100  
  
    //Creating a Source to iterate over numbers sequence
 
    val numberSource: Source[Int, NotUsed] = Source.fromIterator(() =>

 numbers.iterator)   
 
    //Only passing even numbers through the Flow 

    val isEvenFlow: Flow[Int, Int, NotUsed] = Flow[Int].filter((num) => num % 2 == 0)
 
    val evenNumbersSource: Source[Int, NotUsed] =numberSource.via(isEvenFlow)  

   
     //Creating a Sink to write its output to console

     val consoleSink: Sink[Int, Future[Done]] = Sink.foreach[Int](println)  
    
    //Connect the Source with the Sink and run it using the materializer

     evenNumbersSource.runWith(consoleSink)  
  }
}

References

Akka Stream Documentation

Streams Flow Details

Written by 

Amarjeet is a Software Consultant at Knoldus Software LLP. He has an overall experience of 2 years and 10 months.He has completed his Bachelor of Technology in Computer Science from National Institute of Technology, Hamirpur, Himachal Pradesh. He likes reading books, travelling and trekking.