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
Практическое применение Akka Streams
Search
devday2gis
January 23, 2017
Technology
1.1k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Практическое применение Akka Streams
Несколько жизненных примеров использования Akka Streams
devday2gis
January 23, 2017
Other Decks in Technology
See All in Technology
AI導入は済んだ。次は統制を作り替える番だ_AI×開発組織 Summit 2026
techtekt
PRO
0
210
Classmethod Company Deck
satoshi7
1
680
Tofu-Controller lightning talk @ Containerday 2026
gionn
0
110
「Docker Desktop不要の時代」は 来たのか?
ueponx
0
770
PagerDuty Tech Hub-鳴らすけれど、人は動かない
ezaki
0
170
Gemini Intelligence 入門 ― AppFunctions と Gemini Nano
takuroabe
0
250
Browser Spec: Testing Hotwire with Ruby
takahashim
1
120
『SAR衛星データ解析入門』のご紹介とその応用
syuchimu
0
120
[JAWS-UG彩の国埼玉#12]そろそろ準備する?re:Invent2026をやさしく解説 / reinvent2026-sainokuni
sh_fk2
1
340
宣言型部分更新は何を解決しどこへ向かうのか
shuta13
1
450
ブラウザとサーバーから考えるAI時代のフロントエンド監視
shogo4131
3
940
TinyGoでオブザーバビリティ?OpenTelemetryはTinyGoで使えるのか / Is OpenTelemetry available in TinyGo environment?
ymotongpoo
2
140
Featured
See All Featured
Discover your Explorer Soul
emna__ayadi
2
1.3k
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
BBQ
matthewcrist
90
10k
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
2
2.9k
HDC tutorial
michielstock
2
960
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
GitHub's CSS Performance
jonrohan
1033
470k
Reflections from 52 weeks, 52 projects
jeffersonlam
356
22k
Making Projects Easy
brettharned
120
6.8k
How to Grow Your eCommerce with AI & Automation
katarinadahlin
PRO
2
330
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
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)