Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Coordinating non blocking io melb-clj

562 views

Published on

Published in: Business, Economy & Finance
  • Be the first to comment

  • Be the first to like this

Coordinating non blocking io melb-clj

  1. 1. COORDINATING NON-BLOCKING IO AND ASYNC HTTP RESPONSES
  2. 2. WHAT IS THE WEB STACK • • • HttpKit as web server Compojure for routing HttpKit for non-blocking http requests
  3. 3. 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 •
  4. 4. 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
  5. 5. CANDIDATES • Synchronous promises • core.async • Promise monad let/do • Lamina • Promise monad chain/lift- • Meltdown m-2 pipeline (LMAX Disrupter) • Raw promises • Pulsar promises • Raw callbacks • Pulsar Actors
  6. 6. 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)))  
  7. 7. 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)))))
  8. 8. 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)))))
  9. 9. 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))))
  10. 10. 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))))
  11. 11. 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))  
  12. 12. 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)))))
  13. 13. SOLUTION 4: RAW CALLBACKS Not  Viable
  14. 14. 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))))
  15. 15. 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)))))
  16. 16. SOLUTION 7: MELTDOWN No  point
  17. 17. 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)))
  18. 18. SOLUTION 9: PULSAR ACTORS Not  Appropriate
  19. 19. (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
  20. 20. SCALA    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)        }    }
  21. 21. REQUESTS PER SECOND
  22. 22. HELLO WORLD • Single C1-Medium • 7GB •8 Ram Cores • 313,852 Concurrent Users • 4756.79 Requests Per Second • More meaningful results once in SVT with full implementation
  23. 23. ALL DONE AT AUSTRALIA POST DIGITAL MAILBOX They're hiring. Send your CV to APDMRecruitment@auspost.com.au

×