Calculando Bitcoins com Twitter e Ruby

Kemel Zaidan @kemelzaidan | Lucas Uyezu @coralton

#CPBR8

Kemel Zaidan

Evangelista de Tecnologia na @Locaweb

  • Community Member no iMasters
  • Editor chefe da Linux Magazine
  • Colunista de Tecnologia
  • Coord. de Projetos de Inclusão
  • Ubuntu Member
  • Membro do Garoa Hacker Clube

Lucas Uyezu

  • IaaS dev @ Locaweb
  • Java 2005 - 2008
  • Android 2011-2012
  • Ruby 2008 - hoje

Motivações do Projeto

  • Aprender Ruby
  • Aprender sobre o Jelastic

Ideias

  • Início do projeto no XDK;
  • Ter uma maneira fácil e "mobile friendly" de conseguir uma conversão de Bitcoins;
  • Que envolvesse Bitcoins;
  • Que rodasse no Jelastic;
  • Que ninguém tivesse feito ainda.

Código do projeto BitcoinCalc do XDK ainda está no Github: https://github.com/kemelzaidan/BitcoinCalc

Requisitos

Twitter tem várias APIs, dentre elas a de streaming (diferente da REST)

Requisitos

  • Isso obrigava a programar assincronamente;
  • Utilizar uma API para descobrir a cotação do Bitcoin;
  • API do bitcoinaverage.com já fornecia a conversão para várias moedas.
  • Ideia era deixar o mais simples possíveis
  • Colocar para rodar no Jelastic

Implementação

 Gems utilizadas

  • tweetstream
  • em-http-request
  • httparty
  • simple_oauth
  • json
  • rack
  • redis

Rack

  • No começo, cada framework e servidor Ruby trabalhava de um jeito.
  • O Rack é uma interface que unifica a forma como frameworks e servidores Ruby conversam.
  • Você pode testar um servidor/PaaS novo sem mudar uma linha do seu código. (Jelastic, Heroku, Unicorn, Puma, etc).
  • Você pode testar um framework novo sem mudar de servidor (Sinatra, RoR).
  • Esse conceito existe em outras linguagens: Python tem WSGI, Java tem servlets.

Reactor Pattern

Definição:

The reactor design pattern is an event handling pattern for handling service requests delivered concurrently to a service handler by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to the associated request handlers".

Professor Chatoff

Metáfora

  • Imagine malabarismo com Threads bloqueadas (por IO), aproveitando recursos não bloqueados (CPU);
  • Beneficia linguagens interpretadas que possuem GIL e acabam rodando num processador só;
  • Pró: economiza dinheiro com hospedagem;
  • Contra: Adiciona complexidade que pode ser desnecessária;
  • Ruby tem Event Machine, Python tem Twisted.

     

Problema

# Setup
$conversions = 0
 
# Conversion
currency, amount = parse_tweet("0.5 in #USD")
result = convert('USD', 0.5)
reply("#{amount} in #{currency} is #{result}")
$conversions += 1
 
# Checking later
reply("We have made #{$conversions} conversions so far")

Solução

# Setup
$redis = Redis.connect
 
# Conversion
currency, amount = parse_tweet("0.5 in #USD")
result = convert('USD', 0.5)
reply("#{amount} in #{currency} is #{result}")
$redis.sadd("conversions", "#{amount} in #{currency} at #{Time.now}")
 
# Checking later
reply("We have made #{$redis.scard("conversions")} conversions so far")

Programação Assíncrona:

Teoria x Prática

  • Problemas nos acessos de threads a valores de variáveis
  • Variáveis globais: pensar antes de usar
  • No ambiente de nuvem, podem haver variáveis globais para processos ou servidores diferentes.

Código Síncrono

puts "1) Fetching data"
respose_body = HTTParty.get "https://api.bitcoinaverage.com/ticker/global/all"
# 1 second later
puts "2) Storing fetched data"
$redis.set(response_body["data"])
puts "3) Done!"

Código Assíncrono

puts "1) Fetching data"
http = EventMachine::HttpRequest.new("https://api.bitcoinaverage.com/ticker/global/all").get
 
http.errback { p '3) Not-done! Error!'; EM.stop }
http.callback do
    # 1 second later
    $redis.set(response_body["data"])
    puts "3) Storing fetched data"
    p http.response_header.status
    p http.response_header
    p http.response
    puts "4) Done!"
 
    EventMachine.stop
end
 
puts "2) Doing other things"

Aprendizados

Programação assíncrona

  • A sequência de execução das instruções não é a mesma que estamos acostumados
  • Debugar mentalmente é mais complicado
  • Log tudo que for possível!!!

Outros

  • Gem do Redis mimetiza a API do banco
  • Possível setar um valor apenas se ele existir

Descobertas do Jelastic

  • Resolve as dependências sozinho através do método padrão da linguagem (Gemfile e bundler no Ruby);
  • Utiliza o Passenger como padrão (Unicorn e Puma estão disponíveis);
  • Como visualizar os puts no terminal? errors.log

Hora de Testar!!!

Programador Ruby???

@kemelzaidan

kemel.zaidan@locaweb.com.br

@coralton

lucas.uyezu@locaweb.com.br

Made with Slides.com