0
CLOJURE AT A POST OFFICE
HTTP-KIT
• AWS C1-Medium!
• 7GB Ram!
• 8 Cores
• 313,852 Concurrent Users!
• 4756.79 Requests Per Second
If payment is success: display amount remaining on bill!
If payment fails: display error
Make a payment on a bill!
- Not n...
CANDIDATES
• Synchronous promises!
• Promise monad let/do!
• Raw promises!
• Raw callbacks!
• core.async!
• Lamina pipelin...
SOLUTION 0:
SYNCHRONOUS
(GET""/bills/:bill*id/payments""[bill*id"user*id"amount]"
""(let'[token"""""""(auth/card/token"use...
SOLUTION 1.1:
PROMISE MONAD DO
(GET""/bills/:bill*id/payments""[bill*id"user*id"amount]"
"""""(do'[token"""""""(auth/card/...
SOLUTION 1.2:
PROMISE MONAD LET/DO
(GET""/bills/:bill*id/payments""[bill*id"user*id"amount]"
"""""(let'[token*req"""(auth/...
SOLUTION 1.3:
PROMISE MONAD LET/DO/DO
(GET""/bills/:bill*id/payments""[bill*id"user*id"amount]"
"""""(let'[token*req"""(au...
SOLUTION 3:
RAW PROMISES
(GET""/bills/:bill*id/payments""[bill*id"user*id"amount]"
"""""(let'[transaction*req"(*>"(auth/ca...
SOLUTION 4:
RAW CALLBACKS
Not"Viable
SOLUTION 5:
CORE.ASYNC
(GET""/bills/:bill*id/payments""[bill*id"user*id"amount]"
"""""(go"(let'[token"""""""(auth/card/tok...
SOLUTION 6:
LAMINA PIPELINE
(GET""/bills/:bill*id/payments""[bill*id"user*id"amount]"
"""""(let'[details*req"(bill/details...
SOLUTION 7:
MELTDOWN
No"point
SOLUTION 8:
PULSAR PROMISES
(GET""/bills/:bill*id/payments""[bill*id"user*id"amount]"
""#(let'[token"""""""(auth/card/toke...
SOLUTION 9:
PULSAR ACTORS
Not"Appropriate
(GET""/bills/:bill*id/payments""[bill*id"user*id"amount]"
""(let'[token"""""""(auth/card/token"user*id)"
""""""""details""...
""def"payBill(billId:"Integer,"userId:"Integer,"amount:"Integer):Future[Option[Json]]"="{
""""val"seq"="for"{
""""""token"...
REQUESTS PER SECOND
CQRS!
• Want fast reads. Reduce the
number of queries.!
• Don't want to have to
update write code every
time we add a new ...
1.#Just#write#to#normalised#copy#
1.1.# Just#read#everything#every#time#
1.2.# Read#and#cache#
1.2.1.# Cache#the#page#
1.2...
Write
!
!
Cassandra
Service A
Service B Index Maintainer
Notify
Read Write
Rabbit MQ
Publish
Triggers
CASSANDRATRIGGERS
• Can just throw the Clojure
jar in there!
• Everything is byte buffers!
• Need to know the type of
field...
User
Service
Mail
Service
Provider
Service
Cassandra
IOS Web Android
User
Service
Authentication
Multi Factor
Authentication
Authorisation
User Profile
Password Reset
Clojure at a post office
Clojure at a post office
Clojure at a post office
Clojure at a post office
Upcoming SlideShare
Loading in...5
×

Clojure at a post office

2,747

Published on

Presented at Euroclojure June 2014.

0 Comments
5 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,747
On Slideshare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
19
Comments
0
Likes
5
Embeds 0
No embeds

No notes for slide

Transcript of "Clojure at a post office"

  1. 1. CLOJURE AT A POST OFFICE
  2. 2. HTTP-KIT • AWS C1-Medium! • 7GB Ram! • 8 Cores • 313,852 Concurrent Users! • 4756.79 Requests Per Second
  3. 3. If payment is success: display amount remaining on bill! If payment fails: display error 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. POST request to payment gateway! 2. GET how much was left to be payed
  4. 4. CANDIDATES • Synchronous promises! • Promise monad let/do! • Raw promises! • Raw callbacks! • core.async! • Lamina pipeline! • Meltdown (LMAX Disrupter)! • Pulsar promises! • Pulsar Actors
  5. 5. 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)))"
  6. 6. SOLUTION 1.1: 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))))
  7. 7. SOLUTION 1.2: 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.3: 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 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)))))
  10. 10. SOLUTION 4: RAW CALLBACKS Not"Viable
  11. 11. 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))))
  12. 12. 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)))))
  13. 13. SOLUTION 7: MELTDOWN No"point
  14. 14. 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)))
  15. 15. SOLUTION 9: PULSAR ACTORS Not"Appropriate
  16. 16. (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
  17. 17. ""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
  18. 18. REQUESTS PER SECOND
  19. 19. CQRS! • Want fast reads. Reduce the number of queries.! • Don't want to have to update write code every time we add a new reader.! • Don't want to have to update reader every time there's a new writer.! • Would be great to have an event stream to re-calculate current state.
  20. 20. 1.#Just#write#to#normalised#copy# 1.1.# Just#read#everything#every#time# 1.2.# Read#and#cache# 1.2.1.# Cache#the#page# 1.2.2.# Cache#the#intermediate#data;structure# 2.#Just#write#to#views# 2.1.# Direct#write# 2.2.# Event#stream# 2.2.1.# Persisted# 2.2.1.1.# Domain#events# 2.2.1.1.1.#Live#update# 2.2.1.1.2.#Async#update# 2.2.1.2.# CRUD#event# 2.2.1.2.1.#Live#update# 2.2.1.2.2.#Async#update# 2.2.2.# Ephemeral# 2.2.2.1.# Domain#events# 2.2.2.1.1.#Live#update# 2.2.2.2.# CRUD#event# 2.2.2.2.1.#Live#update# 3.#Write#to#views#and#normalized#copy## 3.1.# Direct#write# 3.2.# Event#stream# 3.2.1.# Persisted# 3.2.1.1.# Domain#events# 3.2.1.1.1.#Live#update# 3.2.1.1.2.#Async#update# 3.2.1.2.# CRUD#event# 3.2.1.2.1.#Live#update# 3.2.1.2.2.#Async#update# 3.2.2.# Ephemeral# 3.2.2.1.# Domain#events# 3.2.2.1.1.#Live#update# 3.2.2.2.# CRUD#event# 3.2.2.2.1.#Live#update# 3.3.# Write#to#normalized#keyspace#causing# trigger# 3.3.1.# Direct#update#to#views# 3.3.2.# Event#to#be#published# 3.3.2.1.# Persisted# 3.3.2.1.1.#Live#Update# 3.3.2.1.2.#Async#update# 3.3.2.2.# Ephemeral# 3.3.2.2.1.#Live#Update
  21. 21. Write ! ! Cassandra Service A Service B Index Maintainer Notify Read Write Rabbit MQ Publish Triggers
  22. 22. CASSANDRATRIGGERS • Can just throw the Clojure jar in there! • Everything is byte buffers! • Need to know the type of fields out of band! • One class per trigger per table! • Bizarre key names (format changes depending on value type)
  23. 23. User Service Mail Service Provider Service Cassandra IOS Web Android
  24. 24. User Service Authentication Multi Factor Authentication Authorisation User Profile Password Reset
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×