SlideShare una empresa de Scribd logo
1 de 40
Descargar para leer sin conexión
Advanced Patterns
in Asynchronous
Programming
Asy Ronen
Michael Arenzon
Asy Ronen
* Independent consultant
* asy.ronen@gmail.com
* linkedin.com/in/asyronen
Michael Arenzon
* Application Infrastructure TL @ Outbrain
* github.com/marenzo
* linkedin.com/in/arenzon
About Us
Intro
▪ When writing async code, a few models can be used, such as:
▫ Actor
▫ CSP
▫ Future / Promise
▪ We will concentrate on futures, specifically Scala Future
▪ We will introduce a set of useful patterns that will enhance the
resiliency of your system
“
Disclaimer: All patterns were
tested in production
All patterns are
used in
production
Motivation
▪ In Outbrain we started writing asynchronous services a few
years back using our own library called Ob1k.
▪ Ob1k includes a Future implementation in Java that is similar to
the Scala one (or C# Task).
▪ We learned a few patterns that were useful when working with
asynchronous code in a live production environment
▪ These patterns are now ported to a standalone library around
Scala’s future.
▪ When writing async code there is a need to relate to real clock in order to:
▫ Schedule a future computation
▫ “Sleep” between two async actions
▫ Measure time of async actions
▫ Etc…
▪ To do that we need a scheduler
Pattern #1 - schedule()
def schedule[T](duration: FiniteDuration)
(callable: => T)
(implicit scheduler: Scheduler): Future[T]
def scheduleWith[T](duration: FiniteDuration)
(callable: => Future[T])
(implicit scheduler: Scheduler): Future[T]
schedule() - Definition
"schedule" should "schedule execution in the future" in {
val res = schedule(1 second) {
System.currentTimeMillis()
}
val t1 = System.currentTimeMillis()
val t2 = Await.result(res, 2 second)
val time = t2 - t1
assert (time >= 1000 && time <= 1100)
}
schedule() - Usage Example
▪ If not properly bounded, we can wait for a future forever.
▪ If we want to provide SLA for our service, we must limit the total
time allowed to process the request.
▪ An error returned on time is better than no answer.
Pattern #2 - withTimeout()
implicit class FutureTimeout[T](future: Future[T]) {
def withTimeout(duration: FiniteDuration)
(implicit scheduler: Scheduler,
executor: ExecutionContext):Future[T] = {
val deadline = schedule(duration) {
throw new TimeoutException("future timeout")
}
Future firstCompletedOf Seq(future, deadline)
}
}
withTimeout() - Implementation
The original future task is not interrupted!
withTimeout() - (Happy) Usage Example
"withTimeout" should "do nothing if result arrives on time" in {
val scheduledFuture = schedule(1 second) {
"hello"
} withTimeout (2 second)
val result = Await.result(scheduledFuture, 2 second)
assert (result === "hello")
}
withTimeout() - Usage Example
"withTimeout" should "throw exception after timeout" in {
val scheduledFuture = schedule(2 second) {
"hello"
} withTimeout (1 second)
assertThrows[TimeoutException] {
Await.result(scheduledFuture, 2 second)
}
}
Pattern #3 - sequence()
▪ Scala’s Future class contain a sequence method that transforms
a List[Future[T]] => Future[List[T]]
▪ However, it has two main drawbacks:
a. If one future fails the whole thing fails but what if 90% of
the results are good enough for us?
b. It doesn’t fail fast i.e. we wait for the slowest result/error to
arrive
sequence() - Definition
def sequence[T]
(futures: Seq[Future[T]], stop: StopCondition = FailOnError)
(implicit executor: ExecutionContext): Future[Seq[T]]
def collect[K, T]
(futures: Map[K, Future[T]], stop: StopCondition = FailOnError)
(implicit executor: ExecutionContext): Future[Map[K, T]]
sequence() - Stop Conditions
sealed trait StopCondition
case object FailOnError extends StopCondition
case object StopOnError extends StopCondition
case object ContinueOnError extends StopCondition
Used to choose a strategy of handling errors in our execution.
sequence() - FailOnError
Fail fast on the first error and return it. Similar to Scala’s behaviour.
Return Error
sequence() - StopOnError
Stop collecting further results and return collected results so far.
Return value(s)
sequence() - ContinueOnError
Ignore errors and collect all successful results.
Return value(s)
sequence() - Definition (extended)
def sequenceAll[T]
(futures: Seq[Future[T]])
(implicit executor: ExecutionContext): Future[Seq[Try[T]]]
def collectAll[K, T]
(futures: Map[K, Future[T]])
(implicit executor: ExecutionContext): Future[Map[K, Try[T]]]
Return all values & errors
sequence() - #1 Usage Example
"sequence" should "fail immediately if error occurs" in {
val f1 = schedule(1 second)("first")
val f2 = Future failed new ServiceException("I’m down")
val f3 = schedule(2 second)("second")
val res = sequence(Seq(f1, f2, f3), FailOnError)
try {
val finalRes = Await.result(res, 10 milli)
fail("should throw exception.")
} catch {
case e: ServiceException => succeed
}
}
collect() - #2 Usage Example
"sequence" should "stop on first error" in {
val f1 = schedule(1 second)("first")
val f2 = Future failed
new RuntimeException("failed") delay (2 second)
val f3 = schedule(3 second)("second")
val input = Map("1" -> f1, "2" -> f2, "3" -> f3)
val res = collect(input, StopOnError)
val finalRes = Await.result(res, 3 second)
assert (finalRes.size === 1)
}
sequence() - Usage Example (contd.)
"sequence" should "collect all successful results" in {
val f1 = Future("first")
val f2 = Future("second")
val f3 = Future failed new RuntimeException("failed result")
val f4 = Future("third")
val input = Map("1" -> f1, "2" -> f2, "3" -> f3, "4" -> f4)
val res = collect(input, ContinueOnError)
val finalRes = Await.result(res, 1 second)
assert (finalRes.size === 3)
}
collectAll() - Usage Example
"collectAll" should "collect all results" in {
val f1 = schedule(1 second)("first")
val f2 = Future failed new IOException("failed")
val f3 = schedule(2 second)("second")
val res = collectAll(Map("1" -> f1, "2" -> f2, "3" -> f3))
val finalRes = Await.result(res, 3 second)
val (goodResults, badResults) = finalRes partition {
case (_, Success(_)) => true
case _ => false
}
assert(goodResults.size === 2)
assert(badResults.size === 1)
}
Pattern #4 - parallelCollect()
▪ Executing too many operations concurrently can be overwhelming.
▪ Some services cap concurrency of a single consumer
▪ To throttle execution we need a tool that will allow us to define maximum
concurrent operations
parallelCollect() - Definition
def parallelCollect[T, R]
(elements: Seq[T], parallelism: Int,
stop: StopCondition = FailOnError)
(producer: T => Future[R])
(implicit executor: ExecutionContext): Future[Seq[R]]
parallelCollect() - Usage Example
"Google Search" should "return all results without throttling" in {
val queries: List[String] = createQueries(amount = 10000)
val results = parallelCollect(queries, 10, ContinueOnError) {
query => GoogleSearchClient.sendQuery(query)
} withTimeout(30 second)
val finalRes = Await.result(results, 30 second)
assert (finalRes.size === 10000)
}
Pattern #5 - retry()
● Applications fail. Network connections drop. Connections
timeout. Bad things happen.
● You can give your application perseverance with retry.
retry() - (Naive) Implementation
def retry[T](retries: Int)(f: => Future[T]): Future[T] = f recoverWith {
case _ if retries > 0 => retry(retries - 1)(f)
}
retry() - (Real) Implementation
sealed trait RetryPolicy
case object Immediate extends RetryPolicy
case class Fixed(duration: FiniteDuration) extends RetryPolicy
case class Exponential(duration: FiniteDuration) extends RetryPolicy
def retry[T](retries: Int, policy: RetryPolicy)
(producer: Int => Future[T])
(implicit executor: ExecutionContext,
scheduler: Scheduler): Future[T]
retry() - (Real) Implementation
type Conditional = PartialFunction[Throwable, RetryPolicy]
def retry[T](retries: Int)
(policy: Conditional)
(producer: Int => Future[T])
(implicit scheduler: Scheduler,
executor: ExecutionContext): Future[T]
retry() - Fixed Usage Example
"retry(fixed)" should "be called 3 times" in {
val strategy = Fixed(1 second)
val res = retry(3, strategy) {
case 0 => Future.failed
new RuntimeException("not good enough...")
case 1 => Future.failed
new RuntimeException("getting better...")
case 2 => Future.successful("great success !")
}
val finalResult = Await.result(res, 3 second)
assert (finalResult === "great success !")
}
retry() - Conditional Usage Example
"retry(conditional)" should "stop on IOException" in {
val policy: PartialFunction[Throwable, RetryPolicy] = {
case _: TimeoutException => Fixed(1 second)
}
val res = retry(3)(policy) {
case 0 => Future failed new TimeoutException("really slow")
case 1 => Future failed new IOException("something bad")
case 2 => Future successful "great success"
}
try Await.result(res, 3 second) catch {
case _: IOException => succeed
}
}
▪ Slow response at a single instance level happens on a regular basis -
GC, unresponsive queries, network issues, etc.
▪ When we analyze our latencies over time, we will see a long tail of long
latencies exceeding our SLA.
▪ It is possible to trade-off between average load of a system and overall
response time.
Pattern #6 - doubleDispatch()
doubleDispatch() - (Naive) Algorithm
1. Send two requests immediately, assuming that we have a
load-balancer that will distribute requests across nodes.
2. Collecting first returned answer from both calls.
Client
Server1 Server2
doubleDispatch() - A better approach
1. Send the first request to the first node
2. After a predefined period of time, if no answer arrived from
the first request, we dispatch the second one.
3. Collect first returned answer from both calls.
Client
Server1 Server2
20 msec
doubleDispatch() - Definition
def doubleDispatch[T](duration: FiniteDuration)
(producer: => Future[T])
(implicit executor: ExecutionContext,
scheduler: Scheduler): Future[T]
This mechanism can only be used with idempotent operations
doubleDispatch() - Usage Example
"doubleDispatch" should "return the short call" in {
val switch = new AtomicBoolean()
val res = doubleDispatch(1 second) {
if (switch.compareAndSet(false, true)) {
Future("slow response") delay (3 second)
} else {
Future("fast response") delay (1 second)
}
}
val finalRes = Await.result(res, 4 second)
assert (finalRes === "fast response")
}
doubleDispatch() - Choosing Duration
● Without DD 99% of calls are
under the SLA
● DD on 50ms (90th percentile)
● Out of 1% calls 90% will be under
SLA which is 50ms (0.9%)
● In total 99.9% successful calls!
● Resource utilization is up by 10%
Future Plans
▪ Circuit breaker
▪ Resource (Object) Pool
▪ What else ? we accept pull requests ;)
THANKS!
Code available at:
https://github.com/haski/async-patterns
Ob1k:
https://github.com/outbrain/ob1k

Más contenido relacionado

La actualidad más candente

Introduction to nsubstitute
Introduction to nsubstituteIntroduction to nsubstitute
Introduction to nsubstituteSuresh Loganatha
 
Use C++ to Manipulate mozSettings in Gecko
Use C++ to Manipulate mozSettings in GeckoUse C++ to Manipulate mozSettings in Gecko
Use C++ to Manipulate mozSettings in GeckoChih-Hsuan Kuo
 
Java Performance Puzzlers
Java Performance PuzzlersJava Performance Puzzlers
Java Performance PuzzlersDoug Hawkins
 
Unittesting JavaScript with Evidence
Unittesting JavaScript with EvidenceUnittesting JavaScript with Evidence
Unittesting JavaScript with EvidenceTobie Langel
 
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 AsynchrhonouslyDavid Gómez García
 
Java practice programs for beginners
Java practice programs for beginnersJava practice programs for beginners
Java practice programs for beginnersishan0019
 
The Ring programming language version 1.6 book - Part 11 of 189
The Ring programming language version 1.6 book - Part 11 of 189The Ring programming language version 1.6 book - Part 11 of 189
The Ring programming language version 1.6 book - Part 11 of 189Mahmoud Samir Fayed
 
Concurrent Programming in Java
Concurrent Programming in JavaConcurrent Programming in Java
Concurrent Programming in JavaRuben Inoto Soto
 
The Future of Futures - A Talk About Java 8 CompletableFutures
The Future of Futures - A Talk About Java 8 CompletableFuturesThe Future of Futures - A Talk About Java 8 CompletableFutures
The Future of Futures - A Talk About Java 8 CompletableFuturesHaim Yadid
 
The Ring programming language version 1.9 book - Part 91 of 210
The Ring programming language version 1.9 book - Part 91 of 210The Ring programming language version 1.9 book - Part 91 of 210
The Ring programming language version 1.9 book - Part 91 of 210Mahmoud Samir Fayed
 
Introduction to ParSeq: to make asynchronous java easier
Introduction to ParSeq: to make asynchronous java easierIntroduction to ParSeq: to make asynchronous java easier
Introduction to ParSeq: to make asynchronous java easierJunchuan Wang
 
Greach, GroovyFx Workshop
Greach, GroovyFx WorkshopGreach, GroovyFx Workshop
Greach, GroovyFx WorkshopDierk König
 
javascript function & closure
javascript function & closurejavascript function & closure
javascript function & closureHika Maeng
 
Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsPiotr Pelczar
 

La actualidad más candente (20)

Rxjs marble-testing
Rxjs marble-testingRxjs marble-testing
Rxjs marble-testing
 
Introduction to nsubstitute
Introduction to nsubstituteIntroduction to nsubstitute
Introduction to nsubstitute
 
Use C++ to Manipulate mozSettings in Gecko
Use C++ to Manipulate mozSettings in GeckoUse C++ to Manipulate mozSettings in Gecko
Use C++ to Manipulate mozSettings in Gecko
 
JVM Mechanics
JVM MechanicsJVM Mechanics
JVM Mechanics
 
Java Performance Puzzlers
Java Performance PuzzlersJava Performance Puzzlers
Java Performance Puzzlers
 
Unittesting JavaScript with Evidence
Unittesting JavaScript with EvidenceUnittesting JavaScript with Evidence
Unittesting JavaScript with Evidence
 
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
 
Java practice programs for beginners
Java practice programs for beginnersJava practice programs for beginners
Java practice programs for beginners
 
Reactive Java (33rd Degree)
Reactive Java (33rd Degree)Reactive Java (33rd Degree)
Reactive Java (33rd Degree)
 
The Ring programming language version 1.6 book - Part 11 of 189
The Ring programming language version 1.6 book - Part 11 of 189The Ring programming language version 1.6 book - Part 11 of 189
The Ring programming language version 1.6 book - Part 11 of 189
 
Concurrent Programming in Java
Concurrent Programming in JavaConcurrent Programming in Java
Concurrent Programming in Java
 
applet.docx
applet.docxapplet.docx
applet.docx
 
The Future of Futures - A Talk About Java 8 CompletableFutures
The Future of Futures - A Talk About Java 8 CompletableFuturesThe Future of Futures - A Talk About Java 8 CompletableFutures
The Future of Futures - A Talk About Java 8 CompletableFutures
 
The Ring programming language version 1.9 book - Part 91 of 210
The Ring programming language version 1.9 book - Part 91 of 210The Ring programming language version 1.9 book - Part 91 of 210
The Ring programming language version 1.9 book - Part 91 of 210
 
Durable Functions
Durable FunctionsDurable Functions
Durable Functions
 
Introduction to ParSeq: to make asynchronous java easier
Introduction to ParSeq: to make asynchronous java easierIntroduction to ParSeq: to make asynchronous java easier
Introduction to ParSeq: to make asynchronous java easier
 
Greach, GroovyFx Workshop
Greach, GroovyFx WorkshopGreach, GroovyFx Workshop
Greach, GroovyFx Workshop
 
javascript function & closure
javascript function & closurejavascript function & closure
javascript function & closure
 
Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.js
 
Understanding greenlet
Understanding greenletUnderstanding greenlet
Understanding greenlet
 

Similar a Advanced patterns in asynchronous programming

C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...
C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...
C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...corehard_by
 
Parallel Programming With Dot Net
Parallel Programming With Dot NetParallel Programming With Dot Net
Parallel Programming With Dot NetNeeraj Kaushik
 
Asynchronous Orchestration DSL on squbs
Asynchronous Orchestration DSL on squbsAsynchronous Orchestration DSL on squbs
Asynchronous Orchestration DSL on squbsAnil Gursel
 
Finagle and Java Service Framework at Pinterest
Finagle and Java Service Framework at PinterestFinagle and Java Service Framework at Pinterest
Finagle and Java Service Framework at PinterestPavan Chitumalla
 
Distributed Radar Tracking Simulation Project
Distributed Radar Tracking Simulation ProjectDistributed Radar Tracking Simulation Project
Distributed Radar Tracking Simulation ProjectAssignmentpedia
 
Distributed Radar Tracking Simulation Project
Distributed Radar Tracking Simulation ProjectDistributed Radar Tracking Simulation Project
Distributed Radar Tracking Simulation ProjectAssignmentpedia
 
Deuce STM - CMP'09
Deuce STM - CMP'09Deuce STM - CMP'09
Deuce STM - CMP'09Guy Korland
 
What is new in java 8 concurrency
What is new in java 8 concurrencyWhat is new in java 8 concurrency
What is new in java 8 concurrencykshanth2101
 
Job Queue in Golang
Job Queue in GolangJob Queue in Golang
Job Queue in GolangBo-Yi Wu
 
NDC Sydney 2019 - Async Demystified -- Karel Zikmund
NDC Sydney 2019 - Async Demystified -- Karel ZikmundNDC Sydney 2019 - Async Demystified -- Karel Zikmund
NDC Sydney 2019 - Async Demystified -- Karel ZikmundKarel Zikmund
 
What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)Pavlo Baron
 
.NET Core Summer event 2019 in Brno, CZ - Async demystified -- Karel Zikmund
.NET Core Summer event 2019 in Brno, CZ - Async demystified -- Karel Zikmund.NET Core Summer event 2019 in Brno, CZ - Async demystified -- Karel Zikmund
.NET Core Summer event 2019 in Brno, CZ - Async demystified -- Karel ZikmundKarel Zikmund
 
Java util concurrent
Java util concurrentJava util concurrent
Java util concurrentRoger Xia
 
Fork and join framework
Fork and join frameworkFork and join framework
Fork and join frameworkMinh Tran
 

Similar a Advanced patterns in asynchronous programming (20)

C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...
C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...
C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...
 
Celery
CeleryCelery
Celery
 
Clojure basics
Clojure basicsClojure basics
Clojure basics
 
Parallel Programming With Dot Net
Parallel Programming With Dot NetParallel Programming With Dot Net
Parallel Programming With Dot Net
 
Asynchronous Orchestration DSL on squbs
Asynchronous Orchestration DSL on squbsAsynchronous Orchestration DSL on squbs
Asynchronous Orchestration DSL on squbs
 
Rx workshop
Rx workshopRx workshop
Rx workshop
 
Finagle and Java Service Framework at Pinterest
Finagle and Java Service Framework at PinterestFinagle and Java Service Framework at Pinterest
Finagle and Java Service Framework at Pinterest
 
Distributed Radar Tracking Simulation Project
Distributed Radar Tracking Simulation ProjectDistributed Radar Tracking Simulation Project
Distributed Radar Tracking Simulation Project
 
Distributed Radar Tracking Simulation Project
Distributed Radar Tracking Simulation ProjectDistributed Radar Tracking Simulation Project
Distributed Radar Tracking Simulation Project
 
Deuce STM - CMP'09
Deuce STM - CMP'09Deuce STM - CMP'09
Deuce STM - CMP'09
 
What is new in java 8 concurrency
What is new in java 8 concurrencyWhat is new in java 8 concurrency
What is new in java 8 concurrency
 
RxJava on Android
RxJava on AndroidRxJava on Android
RxJava on Android
 
Job Queue in Golang
Job Queue in GolangJob Queue in Golang
Job Queue in Golang
 
NDC Sydney 2019 - Async Demystified -- Karel Zikmund
NDC Sydney 2019 - Async Demystified -- Karel ZikmundNDC Sydney 2019 - Async Demystified -- Karel Zikmund
NDC Sydney 2019 - Async Demystified -- Karel Zikmund
 
What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)
 
Golang dot-testing-lite
Golang dot-testing-liteGolang dot-testing-lite
Golang dot-testing-lite
 
.NET Core Summer event 2019 in Brno, CZ - Async demystified -- Karel Zikmund
.NET Core Summer event 2019 in Brno, CZ - Async demystified -- Karel Zikmund.NET Core Summer event 2019 in Brno, CZ - Async demystified -- Karel Zikmund
.NET Core Summer event 2019 in Brno, CZ - Async demystified -- Karel Zikmund
 
Java util concurrent
Java util concurrentJava util concurrent
Java util concurrent
 
Java Concurrency
Java ConcurrencyJava Concurrency
Java Concurrency
 
Fork and join framework
Fork and join frameworkFork and join framework
Fork and join framework
 

Último

W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...panagenda
 
tonesoftg
tonesoftgtonesoftg
tonesoftglanshi9
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...masabamasaba
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxAnnaArtyushina1
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension AidPhilip Schwarz
 
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benonimasabamasaba
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfonteinmasabamasaba
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisamasabamasaba
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...masabamasaba
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...masabamasaba
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park masabamasaba
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...Jittipong Loespradit
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech studentsHimanshiGarg82
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfonteinmasabamasaba
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationJuha-Pekka Tolvanen
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...SelfMade bd
 

Último (20)

W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptx
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the Situation
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 

Advanced patterns in asynchronous programming

  • 2. Asy Ronen * Independent consultant * asy.ronen@gmail.com * linkedin.com/in/asyronen Michael Arenzon * Application Infrastructure TL @ Outbrain * github.com/marenzo * linkedin.com/in/arenzon About Us
  • 3. Intro ▪ When writing async code, a few models can be used, such as: ▫ Actor ▫ CSP ▫ Future / Promise ▪ We will concentrate on futures, specifically Scala Future ▪ We will introduce a set of useful patterns that will enhance the resiliency of your system
  • 4. “ Disclaimer: All patterns were tested in production All patterns are used in production
  • 5. Motivation ▪ In Outbrain we started writing asynchronous services a few years back using our own library called Ob1k. ▪ Ob1k includes a Future implementation in Java that is similar to the Scala one (or C# Task). ▪ We learned a few patterns that were useful when working with asynchronous code in a live production environment ▪ These patterns are now ported to a standalone library around Scala’s future.
  • 6. ▪ When writing async code there is a need to relate to real clock in order to: ▫ Schedule a future computation ▫ “Sleep” between two async actions ▫ Measure time of async actions ▫ Etc… ▪ To do that we need a scheduler Pattern #1 - schedule()
  • 7. def schedule[T](duration: FiniteDuration) (callable: => T) (implicit scheduler: Scheduler): Future[T] def scheduleWith[T](duration: FiniteDuration) (callable: => Future[T]) (implicit scheduler: Scheduler): Future[T] schedule() - Definition
  • 8. "schedule" should "schedule execution in the future" in { val res = schedule(1 second) { System.currentTimeMillis() } val t1 = System.currentTimeMillis() val t2 = Await.result(res, 2 second) val time = t2 - t1 assert (time >= 1000 && time <= 1100) } schedule() - Usage Example
  • 9. ▪ If not properly bounded, we can wait for a future forever. ▪ If we want to provide SLA for our service, we must limit the total time allowed to process the request. ▪ An error returned on time is better than no answer. Pattern #2 - withTimeout()
  • 10. implicit class FutureTimeout[T](future: Future[T]) { def withTimeout(duration: FiniteDuration) (implicit scheduler: Scheduler, executor: ExecutionContext):Future[T] = { val deadline = schedule(duration) { throw new TimeoutException("future timeout") } Future firstCompletedOf Seq(future, deadline) } } withTimeout() - Implementation The original future task is not interrupted!
  • 11. withTimeout() - (Happy) Usage Example "withTimeout" should "do nothing if result arrives on time" in { val scheduledFuture = schedule(1 second) { "hello" } withTimeout (2 second) val result = Await.result(scheduledFuture, 2 second) assert (result === "hello") }
  • 12. withTimeout() - Usage Example "withTimeout" should "throw exception after timeout" in { val scheduledFuture = schedule(2 second) { "hello" } withTimeout (1 second) assertThrows[TimeoutException] { Await.result(scheduledFuture, 2 second) } }
  • 13. Pattern #3 - sequence() ▪ Scala’s Future class contain a sequence method that transforms a List[Future[T]] => Future[List[T]] ▪ However, it has two main drawbacks: a. If one future fails the whole thing fails but what if 90% of the results are good enough for us? b. It doesn’t fail fast i.e. we wait for the slowest result/error to arrive
  • 14. sequence() - Definition def sequence[T] (futures: Seq[Future[T]], stop: StopCondition = FailOnError) (implicit executor: ExecutionContext): Future[Seq[T]] def collect[K, T] (futures: Map[K, Future[T]], stop: StopCondition = FailOnError) (implicit executor: ExecutionContext): Future[Map[K, T]]
  • 15. sequence() - Stop Conditions sealed trait StopCondition case object FailOnError extends StopCondition case object StopOnError extends StopCondition case object ContinueOnError extends StopCondition Used to choose a strategy of handling errors in our execution.
  • 16. sequence() - FailOnError Fail fast on the first error and return it. Similar to Scala’s behaviour. Return Error
  • 17. sequence() - StopOnError Stop collecting further results and return collected results so far. Return value(s)
  • 18. sequence() - ContinueOnError Ignore errors and collect all successful results. Return value(s)
  • 19. sequence() - Definition (extended) def sequenceAll[T] (futures: Seq[Future[T]]) (implicit executor: ExecutionContext): Future[Seq[Try[T]]] def collectAll[K, T] (futures: Map[K, Future[T]]) (implicit executor: ExecutionContext): Future[Map[K, Try[T]]] Return all values & errors
  • 20. sequence() - #1 Usage Example "sequence" should "fail immediately if error occurs" in { val f1 = schedule(1 second)("first") val f2 = Future failed new ServiceException("I’m down") val f3 = schedule(2 second)("second") val res = sequence(Seq(f1, f2, f3), FailOnError) try { val finalRes = Await.result(res, 10 milli) fail("should throw exception.") } catch { case e: ServiceException => succeed } }
  • 21. collect() - #2 Usage Example "sequence" should "stop on first error" in { val f1 = schedule(1 second)("first") val f2 = Future failed new RuntimeException("failed") delay (2 second) val f3 = schedule(3 second)("second") val input = Map("1" -> f1, "2" -> f2, "3" -> f3) val res = collect(input, StopOnError) val finalRes = Await.result(res, 3 second) assert (finalRes.size === 1) }
  • 22. sequence() - Usage Example (contd.) "sequence" should "collect all successful results" in { val f1 = Future("first") val f2 = Future("second") val f3 = Future failed new RuntimeException("failed result") val f4 = Future("third") val input = Map("1" -> f1, "2" -> f2, "3" -> f3, "4" -> f4) val res = collect(input, ContinueOnError) val finalRes = Await.result(res, 1 second) assert (finalRes.size === 3) }
  • 23. collectAll() - Usage Example "collectAll" should "collect all results" in { val f1 = schedule(1 second)("first") val f2 = Future failed new IOException("failed") val f3 = schedule(2 second)("second") val res = collectAll(Map("1" -> f1, "2" -> f2, "3" -> f3)) val finalRes = Await.result(res, 3 second) val (goodResults, badResults) = finalRes partition { case (_, Success(_)) => true case _ => false } assert(goodResults.size === 2) assert(badResults.size === 1) }
  • 24. Pattern #4 - parallelCollect() ▪ Executing too many operations concurrently can be overwhelming. ▪ Some services cap concurrency of a single consumer ▪ To throttle execution we need a tool that will allow us to define maximum concurrent operations
  • 25. parallelCollect() - Definition def parallelCollect[T, R] (elements: Seq[T], parallelism: Int, stop: StopCondition = FailOnError) (producer: T => Future[R]) (implicit executor: ExecutionContext): Future[Seq[R]]
  • 26. parallelCollect() - Usage Example "Google Search" should "return all results without throttling" in { val queries: List[String] = createQueries(amount = 10000) val results = parallelCollect(queries, 10, ContinueOnError) { query => GoogleSearchClient.sendQuery(query) } withTimeout(30 second) val finalRes = Await.result(results, 30 second) assert (finalRes.size === 10000) }
  • 27. Pattern #5 - retry() ● Applications fail. Network connections drop. Connections timeout. Bad things happen. ● You can give your application perseverance with retry.
  • 28. retry() - (Naive) Implementation def retry[T](retries: Int)(f: => Future[T]): Future[T] = f recoverWith { case _ if retries > 0 => retry(retries - 1)(f) }
  • 29. retry() - (Real) Implementation sealed trait RetryPolicy case object Immediate extends RetryPolicy case class Fixed(duration: FiniteDuration) extends RetryPolicy case class Exponential(duration: FiniteDuration) extends RetryPolicy def retry[T](retries: Int, policy: RetryPolicy) (producer: Int => Future[T]) (implicit executor: ExecutionContext, scheduler: Scheduler): Future[T]
  • 30. retry() - (Real) Implementation type Conditional = PartialFunction[Throwable, RetryPolicy] def retry[T](retries: Int) (policy: Conditional) (producer: Int => Future[T]) (implicit scheduler: Scheduler, executor: ExecutionContext): Future[T]
  • 31. retry() - Fixed Usage Example "retry(fixed)" should "be called 3 times" in { val strategy = Fixed(1 second) val res = retry(3, strategy) { case 0 => Future.failed new RuntimeException("not good enough...") case 1 => Future.failed new RuntimeException("getting better...") case 2 => Future.successful("great success !") } val finalResult = Await.result(res, 3 second) assert (finalResult === "great success !") }
  • 32. retry() - Conditional Usage Example "retry(conditional)" should "stop on IOException" in { val policy: PartialFunction[Throwable, RetryPolicy] = { case _: TimeoutException => Fixed(1 second) } val res = retry(3)(policy) { case 0 => Future failed new TimeoutException("really slow") case 1 => Future failed new IOException("something bad") case 2 => Future successful "great success" } try Await.result(res, 3 second) catch { case _: IOException => succeed } }
  • 33. ▪ Slow response at a single instance level happens on a regular basis - GC, unresponsive queries, network issues, etc. ▪ When we analyze our latencies over time, we will see a long tail of long latencies exceeding our SLA. ▪ It is possible to trade-off between average load of a system and overall response time. Pattern #6 - doubleDispatch()
  • 34. doubleDispatch() - (Naive) Algorithm 1. Send two requests immediately, assuming that we have a load-balancer that will distribute requests across nodes. 2. Collecting first returned answer from both calls. Client Server1 Server2
  • 35. doubleDispatch() - A better approach 1. Send the first request to the first node 2. After a predefined period of time, if no answer arrived from the first request, we dispatch the second one. 3. Collect first returned answer from both calls. Client Server1 Server2 20 msec
  • 36. doubleDispatch() - Definition def doubleDispatch[T](duration: FiniteDuration) (producer: => Future[T]) (implicit executor: ExecutionContext, scheduler: Scheduler): Future[T] This mechanism can only be used with idempotent operations
  • 37. doubleDispatch() - Usage Example "doubleDispatch" should "return the short call" in { val switch = new AtomicBoolean() val res = doubleDispatch(1 second) { if (switch.compareAndSet(false, true)) { Future("slow response") delay (3 second) } else { Future("fast response") delay (1 second) } } val finalRes = Await.result(res, 4 second) assert (finalRes === "fast response") }
  • 38. doubleDispatch() - Choosing Duration ● Without DD 99% of calls are under the SLA ● DD on 50ms (90th percentile) ● Out of 1% calls 90% will be under SLA which is 50ms (0.9%) ● In total 99.9% successful calls! ● Resource utilization is up by 10%
  • 39. Future Plans ▪ Circuit breaker ▪ Resource (Object) Pool ▪ What else ? we accept pull requests ;)