SlideShare a Scribd company logo
1 of 58
Introduction to ParSeq
To make asynchronous Java easier
Synchronous
● Result is ready when method returns
● What about methods void e.g.
void deletePerson(Long id)
● Unchecked exception (or it’s lack) is part of a
result
● Error handling through optional try-catch
mechanism
Person fetchPerson(Long id)
2
Asynchronous
● Result may be ready long after method
returns
● There must be a way to access result e.g.
using Callback or Promise
● Custom error handling
void fetchPerson(Long id, Callback callback)
void Promise<Person> fetchPerson(Long id)
3
Synchronous
fetch wait processBodyThread 1 fetch wait processBody
String googleBody = fetchBody("http://www.google.com"); //wait
processBody(googleBody);
String bingBody = fetchBody("http://www.bing.com"); //wait
processBody(bingBody);
time
waitThread 1 wait
In reality:
4
other tasks
Asynchronous
Task.par(
fetchBody("http://www.google.com").andThen(this::processBody),
fetchBody("http://www.bing.com").andThen(this::processBody)
);
fetch
wait
processBody
Thread 1 fetch
wait
processBodyThread 2
other tasks
time
5
Challenges
● Accidental complexity, unreadable code e.g.
doAsync1(function () {
doAsync2(function () {
doAsync3(function () {
doAsync4(function () {
...
})
})
})
6
Challenges
● Indeterminism
○ n! many orders in which all asynchronous operations
can finish
○ Difficult to test
○ No “current state”
● Debugging
○ State of the art is println() sprinkled around
○ No meaningful stack trace
7
Challenges
● Thread safety
○ Synchronized, locks, volatile, atomic, j.u.c.*
○ Immutability
○ 3rd party libraries
○ Thinking about Java Memory Model
○ Thread safety does not mean atomicity
8
Challenges
● Often requires all-async
//fetching Alice and Bob asynchronously
fetchPerson(aliceId, handleAliceCallback);
fetchPerson(bobId, handleBobCallback);
// hmmm... now what?
9
Core concepts: Promise<T>
● Represents state of an asynchronous
operation
● Possible states: completed (resolved),
uncompleted (unresolved)
● Container for a result of an asynchronous
operation
● Result of completed Promise<T> is either
value of type T or an exception 10
Core concepts: Task<T>
● Main abstraction and building block in
ParSeq, represents asynchronous operation
● Main ingredient of a Task<T> is a clojure
that (synchronously) returns a Promise<T>,
as if Task<T> had void Promise<T> run(...)
● Clojure starts asynchronous operation and
returns a Promise that represents the state
of that operation 11
Core concepts: Task<T>
Callable<Promise<String>> callable = () -> {
SettablePromise<String> promise = Promises.settable();
return promise;
};
● Closest construct in pure Java is a
Callable<Promise<T>>
Task<String> task = Task.async(name, () -> {
SettablePromise<String> promise = Promises.settable();
return promise;
}); 12
Core concepts: Task<T>
Callable<Promise<String>> callable = () -> {
SettablePromise<String> promise = Promises.settable();
return promise;
};
● Closest construct in pure Java is a
Callable<Promise<T>>
Task<String> task = Task.async(name, () -> {
SettablePromise<String> promise = Promises.settable();
return promise;
});
clojure
13
Core concepts: Task<T>
public <T> Promise<Response<T>> sendRequest(Request<T> request,
RequestContext requestContext) {
SettablePromise<Response<T>> promise = Promises.settable();
_restClient.sendRequest(request, requestContext,
new PromiseCallbackAdapter<T>(promise));
return promise;
}
Task<Response<T>> task =
Task.async(name, () -> sendRequest(request, requestContext));
● Real example from ParSeqRestClient
14
Core concepts: Task<T>
public <T> Promise<Response<T>> sendRequest(Request<T> request,
RequestContext requestContext) {
SettablePromise<Response<T>> promise = Promises.settable();
_restClient.sendRequest(request, requestContext,
new PromiseCallbackAdapter<T>(promise));
return promise;
}
Task<Response<T>> task =
Task.async(name, () -> sendRequest(request, requestContext));
● Real example from ParSeqRestClient
clojure
15
Core concepts: Task<T>
time
● Example execution of tasks
○ clojure synchronously returns a Promise<T>
○ Promise is completed at some point in the future
clojure
execution
Promise
completion
16
Properties of Tasks
● Tasks are lazy - creating a Task instance
does not automatically run it
● Task runs at most once
● Tasks are immutable - all Task.* methods
return new Tasks
● Programming with Tasks comes down to
creating new Tasks that depend on existing
ones (composition) 17
Creating Tasks from scratch
● Usually there is no need to create Task from
scratch using Task.async(...), instead use
existing library e.g.
_parseqRestClient.createTask(...)
● If there is a need to create a Task from
scratch use Task.async(...), don’t extend
BaseTask class
18
Parallel Composition
● Task.par(t1, t2, …)
Task<?> par3 = Task.par(fetchBing, fetchGoogle, fetchYahoo)
19
Parallel Composition
● Task.par(t1, t2, …)
Task<?> par3 = Task.par(fetchBing, fetchGoogle, fetchYahoo)
time
20
Parallel Composition
● Task.par(t1, t2, …)
Task<?> par3 = Task.par(fetchBing, fetchGoogle, fetchYahoo)
time
clojure
execution
Promise
completion
21
Sequential Composition
● Do something after Task (it’s Promise) is completed
Task<String> seq = fetchBing.andThen("seq", fetchGoogle);
22
Sequential Composition
● Do something after Task (it’s Promise) is completed
Task<String> seq = fetchBing.andThen("seq", fetchGoogle);
time
23
Sequential Composition
● Do something after Task (it’s Promise) is completed
Task<String> seq = fetchBing.andThen("seq", fetchGoogle);
time
clojure
execution
Promise
completion
24
ParSeq API: map
● Transforms result of a task
Task<String> name = Task.value("Jaroslaw");
Task<Integer> length = name.map(String::length);
25
ParSeq API: flatMap
● Runs Task that depends on result of previous Task
● fetchCompany() invoked after fetchPerson() completes
public Task<Company> fetchCompany(int id) {...}
public Task<Person> fetchPerson(int id) {...}
Task<Person> personTask = fetchPerson(id);
Task<Company> companyTask =
personTask.flatMap(person ->
fetchCompany(person.getCompanyId()));
vs
Task<Task<Company>> companyTask =
personTask.map(person ->
fetchCompany(person.getCompanyId()));
26
Exceptions handling
● All exceptions are automatically propagated
Task<Integer> fetchAndLength =
fetch404Url("http://www.google.com/idontexist")
.map("length", String::length);
● Clojures can throw checked and unchecked exceptions
fetchBody("http://www.bing.com")
.andThen(s -> { throw new IOException(); });
27
Exceptions handling
● Task API has methods to handle exceptions, equivalent
to try-catch for synchronous methods, e.g. recover()
Task<Integer> fetchAndLength =
fetch404Url("http://www.google.com/idontexist")
.recover("default", t -> "")
.map("length", s -> s.length());
28
Exceptions handling
● Exceptions can be handled explicitly, see methods
toTry(), transform()
● Try<T> interface has only two implementation:
Success<T> and Failure<T>
Task<Try<String>> tryFetch =
fetch404Url("http://www.google.com/idontexist")
.toTry();
29
withTimeout
● Fails Task if it is not completed within specified amount
of time
Task<String> fetchWithTimeout =
fetchUrl("http://www.google.com")
.withTimeout(15, TimeUnit.MILLISECONDS);
30
withTimeout
● Fails Task if it is not completed within specified amount
of time
Task<String> fetchWithTimeout =
fetchUrl("http://www.google.com")
.withTimeout(15, TimeUnit.MILLISECONDS);
time
31
ParSeq API
● ParSeq API is declarative
● Focus on “what” not “how”
● Task<T> interface does not have run() method
32
ParSeq programming model
● Express everything by composing and
transforming Tasks
● End up with one Task (Plan) that is passed
to ParSeq Engine for execution
● Rest.li implements this idea
@RestMethod.Get
public Task<Greeting> get(final Long id) {
// rest.li resource implementation
} 33
ParSeq execution model
● ParSeq Engine provides the following
guarantees:
○ Rules expressed in ParSeq API are followed e.g.
first.andThen(second) - “second” will run after “first”
is completed
○ All clojures are executed sequentially, such that
clojure of a previous Task in a sequence “happens
before” clojure of a next Task (“happens before” in
the Java Memory Model sense)
34
Clojures are executed sequentially
● All operations passed to Task.* API are
executed within a Task’s clojure
Task<Integer> length =
fetchBody("http://www.google.com")
.map("length", String::length);
time
35
Clojures are executed sequentially
● All operations passed to Task.* API are
executed within a clojure
Task<Integer> length =
fetchBody("http://www.google.com")
.map("length", String::length);
time
clojure
36
Clojures are executed sequentially
● All operations passed to Task.* API are
automatically thread safe and atomic
● No need to be concerned about:
○ Synchronized, locks, volatile, atomic, j.u.c.*
○ Immutability
○ 3rd party libraries
○ Thinking about Java Memory Model
○ Thread safety does not mean atomicity
37
Clojures are executed sequentially
● Example: find top N Candidates (synchronous)
PriorityQueue<Candidate> topCandidates = new PriorityQueue<>();
void considerCandidate(Candidate candidate) {
topCandidates.add(candidate);
if (topCandidates.size() > N) {
topCandidates.remove();
}
}
38
Clojures are executed sequentially
● Example: find top N Candidates (asynchronous)
Task<Candidate> fetchCandidate(Long Id) {...}
Task<?> considerCandidate(Long id) {
return fetchCandidate(id)
.andThen(this::considerCandidate);
}
● Using thread safe PriorityQueue is not enough
● No need to test concurrency aspect 39
Clojures are executed sequentially
Task<?> par3 = Task.par(fetchBing, fetchGoogle, fetchYahoo)
time
● Task.par(t1, t2, …) example
40
Clojures are executed sequentially
41
Clojures are executed sequentially
Task.par(
Task.callable("1000th prime", () -> nthPrime(1000)),
Task.callable("1000th prime", () -> nthPrime(1000)),
Task.callable("1000th prime", () -> nthPrime(1000))
);
● Task.par(t1, t2, …) example
time
42
Clojures are executed sequentially
● Does it mean that ParSeq is single threaded?
● No
Task.par(
fetchBody("http://www.google.com").andThen(this::processBody),
fetchBody("http://www.bing.com").andThen(this::processBody)
);
43
Clojures are executed sequentially
● Does it mean that ParSeq is single threaded?
● No
time
other tasks
other tasks
wait
processBodyThread 1
wait
Thread 2
fetch
fetch processBody
44
other tasks
Clojures are executed sequentially
● Does it mean that ParSeq is single threaded?
● No
other tasks
wait
processBodyThread 1
wait
Thread 2
time
fetch
happens
before
fetch processBody
happens
before
45
Clojures are executed sequentially
● In order to perform well ParSeq requires
developer’s cooperation. In clojures avoid:
○ blocking e.g. JDBC calls, Thread.sleep(), ...
○ CPU intensive operations
46
Blocking
● Blocking API e.g. Voldemort, JDBC
● CPU intensive computation
● Offload operation to external Executor
Task.blocking(String name,
Callable<? extends T> callable,
Executor executor)
● Supports multiple executors
● Executors management is outside ParSeq 47
Automatic cancellation
● Task abstraction borrows ideas from functional
programming, think: Task ~ function call
○ Task is lazy, only runs when needed
○ Task is immutable
○ It’s purpose is to calculate a result
○ Task runs at most once
○ Once result is known, everything that is still not
completed (for some reason) can be cancelled because
it can’t affect result
48
Automatic cancellation
Task<String> google = fetchBody("http://www.google.com");
Task<String> yahoo = fetchBody("http://www.yahoo.com");
Task<String> bing = fetchBody("http://www.~#fdcm x 0eirw.com");
Task<Integer> sumLengths =
Task.par(google.map("length", String::length),
yahoo.map("length", String::length),
bing.map("length", String::length))
.map("sum", (g, y, b) -> g + y + b);
49
Automatic cancellation
50
Tracing
● Trace is information about what happened
after calling Engine.run()
● Tracing is always enabled for all tasks
● Allows reasoning about what happened
● Includes timing information, exceptions, etc.
● Obtain trace JSON at any time by calling
Task.getTrace().toString()
● Paste JSON at go/tracevis to visualize 51
Tracing best practices
● Add short, meaningful description to every
task
HttpClient.get(url).task()
.map("getBody", response -> response.getResponseBody())
.map("length", s -> s.length());
52
Tasks Fusion
● Sequence of synchronous transformations
can be optimized and executed as a chain of
method calls
Task<Integer> length =
HttpClient.get("http://www.google.com").task()
.map("getBody", Response::getResponseBody)
.map("length", s -> s.length());
53
Batching
● Allows automatic batching of individual
asynchronous operations without affecting
code readability
54
Unit testing
● Use BaseEngineTest as a base class for a
unit test
○ Initialization and shutdown of Engine
○ Lot of helper methods
● Log trace for the tested Task
55
Best Practices
● Focus on readable, clean code
○ Split code into small, unit-testable methods that may
return Task<T>
○ Prefer method handles over lambdas
○ Limit length of lambda code blocks to few lines
○ Don’t mix functional APIs inside lambda code block
e.g. Java Stream map() and Java Optional map()
with ParSeq map()
56
Upcoming feature
● Automatic batching of GET / BATCH_GET
requests in ParSeqRestClient
● Configurable timeouts in ParSeqRestClient
● Automatic logging traces of failed plans
● Sending sample of traces to kafka for
analysis e.g. finding bottlenecks,
regressions, thread blocking, …
● ParSeq “Collections” 57
Reference
● https://github.com/linkedin/parseq/wiki
● http://linkedin.github.io/parseq/javadoc/latest
58

More Related Content

What's hot

If You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongIf You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are Wrong
Mario Fusco
 
DBA Fundamentals Group: Continuous SQL with Kafka and Flink
DBA Fundamentals Group: Continuous SQL with Kafka and FlinkDBA Fundamentals Group: Continuous SQL with Kafka and Flink
DBA Fundamentals Group: Continuous SQL with Kafka and Flink
Timothy Spann
 

What's hot (20)

An Introduction To REST API
An Introduction To REST APIAn Introduction To REST API
An Introduction To REST API
 
Hadoop summit - Scaling Uber’s Real-Time Infra for Trillion Events per Day
Hadoop summit - Scaling Uber’s Real-Time Infra for  Trillion Events per DayHadoop summit - Scaling Uber’s Real-Time Infra for  Trillion Events per Day
Hadoop summit - Scaling Uber’s Real-Time Infra for Trillion Events per Day
 
Graphql presentation
Graphql presentationGraphql presentation
Graphql presentation
 
Rest API
Rest APIRest API
Rest API
 
Introduction to Apache Airflow
Introduction to Apache AirflowIntroduction to Apache Airflow
Introduction to Apache Airflow
 
Asynchronous Programming at Netflix
Asynchronous Programming at NetflixAsynchronous Programming at Netflix
Asynchronous Programming at Netflix
 
Lazy java
Lazy javaLazy java
Lazy java
 
Kafka Retry and DLQ
Kafka Retry and DLQKafka Retry and DLQ
Kafka Retry and DLQ
 
REST API Design & Development
REST API Design & DevelopmentREST API Design & Development
REST API Design & Development
 
Java 8 lambda expressions
Java 8 lambda expressionsJava 8 lambda expressions
Java 8 lambda expressions
 
If You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongIf You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are Wrong
 
Introduction to GraphQL
Introduction to GraphQLIntroduction to GraphQL
Introduction to GraphQL
 
GraphQL Introduction
GraphQL IntroductionGraphQL Introduction
GraphQL Introduction
 
Building Automated REST APIs with Python
Building Automated REST APIs with PythonBuilding Automated REST APIs with Python
Building Automated REST APIs with Python
 
API Design, A Quick Guide to REST, SOAP, gRPC, and GraphQL, By Vahid Rahimian
API Design, A Quick Guide to REST, SOAP, gRPC, and GraphQL, By Vahid RahimianAPI Design, A Quick Guide to REST, SOAP, gRPC, and GraphQL, By Vahid Rahimian
API Design, A Quick Guide to REST, SOAP, gRPC, and GraphQL, By Vahid Rahimian
 
DBA Fundamentals Group: Continuous SQL with Kafka and Flink
DBA Fundamentals Group: Continuous SQL with Kafka and FlinkDBA Fundamentals Group: Continuous SQL with Kafka and Flink
DBA Fundamentals Group: Continuous SQL with Kafka and Flink
 
Event-Driven Messaging and Actions using Apache Flink and Apache NiFi
Event-Driven Messaging and Actions using Apache Flink and Apache NiFiEvent-Driven Messaging and Actions using Apache Flink and Apache NiFi
Event-Driven Messaging and Actions using Apache Flink and Apache NiFi
 
Building a fully managed stream processing platform on Flink at scale for Lin...
Building a fully managed stream processing platform on Flink at scale for Lin...Building a fully managed stream processing platform on Flink at scale for Lin...
Building a fully managed stream processing platform on Flink at scale for Lin...
 
Saturn 2018 rest.li
Saturn 2018 rest.liSaturn 2018 rest.li
Saturn 2018 rest.li
 
Java 8 Lambda Expressions
Java 8 Lambda ExpressionsJava 8 Lambda Expressions
Java 8 Lambda Expressions
 

Similar to Introduction to ParSeq: to make asynchronous java easier

Promises look into the async future
Promises look into the async futurePromises look into the async future
Promises look into the async future
slicejs
 
Jdk 7 4-forkjoin
Jdk 7 4-forkjoinJdk 7 4-forkjoin
Jdk 7 4-forkjoin
knight1128
 
CompletableFuture
CompletableFutureCompletableFuture
CompletableFuture
koji lin
 

Similar to Introduction to ParSeq: to make asynchronous java easier (20)

The evolution of java script asynchronous calls
The evolution of java script asynchronous callsThe evolution of java script asynchronous calls
The evolution of java script asynchronous calls
 
Advanced patterns in asynchronous programming
Advanced patterns in asynchronous programmingAdvanced patterns in asynchronous programming
Advanced patterns in asynchronous programming
 
The Promised Land (in Angular)
The Promised Land (in Angular)The Promised Land (in Angular)
The Promised Land (in Angular)
 
Google App Engine Developer - Day3
Google App Engine Developer - Day3Google App Engine Developer - Day3
Google App Engine Developer - Day3
 
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
 
Promise: async programming hero
Promise: async programming heroPromise: async programming hero
Promise: async programming hero
 
Leverage CompletableFutures to handle async queries. DevNexus 2022
Leverage CompletableFutures to handle async queries. DevNexus 2022Leverage CompletableFutures to handle async queries. DevNexus 2022
Leverage CompletableFutures to handle async queries. DevNexus 2022
 
Scheduling tasks the human way - Brad Wood - ITB2021
Scheduling tasks the human way -  Brad Wood - ITB2021Scheduling tasks the human way -  Brad Wood - ITB2021
Scheduling tasks the human way - Brad Wood - ITB2021
 
Leveraging Completable Futures to handle your query results Asynchrhonously
Leveraging Completable Futures to handle your query results AsynchrhonouslyLeveraging Completable Futures to handle your query results Asynchrhonously
Leveraging Completable Futures to handle your query results Asynchrhonously
 
Promises look into the async future
Promises look into the async futurePromises look into the async future
Promises look into the async future
 
Binary Studio Academy: Concurrency in C# 5.0
Binary Studio Academy: Concurrency in C# 5.0Binary Studio Academy: Concurrency in C# 5.0
Binary Studio Academy: Concurrency in C# 5.0
 
Jdk 7 4-forkjoin
Jdk 7 4-forkjoinJdk 7 4-forkjoin
Jdk 7 4-forkjoin
 
동기화 시대를 뛰어넘는 비동기 프로그래밍
동기화 시대를 뛰어넘는 비동기 프로그래밍동기화 시대를 뛰어넘는 비동기 프로그래밍
동기화 시대를 뛰어넘는 비동기 프로그래밍
 
CompletableFuture
CompletableFutureCompletableFuture
CompletableFuture
 
Threads, Queues, and More: Async Programming in iOS
Threads, Queues, and More: Async Programming in iOSThreads, Queues, and More: Async Programming in iOS
Threads, Queues, and More: Async Programming in iOS
 
Scala Future & Promises
Scala Future & PromisesScala Future & Promises
Scala Future & Promises
 
Async js - Nemetschek Presentaion @ HackBulgaria
Async js - Nemetschek Presentaion @ HackBulgariaAsync js - Nemetschek Presentaion @ HackBulgaria
Async js - Nemetschek Presentaion @ HackBulgaria
 
Silicon Valley JUG: JVM Mechanics
Silicon Valley JUG: JVM MechanicsSilicon Valley JUG: JVM Mechanics
Silicon Valley JUG: JVM Mechanics
 
Flink Forward Berlin 2017: Maciek Próchniak - TouK Nussknacker - creating Fli...
Flink Forward Berlin 2017: Maciek Próchniak - TouK Nussknacker - creating Fli...Flink Forward Berlin 2017: Maciek Próchniak - TouK Nussknacker - creating Fli...
Flink Forward Berlin 2017: Maciek Próchniak - TouK Nussknacker - creating Fli...
 
function* - ES6, generators, and all that (JSRomandie meetup, February 2014)
function* - ES6, generators, and all that (JSRomandie meetup, February 2014)function* - ES6, generators, and all that (JSRomandie meetup, February 2014)
function* - ES6, generators, and all that (JSRomandie meetup, February 2014)
 

Recently uploaded

Online crime reporting system project.pdf
Online crime reporting system project.pdfOnline crime reporting system project.pdf
Online crime reporting system project.pdf
Kamal Acharya
 
Activity Planning: Objectives, Project Schedule, Network Planning Model. Time...
Activity Planning: Objectives, Project Schedule, Network Planning Model. Time...Activity Planning: Objectives, Project Schedule, Network Planning Model. Time...
Activity Planning: Objectives, Project Schedule, Network Planning Model. Time...
Lovely Professional University
 
Complex plane, Modulus, Argument, Graphical representation of a complex numbe...
Complex plane, Modulus, Argument, Graphical representation of a complex numbe...Complex plane, Modulus, Argument, Graphical representation of a complex numbe...
Complex plane, Modulus, Argument, Graphical representation of a complex numbe...
MohammadAliNayeem
 
Maher Othman Interior Design Portfolio..
Maher Othman Interior Design Portfolio..Maher Othman Interior Design Portfolio..
Maher Othman Interior Design Portfolio..
MaherOthman7
 
Final DBMS Manual (2).pdf final lab manual
Final DBMS Manual (2).pdf final lab manualFinal DBMS Manual (2).pdf final lab manual
Final DBMS Manual (2).pdf final lab manual
BalamuruganV28
 

Recently uploaded (20)

Interfacing Analog to Digital Data Converters ee3404.pdf
Interfacing Analog to Digital Data Converters ee3404.pdfInterfacing Analog to Digital Data Converters ee3404.pdf
Interfacing Analog to Digital Data Converters ee3404.pdf
 
"United Nations Park" Site Visit Report.
"United Nations Park" Site  Visit Report."United Nations Park" Site  Visit Report.
"United Nations Park" Site Visit Report.
 
analog-vs-digital-communication (concept of analog and digital).pptx
analog-vs-digital-communication (concept of analog and digital).pptxanalog-vs-digital-communication (concept of analog and digital).pptx
analog-vs-digital-communication (concept of analog and digital).pptx
 
Online crime reporting system project.pdf
Online crime reporting system project.pdfOnline crime reporting system project.pdf
Online crime reporting system project.pdf
 
Involute of a circle,Square, pentagon,HexagonInvolute_Engineering Drawing.pdf
Involute of a circle,Square, pentagon,HexagonInvolute_Engineering Drawing.pdfInvolute of a circle,Square, pentagon,HexagonInvolute_Engineering Drawing.pdf
Involute of a circle,Square, pentagon,HexagonInvolute_Engineering Drawing.pdf
 
Fabrication Of Automatic Star Delta Starter Using Relay And GSM Module By Utk...
Fabrication Of Automatic Star Delta Starter Using Relay And GSM Module By Utk...Fabrication Of Automatic Star Delta Starter Using Relay And GSM Module By Utk...
Fabrication Of Automatic Star Delta Starter Using Relay And GSM Module By Utk...
 
Activity Planning: Objectives, Project Schedule, Network Planning Model. Time...
Activity Planning: Objectives, Project Schedule, Network Planning Model. Time...Activity Planning: Objectives, Project Schedule, Network Planning Model. Time...
Activity Planning: Objectives, Project Schedule, Network Planning Model. Time...
 
Electrical shop management system project report.pdf
Electrical shop management system project report.pdfElectrical shop management system project report.pdf
Electrical shop management system project report.pdf
 
5G and 6G refer to generations of mobile network technology, each representin...
5G and 6G refer to generations of mobile network technology, each representin...5G and 6G refer to generations of mobile network technology, each representin...
5G and 6G refer to generations of mobile network technology, each representin...
 
Complex plane, Modulus, Argument, Graphical representation of a complex numbe...
Complex plane, Modulus, Argument, Graphical representation of a complex numbe...Complex plane, Modulus, Argument, Graphical representation of a complex numbe...
Complex plane, Modulus, Argument, Graphical representation of a complex numbe...
 
Research Methodolgy & Intellectual Property Rights Series 1
Research Methodolgy & Intellectual Property Rights Series 1Research Methodolgy & Intellectual Property Rights Series 1
Research Methodolgy & Intellectual Property Rights Series 1
 
Introduction to Heat Exchangers: Principle, Types and Applications
Introduction to Heat Exchangers: Principle, Types and ApplicationsIntroduction to Heat Exchangers: Principle, Types and Applications
Introduction to Heat Exchangers: Principle, Types and Applications
 
Maher Othman Interior Design Portfolio..
Maher Othman Interior Design Portfolio..Maher Othman Interior Design Portfolio..
Maher Othman Interior Design Portfolio..
 
SLIDESHARE PPT-DECISION MAKING METHODS.pptx
SLIDESHARE PPT-DECISION MAKING METHODS.pptxSLIDESHARE PPT-DECISION MAKING METHODS.pptx
SLIDESHARE PPT-DECISION MAKING METHODS.pptx
 
Final DBMS Manual (2).pdf final lab manual
Final DBMS Manual (2).pdf final lab manualFinal DBMS Manual (2).pdf final lab manual
Final DBMS Manual (2).pdf final lab manual
 
15-Minute City: A Completely New Horizon
15-Minute City: A Completely New Horizon15-Minute City: A Completely New Horizon
15-Minute City: A Completely New Horizon
 
Lesson no16 application of Induction Generator in Wind.ppsx
Lesson no16 application of Induction Generator in Wind.ppsxLesson no16 application of Induction Generator in Wind.ppsx
Lesson no16 application of Induction Generator in Wind.ppsx
 
Circuit Breaker arc phenomenon.pdf engineering
Circuit Breaker arc phenomenon.pdf engineeringCircuit Breaker arc phenomenon.pdf engineering
Circuit Breaker arc phenomenon.pdf engineering
 
Theory for How to calculation capacitor bank
Theory for How to calculation capacitor bankTheory for How to calculation capacitor bank
Theory for How to calculation capacitor bank
 
Diploma Engineering Drawing Qp-2024 Ece .pdf
Diploma Engineering Drawing Qp-2024 Ece .pdfDiploma Engineering Drawing Qp-2024 Ece .pdf
Diploma Engineering Drawing Qp-2024 Ece .pdf
 

Introduction to ParSeq: to make asynchronous java easier

  • 1. Introduction to ParSeq To make asynchronous Java easier
  • 2. Synchronous ● Result is ready when method returns ● What about methods void e.g. void deletePerson(Long id) ● Unchecked exception (or it’s lack) is part of a result ● Error handling through optional try-catch mechanism Person fetchPerson(Long id) 2
  • 3. Asynchronous ● Result may be ready long after method returns ● There must be a way to access result e.g. using Callback or Promise ● Custom error handling void fetchPerson(Long id, Callback callback) void Promise<Person> fetchPerson(Long id) 3
  • 4. Synchronous fetch wait processBodyThread 1 fetch wait processBody String googleBody = fetchBody("http://www.google.com"); //wait processBody(googleBody); String bingBody = fetchBody("http://www.bing.com"); //wait processBody(bingBody); time waitThread 1 wait In reality: 4
  • 6. Challenges ● Accidental complexity, unreadable code e.g. doAsync1(function () { doAsync2(function () { doAsync3(function () { doAsync4(function () { ... }) }) }) 6
  • 7. Challenges ● Indeterminism ○ n! many orders in which all asynchronous operations can finish ○ Difficult to test ○ No “current state” ● Debugging ○ State of the art is println() sprinkled around ○ No meaningful stack trace 7
  • 8. Challenges ● Thread safety ○ Synchronized, locks, volatile, atomic, j.u.c.* ○ Immutability ○ 3rd party libraries ○ Thinking about Java Memory Model ○ Thread safety does not mean atomicity 8
  • 9. Challenges ● Often requires all-async //fetching Alice and Bob asynchronously fetchPerson(aliceId, handleAliceCallback); fetchPerson(bobId, handleBobCallback); // hmmm... now what? 9
  • 10. Core concepts: Promise<T> ● Represents state of an asynchronous operation ● Possible states: completed (resolved), uncompleted (unresolved) ● Container for a result of an asynchronous operation ● Result of completed Promise<T> is either value of type T or an exception 10
  • 11. Core concepts: Task<T> ● Main abstraction and building block in ParSeq, represents asynchronous operation ● Main ingredient of a Task<T> is a clojure that (synchronously) returns a Promise<T>, as if Task<T> had void Promise<T> run(...) ● Clojure starts asynchronous operation and returns a Promise that represents the state of that operation 11
  • 12. Core concepts: Task<T> Callable<Promise<String>> callable = () -> { SettablePromise<String> promise = Promises.settable(); return promise; }; ● Closest construct in pure Java is a Callable<Promise<T>> Task<String> task = Task.async(name, () -> { SettablePromise<String> promise = Promises.settable(); return promise; }); 12
  • 13. Core concepts: Task<T> Callable<Promise<String>> callable = () -> { SettablePromise<String> promise = Promises.settable(); return promise; }; ● Closest construct in pure Java is a Callable<Promise<T>> Task<String> task = Task.async(name, () -> { SettablePromise<String> promise = Promises.settable(); return promise; }); clojure 13
  • 14. Core concepts: Task<T> public <T> Promise<Response<T>> sendRequest(Request<T> request, RequestContext requestContext) { SettablePromise<Response<T>> promise = Promises.settable(); _restClient.sendRequest(request, requestContext, new PromiseCallbackAdapter<T>(promise)); return promise; } Task<Response<T>> task = Task.async(name, () -> sendRequest(request, requestContext)); ● Real example from ParSeqRestClient 14
  • 15. Core concepts: Task<T> public <T> Promise<Response<T>> sendRequest(Request<T> request, RequestContext requestContext) { SettablePromise<Response<T>> promise = Promises.settable(); _restClient.sendRequest(request, requestContext, new PromiseCallbackAdapter<T>(promise)); return promise; } Task<Response<T>> task = Task.async(name, () -> sendRequest(request, requestContext)); ● Real example from ParSeqRestClient clojure 15
  • 16. Core concepts: Task<T> time ● Example execution of tasks ○ clojure synchronously returns a Promise<T> ○ Promise is completed at some point in the future clojure execution Promise completion 16
  • 17. Properties of Tasks ● Tasks are lazy - creating a Task instance does not automatically run it ● Task runs at most once ● Tasks are immutable - all Task.* methods return new Tasks ● Programming with Tasks comes down to creating new Tasks that depend on existing ones (composition) 17
  • 18. Creating Tasks from scratch ● Usually there is no need to create Task from scratch using Task.async(...), instead use existing library e.g. _parseqRestClient.createTask(...) ● If there is a need to create a Task from scratch use Task.async(...), don’t extend BaseTask class 18
  • 19. Parallel Composition ● Task.par(t1, t2, …) Task<?> par3 = Task.par(fetchBing, fetchGoogle, fetchYahoo) 19
  • 20. Parallel Composition ● Task.par(t1, t2, …) Task<?> par3 = Task.par(fetchBing, fetchGoogle, fetchYahoo) time 20
  • 21. Parallel Composition ● Task.par(t1, t2, …) Task<?> par3 = Task.par(fetchBing, fetchGoogle, fetchYahoo) time clojure execution Promise completion 21
  • 22. Sequential Composition ● Do something after Task (it’s Promise) is completed Task<String> seq = fetchBing.andThen("seq", fetchGoogle); 22
  • 23. Sequential Composition ● Do something after Task (it’s Promise) is completed Task<String> seq = fetchBing.andThen("seq", fetchGoogle); time 23
  • 24. Sequential Composition ● Do something after Task (it’s Promise) is completed Task<String> seq = fetchBing.andThen("seq", fetchGoogle); time clojure execution Promise completion 24
  • 25. ParSeq API: map ● Transforms result of a task Task<String> name = Task.value("Jaroslaw"); Task<Integer> length = name.map(String::length); 25
  • 26. ParSeq API: flatMap ● Runs Task that depends on result of previous Task ● fetchCompany() invoked after fetchPerson() completes public Task<Company> fetchCompany(int id) {...} public Task<Person> fetchPerson(int id) {...} Task<Person> personTask = fetchPerson(id); Task<Company> companyTask = personTask.flatMap(person -> fetchCompany(person.getCompanyId())); vs Task<Task<Company>> companyTask = personTask.map(person -> fetchCompany(person.getCompanyId())); 26
  • 27. Exceptions handling ● All exceptions are automatically propagated Task<Integer> fetchAndLength = fetch404Url("http://www.google.com/idontexist") .map("length", String::length); ● Clojures can throw checked and unchecked exceptions fetchBody("http://www.bing.com") .andThen(s -> { throw new IOException(); }); 27
  • 28. Exceptions handling ● Task API has methods to handle exceptions, equivalent to try-catch for synchronous methods, e.g. recover() Task<Integer> fetchAndLength = fetch404Url("http://www.google.com/idontexist") .recover("default", t -> "") .map("length", s -> s.length()); 28
  • 29. Exceptions handling ● Exceptions can be handled explicitly, see methods toTry(), transform() ● Try<T> interface has only two implementation: Success<T> and Failure<T> Task<Try<String>> tryFetch = fetch404Url("http://www.google.com/idontexist") .toTry(); 29
  • 30. withTimeout ● Fails Task if it is not completed within specified amount of time Task<String> fetchWithTimeout = fetchUrl("http://www.google.com") .withTimeout(15, TimeUnit.MILLISECONDS); 30
  • 31. withTimeout ● Fails Task if it is not completed within specified amount of time Task<String> fetchWithTimeout = fetchUrl("http://www.google.com") .withTimeout(15, TimeUnit.MILLISECONDS); time 31
  • 32. ParSeq API ● ParSeq API is declarative ● Focus on “what” not “how” ● Task<T> interface does not have run() method 32
  • 33. ParSeq programming model ● Express everything by composing and transforming Tasks ● End up with one Task (Plan) that is passed to ParSeq Engine for execution ● Rest.li implements this idea @RestMethod.Get public Task<Greeting> get(final Long id) { // rest.li resource implementation } 33
  • 34. ParSeq execution model ● ParSeq Engine provides the following guarantees: ○ Rules expressed in ParSeq API are followed e.g. first.andThen(second) - “second” will run after “first” is completed ○ All clojures are executed sequentially, such that clojure of a previous Task in a sequence “happens before” clojure of a next Task (“happens before” in the Java Memory Model sense) 34
  • 35. Clojures are executed sequentially ● All operations passed to Task.* API are executed within a Task’s clojure Task<Integer> length = fetchBody("http://www.google.com") .map("length", String::length); time 35
  • 36. Clojures are executed sequentially ● All operations passed to Task.* API are executed within a clojure Task<Integer> length = fetchBody("http://www.google.com") .map("length", String::length); time clojure 36
  • 37. Clojures are executed sequentially ● All operations passed to Task.* API are automatically thread safe and atomic ● No need to be concerned about: ○ Synchronized, locks, volatile, atomic, j.u.c.* ○ Immutability ○ 3rd party libraries ○ Thinking about Java Memory Model ○ Thread safety does not mean atomicity 37
  • 38. Clojures are executed sequentially ● Example: find top N Candidates (synchronous) PriorityQueue<Candidate> topCandidates = new PriorityQueue<>(); void considerCandidate(Candidate candidate) { topCandidates.add(candidate); if (topCandidates.size() > N) { topCandidates.remove(); } } 38
  • 39. Clojures are executed sequentially ● Example: find top N Candidates (asynchronous) Task<Candidate> fetchCandidate(Long Id) {...} Task<?> considerCandidate(Long id) { return fetchCandidate(id) .andThen(this::considerCandidate); } ● Using thread safe PriorityQueue is not enough ● No need to test concurrency aspect 39
  • 40. Clojures are executed sequentially Task<?> par3 = Task.par(fetchBing, fetchGoogle, fetchYahoo) time ● Task.par(t1, t2, …) example 40
  • 41. Clojures are executed sequentially 41
  • 42. Clojures are executed sequentially Task.par( Task.callable("1000th prime", () -> nthPrime(1000)), Task.callable("1000th prime", () -> nthPrime(1000)), Task.callable("1000th prime", () -> nthPrime(1000)) ); ● Task.par(t1, t2, …) example time 42
  • 43. Clojures are executed sequentially ● Does it mean that ParSeq is single threaded? ● No Task.par( fetchBody("http://www.google.com").andThen(this::processBody), fetchBody("http://www.bing.com").andThen(this::processBody) ); 43
  • 44. Clojures are executed sequentially ● Does it mean that ParSeq is single threaded? ● No time other tasks other tasks wait processBodyThread 1 wait Thread 2 fetch fetch processBody 44
  • 45. other tasks Clojures are executed sequentially ● Does it mean that ParSeq is single threaded? ● No other tasks wait processBodyThread 1 wait Thread 2 time fetch happens before fetch processBody happens before 45
  • 46. Clojures are executed sequentially ● In order to perform well ParSeq requires developer’s cooperation. In clojures avoid: ○ blocking e.g. JDBC calls, Thread.sleep(), ... ○ CPU intensive operations 46
  • 47. Blocking ● Blocking API e.g. Voldemort, JDBC ● CPU intensive computation ● Offload operation to external Executor Task.blocking(String name, Callable<? extends T> callable, Executor executor) ● Supports multiple executors ● Executors management is outside ParSeq 47
  • 48. Automatic cancellation ● Task abstraction borrows ideas from functional programming, think: Task ~ function call ○ Task is lazy, only runs when needed ○ Task is immutable ○ It’s purpose is to calculate a result ○ Task runs at most once ○ Once result is known, everything that is still not completed (for some reason) can be cancelled because it can’t affect result 48
  • 49. Automatic cancellation Task<String> google = fetchBody("http://www.google.com"); Task<String> yahoo = fetchBody("http://www.yahoo.com"); Task<String> bing = fetchBody("http://www.~#fdcm x 0eirw.com"); Task<Integer> sumLengths = Task.par(google.map("length", String::length), yahoo.map("length", String::length), bing.map("length", String::length)) .map("sum", (g, y, b) -> g + y + b); 49
  • 51. Tracing ● Trace is information about what happened after calling Engine.run() ● Tracing is always enabled for all tasks ● Allows reasoning about what happened ● Includes timing information, exceptions, etc. ● Obtain trace JSON at any time by calling Task.getTrace().toString() ● Paste JSON at go/tracevis to visualize 51
  • 52. Tracing best practices ● Add short, meaningful description to every task HttpClient.get(url).task() .map("getBody", response -> response.getResponseBody()) .map("length", s -> s.length()); 52
  • 53. Tasks Fusion ● Sequence of synchronous transformations can be optimized and executed as a chain of method calls Task<Integer> length = HttpClient.get("http://www.google.com").task() .map("getBody", Response::getResponseBody) .map("length", s -> s.length()); 53
  • 54. Batching ● Allows automatic batching of individual asynchronous operations without affecting code readability 54
  • 55. Unit testing ● Use BaseEngineTest as a base class for a unit test ○ Initialization and shutdown of Engine ○ Lot of helper methods ● Log trace for the tested Task 55
  • 56. Best Practices ● Focus on readable, clean code ○ Split code into small, unit-testable methods that may return Task<T> ○ Prefer method handles over lambdas ○ Limit length of lambda code blocks to few lines ○ Don’t mix functional APIs inside lambda code block e.g. Java Stream map() and Java Optional map() with ParSeq map() 56
  • 57. Upcoming feature ● Automatic batching of GET / BATCH_GET requests in ParSeqRestClient ● Configurable timeouts in ParSeqRestClient ● Automatic logging traces of failed plans ● Sending sample of traces to kafka for analysis e.g. finding bottlenecks, regressions, thread blocking, … ● ParSeq “Collections” 57

Editor's Notes

  1. waiting is eliminated, threads are busy note 1: two threads are involved in execution note 2: req1, req2, process response 1, process response 2 execute sequentially
  2. waiting is eliminated, threads are busy note 1: two threads are involved in execution note 2: req1, req2, process response 1, process response 2 execute sequentially