Featured Posts

NOVA PROMOÇÃO: Como ganhar convite para a promoção chip TIM BETANOVA PROMOÇÃO: Como ganhar convite para a promoção... Com TIM BETA você faz quantas ligações quiser, manda sms a vontade e ainda tem acesso a internet por R$ 0,25 e MSN de graça sem pagar nada! Agora o TIM Beta é adquirido por meio de convite, e o blog RedRails vai dar um TIM Beta para seus leitores. Basta deixar um comentário dizendo por...

Read more

Apagando Fotos do Iphone                 Bom tive alguns problemas com meu Iphone ao tentar apagar umas fotos  que não apareciam o icone da lixeira ao lado. Isso acontece quando você sincroniza as fotos do Iphone com seu Computador. Como eu consegui...

Read more

Como remover Videos/Filmes de seu Iphone Ipod Para apagar videos do seu Iphone ou Ipod não é tão complicado, mas eles esconderam bem essa opção. segue a baixo o video para fazer isso. Já para enviar eu utilizei o aplicativo CopyTrans

Read more

Como mencionar qualquer pessoa do Facebook (inclusive...               Olá fiéis leitores do RedRails e esporádicos também! Hoje iremos ensinar a vocês como mencionar uma pessoa do modo mais eficiente, tão eficiente que funciona para qualquer pessoa do facebook ( amigo seu ou não) via celular,...

Read more

Deploy com Git, Capistrano, Nginx e Unicorn na Velocidade da Luz

0

Posted on : 13-03-2013 | By : Luiz Carvalho | In : Ruby

rocket+git+capistrano+rails+unicorn+nginx

 

 

 

 

 

 

 

 

Todos nós que já desenvolvemos aplicações WEB e tivemos que implantalas, lembramos dos dias que simplesmente carregamos os arquivos via FTP para o servidor e pronto, tudo estava feito, ou quase isso. Hoje em dia temos que clonar repositórios GIT, reiniciar servidores, definir permissões, criar links simbólicos para arquivos de configurações e outros, limpar cache… dentre outros procedimentos cansativos..

Doutor, o que está errado?

Na minha opinião existem dois problemas críticos com deploys de hoje:

  •      Eles são lentos
  •      Eles causam downtime.

Ambos os temas foram discutidos por grandes empresas como Twitter e Github. Eles têm otimizado o seu processo de deploy para permitir implementações rápidas e contínuas (sem o downtime),  utilizando o Capistrano. Que possíbilita que com pouco trabalho, implantar soluções de deploy similares a do  Github e Twitter.

Então vamos lá

Este guia vai ajudar você a configurar o servidor com Rails 3 com rápido deoloy e zero-downtime. Eu vou estar usando Nginx + Unicorn como servidor para a aplicação, git + capistrano para o deploy.

 Nossa Lista de Compras

Você vai precisar dos seguintes ingredientes:

  • Um Ubuntu Server recente (Eu usei 12.04 Netty);
  • Sua aplicação Rails 3;
  • Um respositório remoto com Git, contendo sua aplicação.

 Pressupostos

Eu estou fazendo algumas suposições sobre sua aplicação:

  •      ruby 1.9.2
  •      Aplicações Rails 3.1 usando Postgres chamado my_site
  •      Você quer usar o RVM e Bundle

Configurar o servidor

Existem algumas coisas que você precisa configurar antes de começar. Os comandos são executados como Root.

Aqui está a lista completa de comando apt-get que eu usei.

 

apt-get update
apt-get upgrade -y    
apt-get install build-essential ruby-full libmagickcore-dev imagemagick libxml2-dev \
  libxslt1-dev git-core postgresql postgresql-client postgresql-server-dev-9.1 nginx curl
apt-get build-dep ruby1.9.1

obs: em postgresql-server-dev-9.1 substitua pela versão corrente…

Você irá precisar designar um usuário para rodar sua aplicação. Acredite em mim, você não irá querer fazer isso com o Root. Eu chamo o meu de deployer

useradd -m -g staff -s /bin/bash deployer
passwd deployer

Para permitir que o deployer execute comando como super-user, adicionar isso em /etc/sudoers.

 # /etc/sudoers

%staff ALL=(ALL) ALL

 Ruby and RVM

Feito isso, você está pronto para instalar rvm. certifique-se de executar isso como root.

bash -s stable < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)
source /home/deployer/.rvm/scripts/rvm

Agora instale o Ruby, neste caso o ruby-1.9.2-p290, e o rubygem.

rvm install ruby-1.9.3
wget http://production.cf.rubygems.org/rubygems/rubygems-1.8.10.tgz
tar zxvf rubygems-1.8.10.tgz
cd rubygems-1.8.10
ruby setup.rb

Criae um arquivo ~ /gemrc, este estabelece alguns padrões necessários para o seu servidor de produção:

# ~/.gemrc
---
:verbose: true
:bulk_threshold: 1000
install: --no-ri --no-rdoc --env-shebang
:sources:
- http://gemcutter.org
- http://gems.rubyforge.org/
- http://gems.github.com
:benchmark: false
:backtrace: false
update: --no-ri --no-rdoc --env-shebang
:update_sources: true

Agora crie o ~/.rvmrc

 # ~/.rvmrc

rvm_trust_rvmrcs_flag=1

Nota: fazer isso tanto para o usuário root quanto para o deployer para evitar confusão mais tarde.

Porque você vai estar rodando sua aplicação em modo de produção otempo, adicione a seguinte linha ao arquivo /etc/environment, de modo que você não tem que repeti-lo com todos os comandos Rails que vocẽ vai usar:

RAILS_ENV=production

Eu não sei que todo mundo usa Postgres, mas eu uso. Primeiro, crie o banco e o login como o usuário postgres:

sudo -u postgres createdb my_site
sudo -u postgres psql

Depois execute essas SQL

CREATE USER my_site WITH PASSWORD 'password';
GRANT ALL PRIVILEGES ON DATABASE my_site TO my_site;

Nginx

Nginx é um grande parte da engenharia Russa. Você precisará de algumas configurações:

# /etc/nginx/sites-available/default
upstream my_site {
  # fail_timeout=0 means we always retry an upstream even if it failed
  # to return a good HTTP response (in case the Unicorn master nukes a
  # single worker for timing out).

  # for UNIX domain socket setups:
  server unix:/tmp/my_site.socket fail_timeout=0;
}

server {
    # if you're running multiple servers, instead of "default" you should
    # put your main domain name here
    listen 80 default;

    # you could put a list of other domain names this application answers
    server_name my_site.example.com;

    root /home/deployer/apps/my_site/current/public;
    access_log /var/log/nginx/my_site_access.log;
    rewrite_log on;

    location / {
        #all requests are sent to the UNIX socket
        proxy_pass  http://my_site;
        proxy_redirect     off;

        proxy_set_header   Host             $host;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;

        client_max_body_size       10m;
        client_body_buffer_size    128k;

        proxy_connect_timeout      90;
        proxy_send_timeout         90;
        proxy_read_timeout         90;

        proxy_buffer_size          4k;
        proxy_buffers              4 32k;
        proxy_busy_buffers_size    64k;
        proxy_temp_file_write_size 64k;
    }

    # if the request is for a static resource, nginx should serve it directly
    # and add a far future expires header to it, making the browser
    # cache the resource and navigate faster over the website
    # this probably needs some work with Rails 3.1's asset pipe_line
    location ~ ^/(images|javascripts|stylesheets|system)/  {
      root /home/deployer/apps/my_site/current/public;
      expires max;
      break;
    }
}

E mais isso

# /etc/nginx/nginx.conf 
user deployer staff;

# Change this depending on your hardware
worker_processes 4;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
    multi_accept on;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay off;
    # server_tokens off;

    # server_names_hash_bucket_size 64;
    # server_name_in_redirect off;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    gzip on;
    gzip_disable "msie6";

    # gzip_vary on;
    gzip_proxied any;
    gzip_min_length 500;
    # gzip_comp_level 6;
    # gzip_buffers 16 8k;
    # gzip_http_version 1.1;
    gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

    ##
    # Virtual Host Configs
    ##

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Ok, agora o Nginx está funcionando. Você preicsa inicia-lo, ele deve dar um erro 500 ou um erro de proxy:

/etc/init.d/nginx start

Unicorn

A parte seguinte envolve a criação de Capistrano e unicórnio para o seu projeto. É aqui que a verdadeira magia acontece.

Você estará fazendo cap deploy 99% do tempo. Este comando precisa ser rápido. Para realizar isso, quero utilizar o poder do git. Em vez de ter O Capistrano fazendo  malabarismos em torno de um monte de diretórios, o que é dolorosamente lento, eu quero usar o git para mudar para a versão correta do meu aplicativo. Isso significa que vou ter apenas um diretório que é atualizado pelo git somente quando ele precisar.

Vamos começar adicionando algumas gem para sua aplicação. Quando tive-lo feito executae bundle install

# Gemfile
gem "unicorn"

group :development do
  gem "capistrano"
end

Pŕoximo passo é adicionar um arquivo de configuração para o unicorn: config/uniconr.rb

# config/unicorn.rb
# Set environment to development unless something else is specified
env = ENV["RAILS_ENV"] || "development"
# See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete
# documentation.
worker_processes 4
# listen on both a Unix domain socket and a TCP port,
# we use a shorter backlog for quicker failover when busy
listen "/tmp/my_site.socket", :backlog => 64
# Preload our app for more speed
preload_app true
# nuke workers after 30 seconds instead of 60 seconds (the default)
timeout 30
pid "/tmp/unicorn.my_site.pid"
# Production specific settings
if env == "production"
# Help ensure your application will always spawn in the symlinked
# "current" directory that Capistrano sets up.
working_directory "/home/deployer/apps/my_site/current"
# feel free to point this anywhere accessible on the filesystem
user 'deployer', 'staff'
shared_path = "/home/deployer/apps/my_site/shared"
stderr_path "#{shared_path}/log/unicorn.stderr.log"
stdout_path "#{shared_path}/log/unicorn.stdout.log"
end
before_fork do |server, worker|
# the following is highly recomended for Rails + "preload_app true"
# as there's no need for the master process to hold a connection
if defined?(ActiveRecord::Base)
ActiveRecord::Base.connection.disconnect!
end
# Before forking, kill the master process that belongs to the .oldbin PID.
# This enables 0 downtime deploys.
old_pid = "/tmp/unicorn.my_site.pid.oldbin"
if File.exists?(old_pid) && server.pid != old_pid
begin
Process.kill("QUIT", File.read(old_pid).to_i)
rescue Errno::ENOENT, Errno::ESRCH
# someone else did our job for us
end
end
end
after_fork do |server, worker|
# the following is *required* for Rails + "preload_app true",
if defined?(ActiveRecord::Base)
ActiveRecord::Base.establish_connection
end
# if preload_app is true, then you may also want to check and
# restart any other shared sockets/descriptors such as Memcached,
# and Redis.  TokyoCabinet file handles are safe to reuse
# between any number of forked children (assuming your kernel
# correctly implements pread()/pwrite() system calls)
end

Ok, como você pode ver temos umas coisas bem legais aqui como reiniciar o servidor sem intervalos ( zero-downtime). Deixe-me contar mais algumas coisas sobre isso.

Unicorn iniciar o processo principal e gera diversos workers ( nós configuramos 4). Quando voce envia o sinal USR2 ao Unicorn, então ele renomeia o servidor principal (antigo) e cria um novo processo, que assume o serviço do master. O antigo serviço ainda continua rodando.

Agora, quando o novo serviço princial iniciar e segmentar esse trabalho, este checka o PID do novo e do antigo processo principal. Se eles forem diferentes, então o novo é iniciado e o para o antigo é enviado um sinal QUIT e shutdown gracefully.

Capistrano

Agora para o Capistrano, adicionando as seguintes linhas no Gemfile.

# Gemfile
group :development do
gem “capistrano”
end

E geramos os arquivos necessários para o capoistrano

capify .

Abra seu config/deploy.rb e substitua pelos seguintes comandos

Este script de deploy não é totalmente abrangente, mas possui um pulo do gato, quando deletamos a pasta atual, mantendo apenas a última versão do projeto, assim não acumulando espaço desnecessário.

# config/deploy.rb 
require "bundler/capistrano"

set :scm,             :git
set :repository,      "git@codeplane.com:you/my_site.git"
set :branch,          "origin/master"
set :migrate_target,  :current
set :ssh_options,     { :forward_agent => true }
set :rails_env,       "production"
set :deploy_to,       "/home/deployer/apps/my_site"
set :normalize_asset_timestamps, false

set :user,            "deployer"
set :group,           "staff"
set :use_sudo,        false

role :web,    "123.456.789.012"
role :app,    "123.456.789.012"
role :db,     "123.456.789.012", :primary => true

set(:latest_release)  { fetch(:current_path) }
set(:release_path)    { fetch(:current_path) }
set(:current_release) { fetch(:current_path) }

set(:current_revision)  { capture("cd #{current_path}; git rev-parse --short HEAD").strip }
set(:latest_revision)   { capture("cd #{current_path}; git rev-parse --short HEAD").strip }
set(:previous_revision) { capture("cd #{current_path}; git rev-parse --short HEAD@{1}").strip }

default_environment["RAILS_ENV"] = 'production'

# Use our ruby-1.9.2-p290@my_site gemset
default_environment["PATH"]         = "--"
default_environment["GEM_HOME"]     = "--"
default_environment["GEM_PATH"]     = "--"
default_environment["RUBY_VERSION"] = "ruby-1.9.2-p290"

default_run_options[:shell] = 'bash'

namespace :deploy do
  desc "Deploy your application"
  task :default do
    update
    restart
  end

  desc "Setup your git-based deployment app"
  task :setup, :except => { :no_release => true } do
    dirs = [deploy_to, shared_path]
    dirs += shared_children.map { |d| File.join(shared_path, d) }
    run "#{try_sudo} mkdir -p #{dirs.join(' ')} && #{try_sudo} chmod g+w #{dirs.join(' ')}"
    run "git clone #{repository} #{current_path}"
  end

  task :cold do
    update
    migrate
  end

  task :update do
    transaction do
      update_code
    end
  end

  desc "Update the deployed code."
  task :update_code, :except => { :no_release => true } do
    run "cd #{current_path}; git fetch origin; git reset --hard #{branch}"
    finalize_update
  end

  desc "Update the database (overwritten to avoid symlink)"
  task :migrations do
    transaction do
      update_code
    end
    migrate
    restart
  end

  task :finalize_update, :except => { :no_release => true } do
    run "chmod -R g+w #{latest_release}" if fetch(:group_writable, true)

    # mkdir -p is making sure that the directories are there for some SCM's that don't
    # save empty folders
    run <<-CMD
      rm -rf #{latest_release}/log #{latest_release}/public/system #{latest_release}/tmp/pids &&
      mkdir -p #{latest_release}/public &&
      mkdir -p #{latest_release}/tmp &&
      ln -s #{shared_path}/log #{latest_release}/log &&
      ln -s #{shared_path}/system #{latest_release}/public/system &&
      ln -s #{shared_path}/pids #{latest_release}/tmp/pids &&
      ln -sf #{shared_path}/database.yml #{latest_release}/config/database.yml
    CMD

    if fetch(:normalize_asset_timestamps, true)
      stamp = Time.now.utc.strftime("%Y%m%d%H%M.%S")
      asset_paths = fetch(:public_children, %w(images stylesheets javascripts)).map { |p| "#{latest_release}/public/#{p}" }.join(" ")
      run "find #{asset_paths} -exec touch -t #{stamp} {} ';'; true", :env => { "TZ" => "UTC" }
    end
  end

  desc "Zero-downtime restart of Unicorn"
  task :restart, :except => { :no_release => true } do
    run "kill -s USR2 `cat /tmp/unicorn.my_site.pid`"
  end

  desc "Start unicorn"
  task :start, :except => { :no_release => true } do
    run "cd #{current_path} ; bundle exec unicorn_rails -c config/unicorn.rb -D"
  end

  desc "Stop unicorn"
  task :stop, :except => { :no_release => true } do
    run "kill -s QUIT `cat /tmp/unicorn.my_site.pid`"
  end  

  namespace :rollback do
    desc "Moves the repo back to the previous version of HEAD"
    task :repo, :except => { :no_release => true } do
      set :branch, "HEAD@{1}"
      deploy.default
    end

    desc "Rewrite reflog so HEAD@{1} will continue to point to at the next previous release."
    task :cleanup, :except => { :no_release => true } do
      run "cd #{current_path}; git reflog delete --rewrite HEAD@{1}; git reflog delete --rewrite HEAD@{1}"
    end

    desc "Rolls back to the previously deployed version."
    task :default do
      rollback.repo
      rollback.cleanup
    end
  end
end

def run_rake(cmd)
  run "cd #{current_path}; #{rake} #{cmd}"
end

Agora, há uma coisa que você precisa fazer. Eu gosto de rodar minhas aplicações utilizando sua propria. Isso mantém tudo mais limpo e isolado. Entre como usuário deployer  e crie o seu gemset. preenchendo os PATH com GEM_HOME , ​​GEM_PATH.

Não se esqueça de instalar o Bundle em seu GEM SET.

Database configuration

Eu sempre gostei de colocar o arquiv de configuração fora do GIT, Eu o coloco no diretório SHARED.

# /home/deployer/apps/my_site/shared/database.yml
production:
adapter: postgresql
encoding: unicode
database: my_site_production
pool: 5
username: my_site
password: password

First setup

Agora realize o setup de seu deploy, assim:

cap deploy:setup

Isto irá colnar seu repositório e o conectar com seu database.yml .Opcionalmente, você pode rodar suas migrations ou fazer o upload de suas SQL para iniciar rapidamente sua aplicação.

Deployments

Quando você tiver uma nova feature em um branch, realize esse procedimento para realizar o deploy disso:

  1. Merge feature_branch into master
  2. Rode os testes para verificar se tudo está OK.
  3. Push master
  4. Execute o  cap deploy

 

 

asd

Ruby Client para REST API do Jasper Report Server

0

Posted on : 07-03-2013 | By : Luiz Carvalho | In : Ruby

ruby-report-jasper-server+logo

 

 

 

 

 

 

 

 

 

 

Utilizar chamadas REST no Jasper Report Server foi uma bom desafio pra mim, aqui pra vocês o resultiado disso, um pequeno Script que resolve esse “problema” rapidinho. Utilizando BASIC AUTHENTICATION + mais a interface RESTFul do JasperReport.

Look Code in my Github https://github.com/LuizCarvalho/JasperRest/tree/master/ruby

  1. #!/usr/bin/env ruby
  2. # encoding: utf-8
  3.  
  4. require "rubygems"
  5. require "net/http"
  6. require "rexml/document"
  7.  
  8. REPORT_NAME = 'StandardChartsReport'
  9. REPORT_GROUP = "samples"
  10. SERVER_ROOT = "127.0.0.1" #MUDE PARA O ENDERECO DE SEU SERVIDOR
  11. SERVER_PORT = 8080
  12. SERVER_USER = "jasperadmin"
  13. SERVER_PASSWORD = "jasperadmin"
  14. FORMAT = "PDF"
  15. FILE_NAME = "report.pdf"
  16.  
  17. REPORT_PATH = "http://#{SERVER_ROOT}:#{SERVER_PORT}/jasperserver/rest/report"
  18.  
  19. def to_ms(time)
  20. start = Time.new(1970,1,1)
  21. ((time.to_f - start.to_f) * 1000.0).to_i
  22. end
  23.  
  24. #parametros sendo passados somente como exemplo
  25. PARAMS = {:criacao_inicio=>to_ms(Time.new(2011,01,01)),:criacao_final=>to_ms(Time.new(2014,01,01))}
  26.  
  27. def build_xml_request
  28. url_string = "/reports/#{REPORT_GROUP}/#{REPORT_NAME}"
  29. request_body = "null"
  30. puts "CRIANDO XML PARA: #{url_string} "
  31. PARAMS.each do|k,v|
  32. request_body += "#{v.to_s}"
  33. puts "PARAMETROS: #{k}=#{v.to_s}; "
  34. end
  35. request_body += ""
  36. end
  37.  
  38. def get_uuid_and_cookie
  39.  
  40. body = ""
  41. cookie = ""
  42. puts "FULL URL: #{"#{REPORT_PATH}/reports/#{REPORT_GROUP}/#{REPORT_NAME}"}"
  43. uri = URI.parse("#{REPORT_PATH}/reports/#{REPORT_GROUP}/#{REPORT_NAME}")
  44. http = Net::HTTP.new(uri.host, uri.port)
  45. http.start do |http|
  46. req = Net::HTTP::Put.new(uri.path + "?RUN_OUTPUT_FORMAT=#{FORMAT}")
  47. puts "ACESSANDO: #{uri.path}?RUN_OUTPUT_FORMAT=#{FORMAT}"
  48. req.basic_auth(SERVER_USER, SERVER_PASSWORD)
  49. req.body = build_xml_request
  50. resp = http.request(req)
  51. body = resp.body
  52. puts "COOKIE RECEBIDO: #{resp['Set-Cookie']}"
  53. cookie = resp['Set-Cookie']
  54. end
  55.  
  56. xml = REXML::Document.new(body)
  57. puts "\n\n XML \n #{xml} \n\n"
  58. uuid_xml = xml.elements["report/uuid"]
  59.  
  60. if uuid_xml
  61. uuid = uuid_xml.text
  62. puts "UUID RECEBIDO: #{uuid}"
  63. return uuid,cookie
  64. else
  65. puts "PROBLEMA AO RECEBER UUID. RESPOSTA: #{uuid_xml}"
  66. return false,false
  67. end
  68. end
  69.  
  70. def get_file
  71. body_get = nil
  72. uuid,cookie = get_uuid_and_cookie
  73. if uuid
  74. uri_get = URI.parse("#{REPORT_PATH}/#{uuid}")
  75. puts "URL DO RELATORIO: #{uri_get}"
  76. http_get = Net::HTTP.new(uri_get.host, uri_get.port)
  77.  
  78. http_get.start do |http|
  79. req = Net::HTTP::Get.new(uri_get.path + "?file=report")
  80. puts "REQ: #{req.path}"
  81. req.basic_auth(SERVER_USER, SERVER_PASSWORD)
  82. req['cookie'] = cookie
  83. resp = http.request(req)
  84. body_get = resp.body
  85. end
  86. end
  87. body_get
  88. end
  89.  
  90. file = get_file
  91. if file
  92. #puts file
  93. f = File.new(FILE_NAME, 'wb')
  94. f.write(file)
  95. f.close
  96. else
  97. puts "Não foi possível criar o relatório"
  98. end

 

 

RAILS (ActiveRecord) Importando/Exportando um objeto de uma Base para Outra

0

Posted on : 28-02-2013 | By : Luiz Carvalho | In : Ruby, Sem categoria

rails_new

 

 

 

 

@object = YourObject.first
x = YAML::dump(@objeto)
@outro_obj = YAML:load(x)
attrs = @outro_obj.attributes
attrs.except!(“id”)
attrs.except!(“updated_at”)
attrs.except!(“created_at”)
YourOuterModel.create(attrs)

Ruby on Rails: Agrupando Resultados do ActiveRecord

1

Posted on : 29-02-2012 | By : Luiz Carvalho | In : Desenvolvimento, Dicas, Ruby

 

Esses dias tive um trabalho para fazer agrupamento de resultados de um find com Rails.

Tenho dois Models: User e Group
onde User belongs_to Group e Group has_many Users
Eu gostaria de Obter o seguinte resultado em um minha busca
Related Posts Plugin for WordPress, Blogger...