From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory...

51
From Overnight to Always On Enno Runne Reactive Summit 2018-10-24

Transcript of From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory...

Page 1: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

From Overnight to Always On

Enno Runne Reactive Summit 2018-10-24

Page 2: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

• Alpakka Tech Lead @ Lightbend

• Stockholm, Sweden

Enno Runne

Page 3: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

File content as streams

Page 4: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

File-based integration

Disk

Read from file

Disk

Write to file

Page 5: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

InputStream is = new BufferedInputStream( new FileInputStream(sourceFilename)); OutputStream os = new BufferedOutputStream( new FileOutputStream(targetFilename));

byte[] buffer = new byte[1024]; int length; while ((length = is.read(buffer)) > 0) { os.write(buffer, 0, length); }

is.close(); os.close();

Copying a file in traditional Java

Page 6: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Let’s call it source and sink

Disk

Read from file

Disk

Write to file

Source<Byte…> Sink<Byte…>

Page 7: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

FileIO.fromPath(sourceFile) FileIO.toPath(targetFile)

File source and sink with Akka Streams

Disk

Read from file

Disk

Write to file

Source<ByteString, …> Sink<ByteString, …>

Page 8: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Source<ByteString,…> CompletionStage<IOResult fileSource = FileIO.fromPath(sourceFile); Sink<ByteString,…>CompletionStage<IOResult>>fileSink = FileIO.toPath(targetFile); fileSource .to(fileSink) .run(materializer);

Connect source and sink

Read from file

Write to file

Page 9: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Source<ByteString, CompletionStage<IOResult>> fileSource = FileIO.fromPath(sourceFile); Sink<ByteString, CompletionStage<IOResult>> fileSink = FileIO.toPath(targetFile);

CompletionStage<IOResult> handle = fileSource .to(fileSink) .run(materializer);

Materialized values

Page 10: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Source<ByteString, CompletionStage<IOResult>> fileSource = FileIO.fromPath(sourceFile); Sink<ByteString, CompletionStage<IOResult>> fileSink = FileIO.toPath(targetFile);

CompletionStage<IOResult> handle = fileSource .runWith( fileSink, materializer );

Materialized values

Page 11: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Copying a file with Akka Streams

Read from file

Write to file

CompletionStage<IOResult> handle = FileIO.fromPath(sourceFile) .runWith( FileIO.toPath(targetFile), materializer );

Page 12: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Copying a file with Akka Streams

Read from file

Write to file

CompletionStage<IOResult> handle = FileIO.fromPath(sourceFile) .runWith( FileIO.toPath(targetFile), materializer );

Page 13: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Data flow

Step 1 Step 4Step 2 Step 3

Buffering data• May cure the immediate issue • All buffering is limited

Page 14: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Downstream

Source SinkFlow Flow

Streaming with back-pressure

Dynamic push/pull • Push when downstream is faster • Pull when upstream is faster

Page 15: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Akka Streams

Page 16: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Source

TParts of a Stream

Sink

S

A B

Flow

Page 17: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

A B

Stream operators

map

A BmapAsync

A Bvia

Flow

Page 18: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Overnight Batching

Page 19: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Make our file-copy more useful

Disk

Read from file

Disk

Write to file

Detect new file

Page 20: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Detect a new file in the directory

DirectoryChangesSource.create( sourceDir, pollingInterval, maxChangesKept )

Detect new file

.filter(pathChange -> DirectoryChange.Creation == pathChange.second() )

// Pair<Path, DirectoryChange>

.map(Pair::first);

Source<Path, NotUsed> newFileDetector =

Page 21: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

We built our own source!

Page 22: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Combine the source with a stream

Disk

Read from file

Disk

Write to file

Detect new file

Page 23: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Combine the source with a stream with a sink

Disk

Read from file

Disk

Write to file

Detect new file

Page 24: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Combine the source with a stream with a sink

newFileDetector .mapAsync(8, p -> {

Path targetFile = targetDir.resolve(p.getFileName()); return createFileToFile(p, targetFile);

}) .runWith(Sink.ignore(), materializer);

Nesting a stream execution within a stream

Page 25: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Outer and inner flows

Disk

Read from file

Disk

Write to file

Detect new file

Page 26: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Reactive Streamsreactive-streams.org

Page 27: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Part of JDK 9 (java.util.concurrent.Flow)

http://www.reactive-streams.org/

Compliant libraries allow full interoperability

Reactive Streams

A standard for asynchronous stream processing with non-blocking back-pressure.

Page 28: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Reactive Integrations

Page 29: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Reactive Integrations

Cross-system back-pressure support is the key thing Reactive Integrations bring to the table.

Page 30: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Overcoming file-based

Page 31: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Overcoming file-based integration

Disk

Read from file ?

Page 32: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

From bytes to…

Page 33: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Overcoming file-based integration

Disk

Read from file

Parse bytes

bytes messages

Page 34: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Disk

Read from file

Parse CSV

bytes messages

Parse JSON

Parse XML

Overcoming file-based integration

Page 35: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Parse as CSV with Alpakka

Parse CSV

lines

byteStringSource .via(CsvParsing.lineScanner())

Convert CSV lines to maps

ByteString Collection<ByteString> Map<String, String>

.via(CsvToMap.toMapAsStrings(StandardCharsets.UTF_8));

Page 36: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Flow<ByteString, Map<String, String>, NotUsed> csvBytesToMap =

Flow.of(ByteString.class)

.via(CsvParsing.lineScanner())

.via(CsvToMap.toMapAsStrings( StandardCharsets.UTF_8 ));

Build your own flow

Page 37: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance; FileIO.fromPath(p) .via(csvBytesToMap) .map(data -> { // Using raw Jackson to create JSON objects ObjectNode objectNode = jsonNodeFactory.objectNode(); data.forEach(objectNode::put); return objectNode; })

Use your own flow and apply data mappingFlow<ByteString, Map<String, String>, NotUsed> csvBytesToMap = Flow.of(ByteString.class) .via(CsvParsing.lineScanner()) .via(CsvToMap.toMapAsStrings(StandardCharsets.UTF_8));

Page 38: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Overcoming file-based integration

Disk

Read from file

Parse CSV

bytes JSONMap Map to JSON

Page 39: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

What is a stream?

Photo by blucolt - originally posted to Flickr as spearfish creek, CC BY-SA 2.0

50,000 / s 10 / s

1 / month

Page 40: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Reactive File Integration

Disk

Read from file

Destination

Detect new file

Turn into

messages

Other technology

Page 41: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •
Page 42: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Alpakka is a Reactive Enterprise Integration library for Java and Scala, based on Reactive Streams and Akka.

Alpakka

The short version: “Endpoints for Akka Streams”

Page 43: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Alpakka • Typed message interchange,

compiler tracks compatibility

• Back-pressure as specified by Reactive Streams

• No OSGi support

• Relies on Akka Streams; evolving rapidly, but many integration requirements are not covered, yet

• Moving fast, docs split between Akka and Alpakka sites

My view on Apache Camel vs Alpakka

Apache Camel • Data is wrapped in Exchange instance,

type can only be inspected

• No back-pressure awareness, can connect to Reactive Streams compliant systems

• OSGi support

• Full-featured framework to express integrations

• Comprehensive docs and books

Page 44: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Alpakka connectors for cloud services

Amazon DynamoDB Amazon Kinesis data streams & firehose AWS Lambda Amazon S3 Amazon SNS Amazon SQS

Google Cloud Pub/Sub Google Firebase Cloud Messaging

Azure Storage Queue

Page 45: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Alpakka connectors for data stores

Elasticsearch

Page 46: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Alpakka connectors for messaging

(Eclipse Paho)

AMQP (RabbitMQ)

IronMQ

JMS Java Messaging Service

Apache Kafka

… not as fancy logos, but very well suited for the streaming approach.

Page 47: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Community connectors to Akka Streams

Apache Camel Couchbase Eventuate FS2 Pulsar

… if you know of more, please tell us.

Page 48: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •
Page 49: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Preparations for Alpakka 1.0 include

• structure all modules the same

• improve chances to stay binary compatible

• ensure good test coverage

Help with this is highly appreciated…

The road to Alpakka 1.0

Page 50: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Code, Issues, Pull Requests @ Github

• https://github.com/akka/alpakka

• https://github.com/akka/alpakka-kafka

Questions, Discussions

• https://discuss.lightbend.com/c/akka

Alpakka community

Page 51: From Overnight to Always On · 2018-10-29 · Build your own flow. JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance ... connect to Reactive Streams compliant systems •

Thank you!

@ennru [email protected]

https://www.lightbend.com/alpakka @akkateam

Join the Alpakka community at github.com/akka/alpakka