clojure at a post office

28
CLOJURE AT A POST OFFICE

Upload: logan-campbell

Post on 28-Nov-2014

2.003 views

Category:

Internet


0 download

DESCRIPTION

Presented at Euroclojure June 2014.

TRANSCRIPT

Page 1: Clojure at a post office

CLOJURE AT A POST OFFICE

Page 2: Clojure at a post office
Page 3: Clojure at a post office

HTTP-KIT

• AWS C1-Medium!

• 7GB Ram!

• 8 Cores

• 313,852 Concurrent Users!

• 4756.79 Requests Per Second

Page 4: Clojure at a post office

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

Page 5: Clojure at a post office

CANDIDATES

• Synchronous promises!

• Promise monad let/do!

• Raw promises!

• Raw callbacks!

• core.async!

• Lamina pipeline!

• Meltdown (LMAX Disrupter)!

• Pulsar promises!

• Pulsar Actors

Page 6: Clojure at a post office

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 7: Clojure at a post office

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))))

Page 8: Clojure at a post office

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)))))

Page 9: Clojure at a post office

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)))))

Page 10: Clojure at a post office

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 11: Clojure at a post office

SOLUTION 4: RAW CALLBACKS

Not"Viable

Page 12: Clojure at a post office

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 13: Clojure at a post office

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 14: Clojure at a post office

SOLUTION 7: MELTDOWN

No"point

Page 15: Clojure at a post office

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 16: Clojure at a post office

SOLUTION 9: PULSAR ACTORS

Not"Appropriate

Page 17: Clojure at a post office

(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 18: Clojure at a post office

""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 19: Clojure at a post office

REQUESTS PER SECOND

Page 20: Clojure at a post office
Page 21: Clojure at a post office

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.

Page 22: Clojure at a post office

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

Page 23: Clojure at a post office

Write

!!

Cassandra

Service A

Service B Index Maintainer

Notify

Read Write

Rabbit MQ

Publish

Triggers

Page 24: Clojure at a post office

CASSANDRA TRIGGERS

• 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)

Page 25: Clojure at a post office
Page 26: Clojure at a post office

User Service

Mail Service

Provider Service

Cassandra

IOS Web Android

Page 27: Clojure at a post office

User Service

Authentication

Multi Factor Authentication

Authorisation

User Profile

Password Reset

Page 28: Clojure at a post office