Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
FPConf 2016
Search
Alexey Romanchuk
December 03, 2016
Programming
290
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
FPConf 2016
Practical akka streams
Alexey Romanchuk
December 03, 2016
Other Decks in Programming
See All in Programming
Agents on Rails - Rails at Scale 2026
irinanazarova
0
560
ジョジョの世界をXRで再現する
mofurune
0
170
ソニーのクラウド共通基盤の変遷とAI時代の開発スタイルに合わせた進化 / The Journey of Sony’s Common Cloud Platform and Its Evolution for AI-Native Development
kenjiyoneyama
0
270
Railsのためのパスキー実践入門 〜マルチテナントSaaSでの意思決定〜
utakaha
2
610
RAG の “R” を Swift で覗いてみる 〜「意味から探す」検索の仕組み〜
nao_randd
0
160
Agentic Software Factoryに、すごく賢いIF文を。 / super smart IF statement into the Agentic Software Factory.
rkaga
8
2.2k
Unity6 URPによる海底をテーマにしたVJシステムの解説 | Unity Shader 完全に理解した 勉強会
gam0022
0
370
The Rails Doctrine Decade
koic
2
590
AI主導のプログラミング学習アプリを作ってみた
econanringo
0
180
すこし踏み込む CancellationToken
htkym
2
1.7k
Herb in Rails 8.2: Your ERB views, now HTML-aware @ Rails World 2026, Austin, Texas
marcoroth
0
220
月間100万人のサービス刷新で、 技術選定をHonoに振り切った話
yutobara
8
6.6k
Featured
See All Featured
Skip the Path - Find Your Career Trail
mkilby
1
260
Heart Work Chapter 1 - Part 1
lfama
PRO
10
37k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
18k
Bash Introduction
62gerente
615
220k
Ethics towards AI in product and experience design
skipperchong
2
430
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.6k
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.8k
The agentic SEO stack - context over prompts
schlessera
0
970
Navigating Weather and Climate Data
rabernat
0
560
Everyday Curiosity
cassininazir
0
350
How to Grow Your eCommerce with AI & Automation
katarinadahlin
PRO
2
330
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
1
580
Transcript
Практика Akka Streams Алексей Романчук
2 Обо мне
3
4 Обо мне
• Знаете синтаксис Scala • Знакомы со стандартной библиотекой Scala
• Слышали про Reactive Streams • Видели Akka Streams* 5 О вас
В предыдущих сериях
T
T Iterable[T]
T Iterable[T] Future[T]
T Iterable[T] Future[T] Source[T]
• Реализуют спецификацию Reactive Streams • Основаны на Akka •
Умеют Backpressure • Статически типизированы 8 Akka Streams
9 Ключевые абстракции Source Sink Flow
Базовые комбинаторы
11 Source Source.single(1) Source.failed(new Exception()) Source.empty[Int] Source.repeat(1) Source.fromIterator(() =>
Iterator(1, 2, 3)) Source.cycle(() => Iterator(1, 2, 3)) Source.tick(1 second, 100 millis, ())
11 Source Source.single(1) Source.failed(new Exception()) Source.empty[Int] Source.repeat(1) Source.fromIterator(() =>
Iterator(1, 2, 3)) Source.cycle(() => Iterator(1, 2, 3)) Source.tick(1 second, 100 millis, ())
11 Source Source.single(1) Source.failed(new Exception()) Source.empty[Int] Source.repeat(1) Source.fromIterator(() =>
Iterator(1, 2, 3)) Source.cycle(() => Iterator(1, 2, 3)) Source.tick(1 second, 100 millis, ())
11 Source Source.single(1) Source.failed(new Exception()) Source.empty[Int] Source.repeat(1) Source.fromIterator(() =>
Iterator(1, 2, 3)) Source.cycle(() => Iterator(1, 2, 3)) Source.tick(1 second, 100 millis, ())
11 Source Source.single(1) Source.failed(new Exception()) Source.empty[Int] Source.repeat(1) Source.fromIterator(() =>
Iterator(1, 2, 3)) Source.cycle(() => Iterator(1, 2, 3)) Source.tick(1 second, 100 millis, ())
11 Source Source.single(1) Source.failed(new Exception()) Source.empty[Int] Source.repeat(1) Source.fromIterator(() =>
Iterator(1, 2, 3)) Source.cycle(() => Iterator(1, 2, 3)) Source.tick(1 second, 100 millis, ())
11 Source Source.single(1) Source.failed(new Exception()) Source.empty[Int] Source.repeat(1) Source.fromIterator(() =>
Iterator(1, 2, 3)) Source.cycle(() => Iterator(1, 2, 3)) Source.tick(1 second, 100 millis, ())
11 Source Source.single(1) Source.failed(new Exception()) Source.empty[Int] Source.repeat(1) Source.fromIterator(() =>
Iterator(1, 2, 3)) Source.cycle(() => Iterator(1, 2, 3)) Source.tick(1 second, 100 millis, ())
11 Source Source.single(1) Source.failed(new Exception()) Source.empty[Int] Source.repeat(1) Source.fromIterator(() =>
Iterator(1, 2, 3)) Source.cycle(() => Iterator(1, 2, 3)) Source.tick(1 second, 100 millis, ())
12 Sink Sink.ignore Sink.cancelled Sink.foreach[Int](println) Sink.head Sink.headOption Sink.last Sink.lastOption
Sink.fold(0)(_ + _) Sink.reduce[Int](_ + _)
12 Sink Sink.ignore Sink.cancelled Sink.foreach[Int](println) Sink.head Sink.headOption Sink.last Sink.lastOption
Sink.fold(0)(_ + _) Sink.reduce[Int](_ + _)
12 Sink Sink.ignore Sink.cancelled Sink.foreach[Int](println) Sink.head Sink.headOption Sink.last Sink.lastOption
Sink.fold(0)(_ + _) Sink.reduce[Int](_ + _)
12 Sink Sink.ignore Sink.cancelled Sink.foreach[Int](println) Sink.head Sink.headOption Sink.last Sink.lastOption
Sink.fold(0)(_ + _) Sink.reduce[Int](_ + _)
12 Sink Sink.ignore Sink.cancelled Sink.foreach[Int](println) Sink.head Sink.headOption Sink.last Sink.lastOption
Sink.fold(0)(_ + _) Sink.reduce[Int](_ + _)
12 Sink Sink.ignore Sink.cancelled Sink.foreach[Int](println) Sink.head Sink.headOption Sink.last Sink.lastOption
Sink.fold(0)(_ + _) Sink.reduce[Int](_ + _)
12 Sink Sink.ignore Sink.cancelled Sink.foreach[Int](println) Sink.head Sink.headOption Sink.last Sink.lastOption
Sink.fold(0)(_ + _) Sink.reduce[Int](_ + _)
13 Flow Flow[Int].map(identity) Flow[Int].mapAsync(10)(Future.successful) Flow[Int].mapAsyncUnordered(10)(Future.successful) Flow[Int].filter(_ % 2 ==
0) Flow[Int].collect { case n if n % 2 == 0 => n } Flow[Int].take(10) Flow[Int].takeWhile(_ > 10) Flow[Int].drop(10) Flow[Int].dropWhile(_ > 10)
13 Flow Flow[Int].map(identity) Flow[Int].mapAsync(10)(Future.successful) Flow[Int].mapAsyncUnordered(10)(Future.successful) Flow[Int].filter(_ % 2 ==
0) Flow[Int].collect { case n if n % 2 == 0 => n } Flow[Int].take(10) Flow[Int].takeWhile(_ > 10) Flow[Int].drop(10) Flow[Int].dropWhile(_ > 10)
13 Flow Flow[Int].map(identity) Flow[Int].mapAsync(10)(Future.successful) Flow[Int].mapAsyncUnordered(10)(Future.successful) Flow[Int].filter(_ % 2 ==
0) Flow[Int].collect { case n if n % 2 == 0 => n } Flow[Int].take(10) Flow[Int].takeWhile(_ > 10) Flow[Int].drop(10) Flow[Int].dropWhile(_ > 10)
13 Flow Flow[Int].map(identity) Flow[Int].mapAsync(10)(Future.successful) Flow[Int].mapAsyncUnordered(10)(Future.successful) Flow[Int].filter(_ % 2 ==
0) Flow[Int].collect { case n if n % 2 == 0 => n } Flow[Int].take(10) Flow[Int].takeWhile(_ > 10) Flow[Int].drop(10) Flow[Int].dropWhile(_ > 10)
13 Flow Flow[Int].map(identity) Flow[Int].mapAsync(10)(Future.successful) Flow[Int].mapAsyncUnordered(10)(Future.successful) Flow[Int].filter(_ % 2 ==
0) Flow[Int].collect { case n if n % 2 == 0 => n } Flow[Int].take(10) Flow[Int].takeWhile(_ > 10) Flow[Int].drop(10) Flow[Int].dropWhile(_ > 10)
13 Flow Flow[Int].map(identity) Flow[Int].mapAsync(10)(Future.successful) Flow[Int].mapAsyncUnordered(10)(Future.successful) Flow[Int].filter(_ % 2 ==
0) Flow[Int].collect { case n if n % 2 == 0 => n } Flow[Int].take(10) Flow[Int].takeWhile(_ > 10) Flow[Int].drop(10) Flow[Int].dropWhile(_ > 10)
13 Flow Flow[Int].map(identity) Flow[Int].mapAsync(10)(Future.successful) Flow[Int].mapAsyncUnordered(10)(Future.successful) Flow[Int].filter(_ % 2 ==
0) Flow[Int].collect { case n if n % 2 == 0 => n } Flow[Int].take(10) Flow[Int].takeWhile(_ > 10) Flow[Int].drop(10) Flow[Int].dropWhile(_ > 10)
13 Flow Flow[Int].map(identity) Flow[Int].mapAsync(10)(Future.successful) Flow[Int].mapAsyncUnordered(10)(Future.successful) Flow[Int].filter(_ % 2 ==
0) Flow[Int].collect { case n if n % 2 == 0 => n } Flow[Int].take(10) Flow[Int].takeWhile(_ > 10) Flow[Int].drop(10) Flow[Int].dropWhile(_ > 10)
14 Flow Flow[Int].flatMapConcat(n => Source.fromIterator(() => Iterator.range(1, n)) ) 1
2 3 Х
14 Flow Flow[Int].flatMapConcat(n => Source.fromIterator(() => Iterator.range(1, n)) ) 1
2 3 Х 1 Х
14 Flow Flow[Int].flatMapConcat(n => Source.fromIterator(() => Iterator.range(1, n)) ) 1
2 3 Х 1 Х 1 2 Х
14 Flow Flow[Int].flatMapConcat(n => Source.fromIterator(() => Iterator.range(1, n)) ) 1
2 3 Х 1 Х 1 2 Х 1 2 3 Х
14 Flow Flow[Int].flatMapConcat(n => Source.fromIterator(() => Iterator.range(1, n)) ) 1
2 3 Х 1 Х 1 2 Х 1 2 3 Х 1 1 2 1 2 3 Х
Пример №1
• Прочитать с хадупа логи транзакций и найти там 100
примеров фродных транзакций 16 Задача List Files API Read Line Result
17 Наивная реализация def checkFraud(in: String): Future[Option[TransactionId]] = ??? val
result: List[TransactionId] = (for { file <- hdfs.listStatusIterator(path) if file.isFile line <-fromInputStream(fs.open(file.getPath)).getLines() resultOpt = Await.result(checkFraud(line), 10 seconds) result <- resultOpt } yield result) .take(100).toList
17 Наивная реализация def checkFraud(in: String): Future[Option[TransactionId]] = ??? val
result: List[TransactionId] = (for { file <- hdfs.listStatusIterator(path) if file.isFile line <-fromInputStream(fs.open(file.getPath)).getLines() resultOpt = Await.result(checkFraud(line), 10 seconds) result <- resultOpt } yield result) .take(100).toList
17 Наивная реализация def checkFraud(in: String): Future[Option[TransactionId]] = ??? val
result: List[TransactionId] = (for { file <- hdfs.listStatusIterator(path) if file.isFile line <-fromInputStream(fs.open(file.getPath)).getLines() resultOpt = Await.result(checkFraud(line), 10 seconds) result <- resultOpt } yield result) .take(100).toList
17 Наивная реализация def checkFraud(in: String): Future[Option[TransactionId]] = ??? val
result: List[TransactionId] = (for { file <- hdfs.listStatusIterator(path) if file.isFile line <-fromInputStream(fs.open(file.getPath)).getLines() resultOpt = Await.result(checkFraud(line), 10 seconds) result <- resultOpt } yield result) .take(100).toList
17 Наивная реализация def checkFraud(in: String): Future[Option[TransactionId]] = ??? val
result: List[TransactionId] = (for { file <- hdfs.listStatusIterator(path) if file.isFile line <-fromInputStream(fs.open(file.getPath)).getLines() resultOpt = Await.result(checkFraud(line), 10 seconds) result <- resultOpt } yield result) .take(100).toList
17 Наивная реализация def checkFraud(in: String): Future[Option[TransactionId]] = ??? val
result: List[TransactionId] = (for { file <- hdfs.listStatusIterator(path) if file.isFile line <-fromInputStream(fs.open(file.getPath)).getLines() resultOpt = Await.result(checkFraud(line), 10 seconds) result <- resultOpt } yield result) .take(100).toList
17 Наивная реализация def checkFraud(in: String): Future[Option[TransactionId]] = ??? val
result: List[TransactionId] = (for { file <- hdfs.listStatusIterator(path) if file.isFile line <-fromInputStream(fs.open(file.getPath)).getLines() resultOpt = Await.result(checkFraud(line), 10 seconds) result <- resultOpt } yield result) .take(100).toList
17 Наивная реализация def checkFraud(in: String): Future[Option[TransactionId]] = ??? val
result: List[TransactionId] = (for { file <- hdfs.listStatusIterator(path) if file.isFile line <-fromInputStream(fs.open(file.getPath)).getLines() resultOpt = Await.result(checkFraud(line), 10 seconds) result <- resultOpt } yield result) .take(100).toList
17 Наивная реализация def checkFraud(in: String): Future[Option[TransactionId]] = ??? val
result: List[TransactionId] = (for { file <- hdfs.listStatusIterator(path) if file.isFile line <-fromInputStream(fs.open(file.getPath)).getLines() resultOpt = Await.result(checkFraud(line), 10 seconds) result <- resultOpt } yield result) .take(100).toList
17 Наивная реализация def checkFraud(in: String): Future[Option[TransactionId]] = ??? val
result: List[TransactionId] = (for { file <- hdfs.listStatusIterator(path) if file.isFile line <-fromInputStream(fs.open(file.getPath)).getLines() resultOpt = Await.result(checkFraud(line), 10 seconds) result <- resultOpt } yield result) .take(100).toList
17 Наивная реализация def checkFraud(in: String): Future[Option[TransactionId]] = ??? val
result: List[TransactionId] = (for { file <- hdfs.listStatusIterator(path) if file.isFile line <-fromInputStream(fs.open(file.getPath)).getLines() resultOpt = Await.result(checkFraud(line), 10 seconds) result <- resultOpt } yield result) .take(100).toList
Ок?
• Не терять лишнего времени на скачивание • Параллельные запросы
к сервису • Не превышать ограничения в 10 запросов в секунду 19 Требования
20 Красивая картинка со схемой List Files API Read Line
Result
21 Красивый код на стримах val stream = Source .fromIterator
{ () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
21 Красивый код на стримах val stream = Source .fromIterator
{ () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
21 Красивый код на стримах val stream = Source .fromIterator
{ () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
21 Красивый код на стримах val stream = Source .fromIterator
{ () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
21 Красивый код на стримах val stream = Source .fromIterator
{ () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
21 Красивый код на стримах val stream = Source .fromIterator
{ () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
21 Красивый код на стримах val stream = Source .fromIterator
{ () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
21 Красивый код на стримах val stream = Source .fromIterator
{ () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
21 Красивый код на стримах val stream = Source .fromIterator
{ () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
21 Красивый код на стримах val stream = Source .fromIterator
{ () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
21 Красивый код на стримах val stream = Source .fromIterator
{ () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
21 Красивый код на стримах val stream = Source .fromIterator
{ () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
21 Красивый код на стримах val stream = Source .fromIterator
{ () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
21 Красивый код на стримах val stream = Source .fromIterator
{ () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
21 Красивый код на стримах val stream = Source .fromIterator
{ () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
21 Красивый код на стримах val stream = Source .fromIterator
{ () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
Все на стандартных комбинаторах
23 Запуск val result: Future[List[TransactionId]] = stream.run() val result2:
Future[List[TransactionId]] = stream.run()
24 Запуск List Files API Read Line Result
24 Запуск List Files API Read Line Result run() Future
Stream
24 Запуск List Files API Read Line Result run() Future
Stream run() Future Stream
Материализация
Чертеж → Деталь
27 RunnableGraph RunnableGraph[+Mat] { def run(): Mat }
28 Mat final class Source[+Out, +Mat] final class Flow[-In, +Out,
+Mat] final class Sink[-In, +Mat]
29 Sources case object NotUsed def single[T](element: T) def empty[T]
def failed[T](cause: Throwable) def repeat[T](element: T) def fromIterator[T](f: () => Iterator[T]) def cycle[T](f: () => Iterator[T])
30 Sinks def ignore: Sink[Any, Future[Done]] def foreach[T](f: T =>
Unit): Sink[T, Future[Done]] def head[T]: Sink[T, Future[T]] def headOption[T]: Sink[T, Future[Option[T]]] def fold[U, T](z: U)(f: (U, T) => U): Sink[T, Future[U]] def reduce[T](f: (T, T) => T): Sink[T, Future[T]]
30 Sinks def ignore: Sink[Any, Future[Done]] def foreach[T](f: T =>
Unit): Sink[T, Future[Done]] def head[T]: Sink[T, Future[T]] def headOption[T]: Sink[T, Future[Option[T]]] def fold[U, T](z: U)(f: (U, T) => U): Sink[T, Future[U]] def reduce[T](f: (T, T) => T): Sink[T, Future[T]]
30 Sinks def ignore: Sink[Any, Future[Done]] def foreach[T](f: T =>
Unit): Sink[T, Future[Done]] def head[T]: Sink[T, Future[T]] def headOption[T]: Sink[T, Future[Option[T]]] def fold[U, T](z: U)(f: (U, T) => U): Sink[T, Future[U]] def reduce[T](f: (T, T) => T): Sink[T, Future[T]]
30 Sinks def ignore: Sink[Any, Future[Done]] def foreach[T](f: T =>
Unit): Sink[T, Future[Done]] def head[T]: Sink[T, Future[T]] def headOption[T]: Sink[T, Future[Option[T]]] def fold[U, T](z: U)(f: (U, T) => U): Sink[T, Future[U]] def reduce[T](f: (T, T) => T): Sink[T, Future[T]]
30 Sinks def ignore: Sink[Any, Future[Done]] def foreach[T](f: T =>
Unit): Sink[T, Future[Done]] def head[T]: Sink[T, Future[T]] def headOption[T]: Sink[T, Future[Option[T]]] def fold[U, T](z: U)(f: (U, T) => U): Sink[T, Future[U]] def reduce[T](f: (T, T) => T): Sink[T, Future[T]]
30 Sinks def ignore: Sink[Any, Future[Done]] def foreach[T](f: T =>
Unit): Sink[T, Future[Done]] def head[T]: Sink[T, Future[T]] def headOption[T]: Sink[T, Future[Option[T]]] def fold[U, T](z: U)(f: (U, T) => U): Sink[T, Future[U]] def reduce[T](f: (T, T) => T): Sink[T, Future[T]]
30 Sinks def ignore: Sink[Any, Future[Done]] def foreach[T](f: T =>
Unit): Sink[T, Future[Done]] def head[T]: Sink[T, Future[T]] def headOption[T]: Sink[T, Future[Option[T]]] def fold[U, T](z: U)(f: (U, T) => U): Sink[T, Future[U]] def reduce[T](f: (T, T) => T): Sink[T, Future[T]]
30 Sinks def ignore: Sink[Any, Future[Done]] def foreach[T](f: T =>
Unit): Sink[T, Future[Done]] def head[T]: Sink[T, Future[T]] def headOption[T]: Sink[T, Future[Option[T]]] def fold[U, T](z: U)(f: (U, T) => U): Sink[T, Future[U]] def reduce[T](f: (T, T) => T): Sink[T, Future[T]]
31 Композиция val source: Source[Int, NotUsed] = Source.single(1) val sink:
Sink[Any, Future[Done]] = Sink.ignore val s1: RunnableGraph[NotUsed] = source.to(sink) val s2: RunnableGraph[Future[Done]] = source.toMat(sink)(Keep.right) val s3: RunnableGraph[(NotUsed, Future[Done])] = source.toMat(sink)(Keep.both)
31 Композиция val source: Source[Int, NotUsed] = Source.single(1) val sink:
Sink[Any, Future[Done]] = Sink.ignore val s1: RunnableGraph[NotUsed] = source.to(sink) val s2: RunnableGraph[Future[Done]] = source.toMat(sink)(Keep.right) val s3: RunnableGraph[(NotUsed, Future[Done])] = source.toMat(sink)(Keep.both)
31 Композиция val source: Source[Int, NotUsed] = Source.single(1) val sink:
Sink[Any, Future[Done]] = Sink.ignore val s1: RunnableGraph[NotUsed] = source.to(sink) val s2: RunnableGraph[Future[Done]] = source.toMat(sink)(Keep.right) val s3: RunnableGraph[(NotUsed, Future[Done])] = source.toMat(sink)(Keep.both)
31 Композиция val source: Source[Int, NotUsed] = Source.single(1) val sink:
Sink[Any, Future[Done]] = Sink.ignore val s1: RunnableGraph[NotUsed] = source.to(sink) val s2: RunnableGraph[Future[Done]] = source.toMat(sink)(Keep.right) val s3: RunnableGraph[(NotUsed, Future[Done])] = source.toMat(sink)(Keep.both)
31 Композиция val source: Source[Int, NotUsed] = Source.single(1) val sink:
Sink[Any, Future[Done]] = Sink.ignore val s1: RunnableGraph[NotUsed] = source.to(sink) val s2: RunnableGraph[Future[Done]] = source.toMat(sink)(Keep.right) val s3: RunnableGraph[(NotUsed, Future[Done])] = source.toMat(sink)(Keep.both)
31 Композиция val source: Source[Int, NotUsed] = Source.single(1) val sink:
Sink[Any, Future[Done]] = Sink.ignore val s1: RunnableGraph[NotUsed] = source.to(sink) val s2: RunnableGraph[Future[Done]] = source.toMat(sink)(Keep.right) val s3: RunnableGraph[(NotUsed, Future[Done])] = source.toMat(sink)(Keep.both)
32 Композиция
33 Красивый код на стримах val stream: RunnableGraph[Future[List[TransactionId]]] = Source
.fromIterator { () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
33 Красивый код на стримах val stream: RunnableGraph[Future[List[TransactionId]]] = Source
.fromIterator { () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
33 Красивый код на стримах val stream: RunnableGraph[Future[List[TransactionId]]] = Source
.fromIterator { () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
33 Красивый код на стримах val stream: RunnableGraph[Future[List[TransactionId]]] = Source
.fromIterator { () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
34 Красивая картинка со схемой List Files API Read Line
Result run() Stream run() Future Stream Future
34 Красивая картинка со схемой List Files API Read Line
Result run() Future Stream run() Future Stream Future
Пример №2
• Читать данные из очереди и обрабатывать. 36 Задача Source
Process Sink Future
37 Красивый код на стримах val source = ZMQSource(context, mode
= ZMQ.PULL, timeout = 1 second, addresses = List("tcp: //127.0.0.1:12345") ) def process(in: ByteString): Future[Int] = ???
37 Красивый код на стримах val source = ZMQSource(context, mode
= ZMQ.PULL, timeout = 1 second, addresses = List("tcp: //127.0.0.1:12345") ) def process(in: ByteString): Future[Int] = ???
37 Красивый код на стримах val source = ZMQSource(context, mode
= ZMQ.PULL, timeout = 1 second, addresses = List("tcp: //127.0.0.1:12345") ) def process(in: ByteString): Future[Int] = ???
37 Красивый код на стримах val source = ZMQSource(context, mode
= ZMQ.PULL, timeout = 1 second, addresses = List("tcp: //127.0.0.1:12345") ) def process(in: ByteString): Future[Int] = ???
38 Красивый код на стримах val stream = source .mapAsync(10)(process)
.toMat(Sink.last)(Keep.right) val result: Future[Int] = stream.run() result.onComplete(_ => "We are done here")
38 Красивый код на стримах val stream = source .mapAsync(10)(process)
.toMat(Sink.last)(Keep.right) val result: Future[Int] = stream.run() result.onComplete(_ => "We are done here")
38 Красивый код на стримах val stream = source .mapAsync(10)(process)
.toMat(Sink.last)(Keep.right) val result: Future[Int] = stream.run() result.onComplete(_ => "We are done here")
38 Красивый код на стримах val stream = source .mapAsync(10)(process)
.toMat(Sink.last)(Keep.right) val result: Future[Int] = stream.run() result.onComplete(_ => "We are done here")
38 Красивый код на стримах val stream = source .mapAsync(10)(process)
.toMat(Sink.last)(Keep.right) val result: Future[Int] = stream.run() result.onComplete(_ => "We are done here")
39 Красивая картинка со схемой Source Process Sink Future
39 Красивая картинка со схемой Source Process Sink Future Stream
Future
Как это остановить?
41 Проблема остановки val stream = source .mapAsync(10)(process) .toMat(Sink.last)(Keep.right)
val result: Future[Int] = stream.run() result.onComplete(_ => "We are done here")
42 Проблема остановки Source Process Sink Future
42 Проблема остановки Source Process Sink Future Control
42 Проблема остановки Source Process Sink Future Stream Control Control
Future
43 Проблема остановки trait Control { /** * Disconnect the
underlying ZMQ socket, deliver the remaining data and finally close the socket. */ def gracefulStop(): Unit }
44 Проблема остановки val source: Source[ByteString, Control] = ??? val
stream: RunnableGraph[(Control, Future[Int])] = source .mapAsync(10)(process) .toMat(Sink.head)(Keep.both) val (control: Control, result: Future[Int]) = stream.run() result.onComplete(_ => "We are done here") control.gracefulStop()
44 Проблема остановки val source: Source[ByteString, Control] = ??? val
stream: RunnableGraph[(Control, Future[Int])] = source .mapAsync(10)(process) .toMat(Sink.head)(Keep.both) val (control: Control, result: Future[Int]) = stream.run() result.onComplete(_ => "We are done here") control.gracefulStop()
44 Проблема остановки val source: Source[ByteString, Control] = ??? val
stream: RunnableGraph[(Control, Future[Int])] = source .mapAsync(10)(process) .toMat(Sink.head)(Keep.both) val (control: Control, result: Future[Int]) = stream.run() result.onComplete(_ => "We are done here") control.gracefulStop()
44 Проблема остановки val source: Source[ByteString, Control] = ??? val
stream: RunnableGraph[(Control, Future[Int])] = source .mapAsync(10)(process) .toMat(Sink.head)(Keep.both) val (control: Control, result: Future[Int]) = stream.run() result.onComplete(_ => "We are done here") control.gracefulStop()
44 Проблема остановки val source: Source[ByteString, Control] = ??? val
stream: RunnableGraph[(Control, Future[Int])] = source .mapAsync(10)(process) .toMat(Sink.head)(Keep.both) val (control: Control, result: Future[Int]) = stream.run() result.onComplete(_ => "We are done here") control.gracefulStop()
44 Проблема остановки val source: Source[ByteString, Control] = ??? val
stream: RunnableGraph[(Control, Future[Int])] = source .mapAsync(10)(process) .toMat(Sink.head)(Keep.both) val (control: Control, result: Future[Int]) = stream.run() result.onComplete(_ => "We are done here") control.gracefulStop()
Пример №3
46 Механика Flow[T]
46 Механика Flow[T] Request Cancel
46 Механика Flow[T] Request Request Cancel Cancel
46 Механика Flow[T] Request Request T Error Complete Cancel Cancel
46 Механика Flow[T] T Error Complete Request Request T Error
Complete Cancel Cancel
• Emit элемента • Завершение • Ошибка • Backpressure •
Отмена 47 Что нужно знать про stages
48 Свой Source val s: Source[Int, ActorRef] = Source.actorPublisher[Int](Props(new MySourceActor))
class MySourceActor extends ActorPublisher[Int] { override def receive: Receive = { case ActorPublisherMessage.Request(n) => onNext(100) onCompleteThenStop() onErrorThenStop(new Exception) case ActorPublisherMessage.Cancel => context.stop(self) } }
48 Свой Source val s: Source[Int, ActorRef] = Source.actorPublisher[Int](Props(new MySourceActor))
class MySourceActor extends ActorPublisher[Int] { override def receive: Receive = { case ActorPublisherMessage.Request(n) => onNext(100) onCompleteThenStop() onErrorThenStop(new Exception) case ActorPublisherMessage.Cancel => context.stop(self) } }
48 Свой Source val s: Source[Int, ActorRef] = Source.actorPublisher[Int](Props(new MySourceActor))
class MySourceActor extends ActorPublisher[Int] { override def receive: Receive = { case ActorPublisherMessage.Request(n) => onNext(100) onCompleteThenStop() onErrorThenStop(new Exception) case ActorPublisherMessage.Cancel => context.stop(self) } }
48 Свой Source val s: Source[Int, ActorRef] = Source.actorPublisher[Int](Props(new MySourceActor))
class MySourceActor extends ActorPublisher[Int] { override def receive: Receive = { case ActorPublisherMessage.Request(n) => onNext(100) onCompleteThenStop() onErrorThenStop(new Exception) case ActorPublisherMessage.Cancel => context.stop(self) } }
48 Свой Source val s: Source[Int, ActorRef] = Source.actorPublisher[Int](Props(new MySourceActor))
class MySourceActor extends ActorPublisher[Int] { override def receive: Receive = { case ActorPublisherMessage.Request(n) => onNext(100) onCompleteThenStop() onErrorThenStop(new Exception) case ActorPublisherMessage.Cancel => context.stop(self) } }
48 Свой Source val s: Source[Int, ActorRef] = Source.actorPublisher[Int](Props(new MySourceActor))
class MySourceActor extends ActorPublisher[Int] { override def receive: Receive = { case ActorPublisherMessage.Request(n) => onNext(100) onCompleteThenStop() onErrorThenStop(new Exception) case ActorPublisherMessage.Cancel => context.stop(self) } }
48 Свой Source val s: Source[Int, ActorRef] = Source.actorPublisher[Int](Props(new MySourceActor))
class MySourceActor extends ActorPublisher[Int] { override def receive: Receive = { case ActorPublisherMessage.Request(n) => onNext(100) onCompleteThenStop() onErrorThenStop(new Exception) case ActorPublisherMessage.Cancel => context.stop(self) } }
48 Свой Source val s: Source[Int, ActorRef] = Source.actorPublisher[Int](Props(new MySourceActor))
class MySourceActor extends ActorPublisher[Int] { override def receive: Receive = { case ActorPublisherMessage.Request(n) => onNext(100) onCompleteThenStop() onErrorThenStop(new Exception) case ActorPublisherMessage.Cancel => context.stop(self) } }
48 Свой Source val s: Source[Int, ActorRef] = Source.actorPublisher[Int](Props(new MySourceActor))
class MySourceActor extends ActorPublisher[Int] { override def receive: Receive = { case ActorPublisherMessage.Request(n) => onNext(100) onCompleteThenStop() onErrorThenStop(new Exception) case ActorPublisherMessage.Cancel => context.stop(self) } }
48 Свой Source val s: Source[Int, ActorRef] = Source.actorPublisher[Int](Props(new MySourceActor))
class MySourceActor extends ActorPublisher[Int] { override def receive: Receive = { case ActorPublisherMessage.Request(n) => onNext(100) onCompleteThenStop() onErrorThenStop(new Exception) case ActorPublisherMessage.Cancel => context.stop(self) } }
49 Reactive Zmq case object GracefulStop case object DeliverMore class
MySourceActor(addr: String) extends ActorPublisher[Array[Byte]] { var conn: ZMQ.Socket = ??? override def preStart(): Unit = { conn.connect(addr) } override def postStop(): Unit = { conn.disconnect(addr) }
49 Reactive Zmq case object GracefulStop case object DeliverMore class
MySourceActor(addr: String) extends ActorPublisher[Array[Byte]] { var conn: ZMQ.Socket = ??? override def preStart(): Unit = { conn.connect(addr) } override def postStop(): Unit = { conn.disconnect(addr) }
49 Reactive Zmq case object GracefulStop case object DeliverMore class
MySourceActor(addr: String) extends ActorPublisher[Array[Byte]] { var conn: ZMQ.Socket = ??? override def preStart(): Unit = { conn.connect(addr) } override def postStop(): Unit = { conn.disconnect(addr) }
49 Reactive Zmq case object GracefulStop case object DeliverMore class
MySourceActor(addr: String) extends ActorPublisher[Array[Byte]] { var conn: ZMQ.Socket = ??? override def preStart(): Unit = { conn.connect(addr) } override def postStop(): Unit = { conn.disconnect(addr) }
49 Reactive Zmq case object GracefulStop case object DeliverMore class
MySourceActor(addr: String) extends ActorPublisher[Array[Byte]] { var conn: ZMQ.Socket = ??? override def preStart(): Unit = { conn.connect(addr) } override def postStop(): Unit = { conn.disconnect(addr) }
49 Reactive Zmq case object GracefulStop case object DeliverMore class
MySourceActor(addr: String) extends ActorPublisher[Array[Byte]] { var conn: ZMQ.Socket = ??? override def preStart(): Unit = { conn.connect(addr) } override def postStop(): Unit = { conn.disconnect(addr) }
49 Reactive Zmq case object GracefulStop case object DeliverMore class
MySourceActor(addr: String) extends ActorPublisher[Array[Byte]] { var conn: ZMQ.Socket = ??? override def preStart(): Unit = { conn.connect(addr) } override def postStop(): Unit = { conn.disconnect(addr) }
50 Reactive Zmq override def receive: Receive = { case
ActorPublisherMessage.Request(_) | DeliverMore => Option(conn.recv()) match { case Some(msg) => onNext(msg) if(totalDemand > 0) self ! DeliverMore case None => self ! DeliverMore } case ActorPublisherMessage.Cancel | GracefulStop => conn.disconnect(addr) onCompleteThenStop() }
50 Reactive Zmq override def receive: Receive = { case
ActorPublisherMessage.Request(_) | DeliverMore => Option(conn.recv()) match { case Some(msg) => onNext(msg) if(totalDemand > 0) self ! DeliverMore case None => self ! DeliverMore } case ActorPublisherMessage.Cancel | GracefulStop => conn.disconnect(addr) onCompleteThenStop() }
50 Reactive Zmq override def receive: Receive = { case
ActorPublisherMessage.Request(_) | DeliverMore => Option(conn.recv()) match { case Some(msg) => onNext(msg) if(totalDemand > 0) self ! DeliverMore case None => self ! DeliverMore } case ActorPublisherMessage.Cancel | GracefulStop => conn.disconnect(addr) onCompleteThenStop() }
50 Reactive Zmq override def receive: Receive = { case
ActorPublisherMessage.Request(_) | DeliverMore => Option(conn.recv()) match { case Some(msg) => onNext(msg) if(totalDemand > 0) self ! DeliverMore case None => self ! DeliverMore } case ActorPublisherMessage.Cancel | GracefulStop => conn.disconnect(addr) onCompleteThenStop() }
50 Reactive Zmq override def receive: Receive = { case
ActorPublisherMessage.Request(_) | DeliverMore => Option(conn.recv()) match { case Some(msg) => onNext(msg) if(totalDemand > 0) self ! DeliverMore case None => self ! DeliverMore } case ActorPublisherMessage.Cancel | GracefulStop => conn.disconnect(addr) onCompleteThenStop() }
50 Reactive Zmq override def receive: Receive = { case
ActorPublisherMessage.Request(_) | DeliverMore => Option(conn.recv()) match { case Some(msg) => onNext(msg) if(totalDemand > 0) self ! DeliverMore case None => self ! DeliverMore } case ActorPublisherMessage.Cancel | GracefulStop => conn.disconnect(addr) onCompleteThenStop() }
50 Reactive Zmq override def receive: Receive = { case
ActorPublisherMessage.Request(_) | DeliverMore => Option(conn.recv()) match { case Some(msg) => onNext(msg) if(totalDemand > 0) self ! DeliverMore case None => self ! DeliverMore } case ActorPublisherMessage.Cancel | GracefulStop => conn.disconnect(addr) onCompleteThenStop() }
50 Reactive Zmq override def receive: Receive = { case
ActorPublisherMessage.Request(_) | DeliverMore => Option(conn.recv()) match { case Some(msg) => onNext(msg) if(totalDemand > 0) self ! DeliverMore case None => self ! DeliverMore } case ActorPublisherMessage.Cancel | GracefulStop => conn.disconnect(addr) onCompleteThenStop() }
50 Reactive Zmq override def receive: Receive = { case
ActorPublisherMessage.Request(_) | DeliverMore => Option(conn.recv()) match { case Some(msg) => onNext(msg) if(totalDemand > 0) self ! DeliverMore case None => self ! DeliverMore } case ActorPublisherMessage.Cancel | GracefulStop => conn.disconnect(addr) onCompleteThenStop() }
50 Reactive Zmq override def receive: Receive = { case
ActorPublisherMessage.Request(_) | DeliverMore => Option(conn.recv()) match { case Some(msg) => onNext(msg) if(totalDemand > 0) self ! DeliverMore case None => self ! DeliverMore } case ActorPublisherMessage.Cancel | GracefulStop => conn.disconnect(addr) onCompleteThenStop() }
50 Reactive Zmq override def receive: Receive = { case
ActorPublisherMessage.Request(_) | DeliverMore => Option(conn.recv()) match { case Some(msg) => onNext(msg) if(totalDemand > 0) self ! DeliverMore case None => self ! DeliverMore } case ActorPublisherMessage.Cancel | GracefulStop => conn.disconnect(addr) onCompleteThenStop() }
51 Reactive Zmq val source: Source[Array[Byte], Control] = Source.actorPublisher[Array[Byte]]( Props(new
MySourceActor( ???)) ).mapMaterializedValue { ref => new Control { override def gracefulStop() = ref ! GracefulStop } }
51 Reactive Zmq val source: Source[Array[Byte], Control] = Source.actorPublisher[Array[Byte]]( Props(new
MySourceActor( ???)) ).mapMaterializedValue { ref => new Control { override def gracefulStop() = ref ! GracefulStop } }
51 Reactive Zmq val source: Source[Array[Byte], Control] = Source.actorPublisher[Array[Byte]]( Props(new
MySourceActor( ???)) ).mapMaterializedValue { ref => new Control { override def gracefulStop() = ref ! GracefulStop } }
51 Reactive Zmq val source: Source[Array[Byte], Control] = Source.actorPublisher[Array[Byte]]( Props(new
MySourceActor( ???)) ).mapMaterializedValue { ref => new Control { override def gracefulStop() = ref ! GracefulStop } }
51 Reactive Zmq val source: Source[Array[Byte], Control] = Source.actorPublisher[Array[Byte]]( Props(new
MySourceActor( ???)) ).mapMaterializedValue { ref => new Control { override def gracefulStop() = ref ! GracefulStop } }
51 Reactive Zmq val source: Source[Array[Byte], Control] = Source.actorPublisher[Array[Byte]]( Props(new
MySourceActor( ???)) ).mapMaterializedValue { ref => new Control { override def gracefulStop() = ref ! GracefulStop } }
51 Reactive Zmq val source: Source[Array[Byte], Control] = Source.actorPublisher[Array[Byte]]( Props(new
MySourceActor( ???)) ).mapMaterializedValue { ref => new Control { override def gracefulStop() = ref ! GracefulStop } }
52 Свой Sink val s = Sink.actorSubscriber[Int](Props(new MySinkActor)) class
MySinkActor extends ActorSubscriber { override def receive: Receive = { case ActorSubscriberMessage.OnNext => cancel() request(100) case ActorSubscriberMessage.OnComplete => case ActorSubscriberMessage.OnError => }
52 Свой Sink val s = Sink.actorSubscriber[Int](Props(new MySinkActor)) class
MySinkActor extends ActorSubscriber { override def receive: Receive = { case ActorSubscriberMessage.OnNext => cancel() request(100) case ActorSubscriberMessage.OnComplete => case ActorSubscriberMessage.OnError => }
52 Свой Sink val s = Sink.actorSubscriber[Int](Props(new MySinkActor)) class
MySinkActor extends ActorSubscriber { override def receive: Receive = { case ActorSubscriberMessage.OnNext => cancel() request(100) case ActorSubscriberMessage.OnComplete => case ActorSubscriberMessage.OnError => }
52 Свой Sink val s = Sink.actorSubscriber[Int](Props(new MySinkActor)) class
MySinkActor extends ActorSubscriber { override def receive: Receive = { case ActorSubscriberMessage.OnNext => cancel() request(100) case ActorSubscriberMessage.OnComplete => case ActorSubscriberMessage.OnError => }
52 Свой Sink val s = Sink.actorSubscriber[Int](Props(new MySinkActor)) class
MySinkActor extends ActorSubscriber { override def receive: Receive = { case ActorSubscriberMessage.OnNext => cancel() request(100) case ActorSubscriberMessage.OnComplete => case ActorSubscriberMessage.OnError => }
52 Свой Sink val s = Sink.actorSubscriber[Int](Props(new MySinkActor)) class
MySinkActor extends ActorSubscriber { override def receive: Receive = { case ActorSubscriberMessage.OnNext => cancel() request(100) case ActorSubscriberMessage.OnComplete => case ActorSubscriberMessage.OnError => }
52 Свой Sink val s = Sink.actorSubscriber[Int](Props(new MySinkActor)) class
MySinkActor extends ActorSubscriber { override def receive: Receive = { case ActorSubscriberMessage.OnNext => cancel() request(100) case ActorSubscriberMessage.OnComplete => case ActorSubscriberMessage.OnError => }
52 Свой Sink val s = Sink.actorSubscriber[Int](Props(new MySinkActor)) class
MySinkActor extends ActorSubscriber { override def receive: Receive = { case ActorSubscriberMessage.OnNext => cancel() request(100) case ActorSubscriberMessage.OnComplete => case ActorSubscriberMessage.OnError => }
52 Свой Sink val s = Sink.actorSubscriber[Int](Props(new MySinkActor)) class
MySinkActor extends ActorSubscriber { override def receive: Receive = { case ActorSubscriberMessage.OnNext => cancel() request(100) case ActorSubscriberMessage.OnComplete => case ActorSubscriberMessage.OnError => }
Итоги
• Стандартные комбинаторы • Материализация • Управление жизненным циклом •
Свои stages 54 Итоги
Серебряная пуля
• Более простая технология не подходит • Backpressure • Упорядоченные
потоки • Локальность • Фиксированная топология 56 Когда стоит использовать
• Документация Akka Streams • Альпака • reactive-zmq • reactive-kafka
• Первое видео про Akka Streams • Слайды этой презентации - goo.gl/F7EYoE 57 Ссылки
Вопросы?
[email protected]
@1esha
Backpressure
60 Событий слишком много
60 Событий слишком много Отправитель
60 Событий слишком много Отправитель Получатель
60 Событий слишком много Отправитель Получатель
61 Событий слишком много Отправитель Получатель
62 Событий слишком много Отправитель Получатель
63 Событий слишком много Отправитель Получатель
64 Событий слишком много Отправитель Получатель
65 Событий слишком много Отправитель Получатель
66 Событий слишком много Отправитель Получатель
67 Событий слишком много Отправитель Получатель
68 Блокирующий вызов Отправитель Получатель
68 Блокирующий вызов Отправитель Получатель
68 Блокирующий вызов Отправитель Получатель
69 Pull Отправитель Получатель
69 Pull Отправитель Получатель
69 Pull Отправитель Получатель
70 Negative Acknowledge Отправитель Получатель
70 Negative Acknowledge Отправитель Получатель
70 Negative Acknowledge Отправитель Получатель
71 Negative Acknowledge Отправитель Получатель
72 Dynamic pull-push Отправитель Получатель
72 Dynamic pull-push Отправитель Получатель 4
73 Dynamic pull-push 4 Отправитель Получатель
74 Dynamic pull-push 3 Отправитель Получатель
75 Dynamic pull-push 3 Отправитель Получатель
76 Dynamic pull-push 0 Отправитель Получатель
77 Dynamic pull-push 0 Отправитель Получатель
78 Dynamic pull-push 0 Отправитель Получатель
78 Dynamic pull-push 0 Отправитель Получатель 2
79 Dynamic pull-push 2 Отправитель Получатель
80 Dynamic pull-push 0 Отправитель Получатель
81 Balance Balance
81 Balance Balance
81 Balance Balance
82 Broadcast Broadcast
82 Broadcast Broadcast
82 Broadcast Broadcast
83 Zip Zip
83 Zip Zip
83 Zip Zip
84 Unzip Unzip
84 Unzip Unzip
84 Unzip Unzip
85 Красивый код на стримах val stream: RunnableGraph[Future[List[TransactionId]]] = Source
.fromIterator { () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
85 Красивый код на стримах val stream: RunnableGraph[Future[List[TransactionId]]] = Source
.fromIterator { () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
85 Красивый код на стримах val stream: RunnableGraph[Future[List[TransactionId]]] = Source
.fromIterator { () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
85 Красивый код на стримах val stream: RunnableGraph[Future[List[TransactionId]]] = Source
.fromIterator { () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
85 Красивый код на стримах val stream: RunnableGraph[Future[List[TransactionId]]] = Source
.fromIterator { () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
85 Красивый код на стримах val stream: RunnableGraph[Future[List[TransactionId]]] = Source
.fromIterator { () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
85 Красивый код на стримах val stream: RunnableGraph[Future[List[TransactionId]]] = Source
.fromIterator { () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
85 Красивый код на стримах val stream: RunnableGraph[Future[List[TransactionId]]] = Source
.fromIterator { () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
85 Красивый код на стримах val stream: RunnableGraph[Future[List[TransactionId]]] = Source
.fromIterator { () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
85 Красивый код на стримах val stream: RunnableGraph[Future[List[TransactionId]]] = Source
.fromIterator { () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
85 Красивый код на стримах val stream: RunnableGraph[Future[List[TransactionId]]] = Source
.fromIterator { () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
85 Красивый код на стримах val stream: RunnableGraph[Future[List[TransactionId]]] = Source
.fromIterator { () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
85 Красивый код на стримах val stream: RunnableGraph[Future[List[TransactionId]]] = Source
.fromIterator { () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
85 Красивый код на стримах val stream: RunnableGraph[Future[List[TransactionId]]] = Source
.fromIterator { () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
85 Красивый код на стримах val stream: RunnableGraph[Future[List[TransactionId]]] = Source
.fromIterator { () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)
85 Красивый код на стримах val stream: RunnableGraph[Future[List[TransactionId]]] = Source
.fromIterator { () => hdfs.listStatusIterator(path) } .filter(_.isFile) .flatMapConcat { file => val s = fromInputStream(hdfs.open(file.getPath)) Source.fromIterator(() => s.getLines()) } .throttle(10, 1 second, 0, ThrottleMode.Shaping) .mapAsyncUnordered(50)(checkFraud) .collect { case Some(value) => value } .take(100) .fold(List.empty[TransactionId])(_ :+ _) .toMat(Sink.head)(Keep.right)