24
COORDINATING NON-BLOCKING IO AND ASYNC HTTP RESPONSES

Coordinating non blocking io melb-clj

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Coordinating non blocking io melb-clj

COORDINATING NON-BLOCKING IO

AND ASYNC HTTP RESPONSES

Page 2: Coordinating non blocking io melb-clj
Page 3: Coordinating non blocking io melb-clj

WHAT IS THE WEB STACK

• HttpKit as web server • Compojure for routing • HttpKit for non-blocking http requests

Page 4: Coordinating non blocking io melb-clj

REACTIVE APPROACH PREFERRED

• We are not using either Functional Reactive Programming or Reactive Programming libraries. Eg. Rx.java

• May satisfy other more broad definitions of reactive • Are making better use of threads than traditional approaches

Page 5: Coordinating non blocking io melb-clj

Make a payment on a bill - Not necessarily a full payment

!

POST /bills/:bill-id/payments Session: user-id Post Data: amount !

1. Get credit card token for user 1.1. Send request to payment gateway 2. Find how much was left to be payed !

If payment is success: render amount remaining on bill If payment fails: render error

Page 6: Coordinating non blocking io melb-clj

CANDIDATES

• Synchronous promises

• Promise monad let/do

• Promise monad chain/lift-m-2

• Raw promises

• Raw callbacks

• core.async

• Lamina pipeline

• Meltdown (LMAX Disrupter)

• Pulsar promises

• Pulsar Actors

Page 7: Coordinating non blocking io melb-clj

SOLUTION 0: SYNCHRONOUS

(GET  "/bills/:bill-­‐id/payments"  [bill-­‐id  user-­‐id  amount]      (let  [token              (auth/card-­‐token  user-­‐id)                  details          (bill/details  bill-­‐id)                  transaction  (payment/bill  bill-­‐id  amount  @token)]          (if  (success?  @transaction)              (render-­‐remaining-­‐response  @details  amount)              error-­‐response)))  

Page 8: Coordinating non blocking io melb-clj

SOLUTION 1: PROMISE MONAD LET/DO

(GET  "/bills/:bill-­‐id/payments"  [bill-­‐id  user-­‐id  amount]            (let  [token-­‐req      (auth/card-­‐token  user-­‐id)                        details-­‐req  (bill/details  bill-­‐id)]                (do  [token              token-­‐req                          transaction  (payment/bill  bill-­‐id  amount  token)                          details          details-­‐req]                        (return                            (if  (success?  transaction)                                (render-­‐remaining-­‐response  details  amount)                                error-­‐response)))))

Page 9: Coordinating non blocking io melb-clj

SOLUTION 1.1: PROMISE MONAD LET/DO/DO

(GET  "/bills/:bill-­‐id/payments"  [bill-­‐id  user-­‐id  amount]            (let  [token-­‐req      (auth/card-­‐token  user-­‐id)                        details-­‐req  (bill/details  bill-­‐id)]                (do  [token              token-­‐req                          transaction  (payment/bill  bill-­‐id  amount  token)]                        (if  (success?  transaction)                            (do  [details  details-­‐req]                                    (return  (render-­‐remaining-­‐response  details  amount)))                            (return  error-­‐response)))))

Page 10: Coordinating non blocking io melb-clj

SOLUTION 1.2: PROMISE MONAD DO

(GET  "/bills/:bill-­‐id/payments"  [bill-­‐id  user-­‐id  amount]            (do  [token              (auth/card-­‐token  user-­‐id)                      transaction  (payment/bill  bill-­‐id  amount  token)                      details          (bill/details  bill-­‐id)]                    (return                        (if  (success?  transaction)                            (render-­‐remaining-­‐response  details  amount)                            error-­‐response))))

Page 11: Coordinating non blocking io melb-clj

SOLUTION 1.3: PROMISE + ERROR MONADS

(GET  "/bills/:bill-­‐id/payments"  [bill-­‐id  user-­‐id  amount]            (do  [token              (auth/card-­‐token  user-­‐id)                      transaction  (payment/bill  bill-­‐id  amount  token)                      details          (bill/details  bill-­‐id)]                    (return  (render-­‐remaining-­‐response  details  amount))))

Page 12: Coordinating non blocking io melb-clj

SOLUTION 2: PROMISE CHAIN AND LIFT-M-2

(GET  "/bills/:bill-­‐id/payments"  [bill-­‐id  user-­‐id  amount]            (let  [transaction-­‐req  (chain  (promise  user-­‐id)                                                                      auth/card-­‐token                                                                      (partial  payment/bill  bill-­‐id  amount))                        details-­‐req          (bill/details  bill-­‐id)]                (lift-­‐m-­‐2  (fn  [transaction  details]                                        (if  (success?  transaction)                                            (render-­‐remaining-­‐response  details  amount)                                            error-­‐response)))                transaction-­‐req  details-­‐req))  

Page 13: Coordinating non blocking io melb-clj

SOLUTION 3: RAW PROMISES

(GET  "/bills/:bill-­‐id/payments"  [bill-­‐id  user-­‐id  amount]            (let  [transaction-­‐req  (-­‐>  (auth/card-­‐token  user-­‐id)                                                                (then  (partial  payment/bill  bill-­‐id  amount)))                        details-­‐req          (bill/details  bill-­‐id)]                (when  transaction-­‐req  details-­‐req                    (fn  [transaction  details]                        (if  (success?  transaction)                            (render-­‐remaining-­‐response  details  amount)                            error-­‐response)))))

Page 14: Coordinating non blocking io melb-clj

SOLUTION 4: RAW CALLBACKS

Not  Viable

Page 15: Coordinating non blocking io melb-clj

SOLUTION 5: CORE.ASYNC

(GET  "/bills/:bill-­‐id/payments"  [bill-­‐id  user-­‐id  amount]            (go  (let  [token              (auth/card-­‐token  user-­‐id)                                details          (bill/details  bill-­‐id)                                transaction  (payment/bill  bill-­‐id  amount  (<!  token))]                        (if  (success?  (<!  transaction))                            (render-­‐remaining-­‐response  (<!  details)  amount)                            error-­‐response))))

Page 16: Coordinating non blocking io melb-clj

SOLUTION 6: LAMINA PIPELINE

(GET  "/bills/:bill-­‐id/payments"  [bill-­‐id  user-­‐id  amount]            (let  [details-­‐req  (bill/details  bill-­‐id)]                (pipeline  (auth/card-­‐token  user-­‐id)                                    (partial  payment/bill  bill-­‐id  amount)                                    (fn  [transaction]                                        (if  (success?  transaction)                                            (on-­‐realized  details-­‐req                                                                      (fn  [details]                                                                          (render-­‐remaining-­‐response  details  amount)))                                            error-­‐response)))))

Page 17: Coordinating non blocking io melb-clj

SOLUTION 7: MELTDOWN

No  point

Page 18: Coordinating non blocking io melb-clj

SOLUTION 8: PULSAR PROMISES

(GET  "/bills/:bill-­‐id/payments"  [bill-­‐id  user-­‐id  amount]      #(let  [token              (auth-­‐card-­‐token  user-­‐id)                    details          (bill-­‐details  bill-­‐id)                    transaction  (payment-­‐bill  bill-­‐id  amount  @token)]          (if  (success?  @transaction)              (render-­‐remaining-­‐response  @details  amount)              error-­‐response)))

Page 19: Coordinating non blocking io melb-clj

SOLUTION 9: PULSAR ACTORS

Not  Appropriate

Page 20: Coordinating non blocking io melb-clj

(GET  "/bills/:bill-­‐id/payments"  [bill-­‐id  user-­‐id  amount]      (let  [token              (auth/card-­‐token  user-­‐id)                  details          (bill/details  bill-­‐id)                  transaction  (payment/bill  bill-­‐id  amount  @token)]          (if  (success?  @transaction)              (render-­‐remaining-­‐response  @details  amount)              error-­‐response))) Synchronous

(GET  "/bills/:bill-­‐id/payments"  [bill-­‐id  user-­‐id  amount]      (go  (let  [token              (auth/card-­‐token  user-­‐id)                          details          (bill/details  bill-­‐id)                          transaction  (payment/bill  bill-­‐id  amount  (<!  token))]                  (if  (success?  (<!  transaction))                      (render-­‐remaining-­‐response  (<!  details)  amount)                      error-­‐response)))) core.async

(GET  "/bills/:bill-­‐id/payments"  [bill-­‐id  user-­‐id  amount]      #(let  [token              (auth-­‐card-­‐token  user-­‐id)                    details          (bill-­‐details  bill-­‐id)                    transaction  (payment-­‐bill  bill-­‐id  amount  @token)]            (if  (success?  @transaction)                (render-­‐remaining-­‐response  @details  amount)                (error-­‐response)))) Pulsar

Page 21: Coordinating non blocking io melb-clj

   def  payBill(billId:  Integer,  userId:  Integer,  amount:  Integer):Future[Option[Json]]  =  {        val  seq  =  for  {            token  <-­‐  Auth.cardToken(userId)            tr  <-­‐  Payment.bill(token)        }  yield  tr          async  {            val  transactionProcess  =  await(seq.run)            val  detailProcess  =  await(BillOps.details(billId))            for  {                transaction  <-­‐  transactionProcess                detail  <-­‐  detailProcess            }  yield  renderRemainingResponse(amount,  detail)        }    }

SCALA

Page 22: Coordinating non blocking io melb-clj

REQUESTS PER SECOND

Page 23: Coordinating non blocking io melb-clj

HELLO WORLD

• Single C1-Medium

• 7GB Ram

• 8 Cores

• 313,852 Concurrent Users

• 4756.79 Requests Per Second

• More meaningful results once in SVT with full implementation

Page 24: Coordinating non blocking io melb-clj

ALL DONE AT AUSTRALIA POST DIGITAL MAILBOX

They're hiring. Send your CV to

[email protected]