Como a Carjump usa Scala para revolucionar o mercado de Compartilhamento de carros

Preview:

Citation preview

Scala na Carjump

Como a [Carjump] usa Scala para revolucionar o mercado de compartilhamento de carros

Paulo "JCranky" SiqueiraSenior Scala Dev @ Carjump

JCranky

Dev Scala, com passado Java

­> Berlin­> Carjump

JCranky

Um dos fundadores dos Scaladores

­> scaladores.com.br

­> continua vivo   ­> (Felipe e Onilton)

JCranky

scaladores.com.br

groups.google.com/group/scaladores

http://scaladores.herokuapp.com/

Típica Startup

Fundada há poucos anos, comprada pelos sócios atuais

Passou por rodadas de investimentos

Atua no ramo de car­sharing

Mas que diabos é Car­Sharing?

[Compartilhamento de Carros]

ou

Forma moderna de [Aluguel] de carros

[MODERNA]

[Stationary]

ou

[Fixa]

[REALMENTE moderna]

­> Estacione em qualquer lugar

(dentro de uma área pré­definida)

Carjump: O que?

Agregação de vários provedores em um único App.

Ao ponto: Backend!

­> Scala­> Startup e desenvolvedor único...­> ... para tudo, inclusive front­end

Conceito original

"Ache o carro e pule para a App do provedor"

Arquitetura e Componentes

­> Scala Futures­> Java Futures (passado! \o/)­> Akka­> Mongo­> Scalatra­> Heroku

Arquitetura

if (password < 0) login() 

Scala Futures

cities.flatMap { city =>  val carsF = Future(    new CityWorker(city).call)

  Try(Await.result(    carsF, timeout)) match {

    // handle result  }} 

val system =  ActorSystem("Fetchers")var attempts = 0

while (  system == null &&  attempts < 5) {

  // whatever ...} 

Akka - CarFetcher

override def receive: Receive = {  case FETCH =>    val cars = safeFetch()

    context.system.scheduler      .scheduleOnce(pollPeriod,                self, FETCH)

    persist(cars)} 

Scalatra

get("/") {  new AsyncResult {    val is =      Future {        // 56734 lines      }  }} 

Novo conceito:

[One App to Rule 'em All]

Evolution

[Mini­Services]

­> uso mais intenso do Scalatra

­> APIs RESTful­> DBs individuais

Async

Quase tudo Async

­> Scalatra nos queimou!

Future composition

for {  user <­    isEmailValidated(user)  sepaDetails <­    paymentService      .getSepa(user.code)  remote <­   remoteCreditCheck(     user, sepaDetails)} yield remote 

usando um login token

val findQ = tokensTable  .filter(_.userId === userId)  .filter(_.sentAt.isDefined)  .filter(_.token.isDefined)  .filter(_.usedAt.isEmpty)  .filter(_.expireAt.isDefined) 

Mas nada aconteceu!

IO Monad, declarando o que vai ser feito no BD

um pouco mais de lógica

val q = findQ.result  .flatMap { tokens =>

  // verify if token is valid} 

agora vai!

db.run(q.transactionally) 

Scalatra: nossa triste realidade.

ScentryStrategy

def authenticate()(  implicit request: HttpServletRequest,  response: HttpServletResponse): Option[HttpUser] 

ScentryStrategy

def authenticate()(...) {  val f = validate(request)  Await.result(f, 5 second)} 

Heroku

Fator limitante

Arquitetura engessada

E finalmente...

... nova arquitetura

Nova arquitetura

Grandes mudanças

Parcialmente no Heroku,parcialmente no AWS EC2

­> Akka cluster

­> (pelo menos) Um provedor por nó

­> EC2 micro para cada máquina / nó

cluster config

// other akka remote config

akka.cluster {  seed­nodes = [...]  roles = ["provider", "drivenow"]}

find cluster node

(simplificado)

val cluster = Cluster(context.system)

cluster.state.members  .filter(m =>    m.roles.contains(key) &&    m.status == Status.Up)  .map(_.alongside(_.address)) 

Secret sauce

Ansible!

Provisionamento mega simples de todos os nós no EC2.(ou seria inviável migrar para o EC2)

Install Java

­ apt_repository:    repo=ppa:webupd8team/java    update_cache=yes

­ apt:    name=oracle­java8­installer    state=present

(omitido accept license)

Automatizando tudo!

­ Install Java, Scala, etc­ Build do projetos­ Setup Docker­ etc

Obrigado!

Perguntas?!