Puma é um servidor HTTP 1.1 simples, rápido, multithread e altamente paralelo para aplicações Ruby/Rack .
Puma é um servidor para aplicações HTTP baseadas em Rack escritas em Ruby. Isso é:
Originalmente projetado como um servidor para Rubinius, o Puma também funciona bem com Ruby (MRI) e JRuby.
Na ressonância magnética, há um Global VM Lock (GVL) que garante que apenas um thread possa executar o código Ruby por vez. Mas se você estiver bloqueando muito IO (como chamadas HTTP para APIs externas como o Twitter), o Puma ainda melhora o rendimento da ressonância magnética, permitindo que a espera de IO seja feita em paralelo. Implementações Ruby verdadeiramente paralelas (TruffleRuby, JRuby) não têm essa limitação.
$ gem install puma
$ puma
Sem argumentos, o puma procurará um arquivo rackup (.ru) no diretório de trabalho chamado config.ru
.
O Puma irá instalar/compilar com suporte para soquetes SSL, assumindo que os arquivos de desenvolvimento OpenSSL estejam instalados no sistema.
Se o sistema não tiver arquivos de desenvolvimento OpenSSL instalados, o Puma irá instalar/compilar, mas não permitirá conexões SSL.
Puma é o servidor padrão para Rails, incluído no Gemfile gerado.
Inicie seu servidor com o comando rails
:
$ rails server
Muitas opções de configuração e recursos do Puma não estão disponíveis ao usar rails server
. É recomendado que você use o executável do Puma:
$ bundle exec puma
Você pode executar seu aplicativo Sinatra com Puma na linha de comando assim:
$ ruby app.rb -s Puma
Para realmente configurar o Puma usando um arquivo de configuração, como puma.rb
, no entanto, você precisa usar o executável puma
. Para fazer isso, você deve adicionar um arquivo rackup ao seu aplicativo Sinatra:
# config.ru
require './app'
run Sinatra :: Application
Você pode então iniciar seu aplicativo usando:
$ bundle exec puma
A Puma oferece inúmeras opções. Consulte puma -h
(ou puma --help
) para obter uma lista completa de opções CLI ou consulte Puma::DSL
ou dsl.rb.
Você também pode encontrar vários exemplos de configuração como parte do conjunto de testes.
Para fins de depuração, você pode definir a variável de ambiente PUMA_LOG_CONFIG
com um valor e a configuração carregada será impressa como parte do processo de inicialização.
Puma usa um pool de threads. Você pode definir o número mínimo e máximo de threads disponíveis no pool com o sinalizador -t
(ou --threads
):
$ puma -t 8:32
O Puma dimensionará automaticamente o número de threads, do mínimo até o limite máximo, com base na quantidade de tráfego presente. O padrão atual é 0:16
e na ressonância magnética é 0:5
. Sinta-se à vontade para experimentar, mas tome cuidado para não definir o número máximo de threads para um grande número, pois você pode esgotar os recursos do sistema (ou causar contenção para o Global VM Lock, ao usar MRI).
Esteja ciente de que, além disso, o Puma cria threads por conta própria para fins internos (por exemplo, lidar com clientes lentos). Portanto, mesmo se você especificar -t 1:1, espere cerca de 7 threads criados em seu aplicativo.
Puma também oferece “modo cluster”. O modo cluster fork
os trabalhadores de um processo mestre. Cada processo filho ainda possui seu próprio pool de threads. Você pode ajustar o número de trabalhadores com o sinalizador -w
(ou --workers
):
$ puma -t 8:32 -w 3
Ou com a variável de ambiente WEB_CONCURRENCY
:
$ WEB_CONCURRENCY=3 puma -t 8:32
Observe que os threads ainda são usados no modo clusterizado e a configuração do sinalizador de thread -t
é por trabalhador, portanto -w 2 -t 16:16
gerará 32 threads no total, com 16 em cada processo de trabalho.
Se a variável de ambiente WEB_CONCURRENCY
estiver definida como "auto"
e a gema concurrent-ruby
estiver disponível em seu aplicativo, o Puma definirá a contagem do processo de trabalho como o resultado dos processadores disponíveis.
Para uma discussão aprofundada sobre as vantagens das configurações de contagem de threads e processos, consulte nossos documentos.
No modo clusterizado, o Puma pode “pré-carregar” seu aplicativo. Isso carrega todo o código do aplicativo antes da bifurcação. O pré-carregamento reduz o uso total de memória do seu aplicativo por meio de um recurso do sistema operacional chamado copy-on-write.
Se a variável de ambiente WEB_CONCURRENCY
estiver definida com um valor > 1 (e --prune-bundler
não tiver sido especificado), o pré-carregamento será habilitado por padrão. Caso contrário, você pode usar o sinalizador --preload
na linha de comando:
$ puma -w 3 --preload
Ou, se estiver usando um arquivo de configuração, você pode usar o preload_app!
método:
# config/puma.rb
workers 3
preload_app!
O pré-carregamento não pode ser usado com a reinicialização em fases, pois a reinicialização em fases mata e reinicia os trabalhadores um por um, e o pré-carregamento copia o código do mestre nos trabalhadores.
Ao usar o modo clusterizado, o DSL de configuração do Puma fornece ganchos before_fork
e on_worker_boot
para executar o código quando os forks do processo mestre e os trabalhadores filhos são inicializados, respectivamente.
É recomendado usar esses ganchos com preload_app!
, caso contrário, as constantes carregadas pela sua aplicação (como Rails
) não estarão disponíveis dentro dos ganchos.
# config/puma.rb
before_fork do
# Add code to run inside the Puma master process before it forks a worker child.
end
on_worker_boot do
# Add code to run inside the Puma worker process after forking.
end
Além disso, há um gancho on_refork
que é usado apenas no modo fork_worker
, quando o processo filho do trabalhador 0 bifurca um trabalhador neto:
on_refork do
# Used only when fork_worker mode is enabled. Add code to run inside the Puma worker 0
# child process before it forks a grandchild worker.
end
É importante observar as seguintes considerações quando Ruby bifurca um processo filho:
SocketError
, Errno::EPIPE
e EOFError
.Portanto, recomendamos o seguinte:
before_fork
e on_refork
para desconectar as conexões de soquete do pai durante a bifurcação, para que não sejam copiadas acidentalmente para o processo filho.on_worker_boot
para reiniciar quaisquer threads em segundo plano no filho bifurcado. A configuração DSL do Puma fornece ganchos de ciclo de vida do processo mestre on_booted
, on_restart
e on_stopped
que podem ser usados para especificar blocos de código a serem executados em cada evento:
# config/puma.rb
on_booted do
# Add code to run in the Puma master process after it boots,
# and also after a phased restart completes.
end
on_restart do
# Add code to run in the Puma master process when it receives
# a restart command but before it restarts.
end
on_stopped do
# Add code to run in the Puma master process when it receives
# a stop command but before it shuts down.
end
Se o Puma encontrar um erro fora do contexto do seu aplicativo, ele responderá com um 400/500 e uma mensagem de erro textual simples (consulte Puma::Server#lowlevel_error
ou server.rb). Você pode especificar um comportamento personalizado para este cenário. Por exemplo, você pode relatar o erro ao serviço de rastreamento de erros de terceiros (neste exemplo, rollbar):
lowlevel_error_handler do | e , env , status |
if status == 400
message = "The server could not process the request due to an error, such as an incorrectly typed URL, malformed syntax, or a URL that contains illegal characters. n "
else
message = "An error has occurred, and engineers have been informed. Please reload the page. If you continue to have problems, contact [email protected] n "
Rollbar . critical ( e )
end
[ status , { } , [ message ] ]
end
Vincule o Puma a um soquete com o sinalizador -b
(ou --bind
):
$ puma -b tcp://127.0.0.1:9292
Para usar um soquete UNIX em vez de TCP:
$ puma -b unix:///var/run/puma.sock
Se você precisar alterar as permissões do soquete UNIX, basta adicionar um parâmetro umask:
$ puma -b 'unix:///var/run/puma.sock?umask=0111'
Precisa de um pouco de segurança? Use soquetes SSL:
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert'
localhost
, para uso em desenvolvimento): Puma oferece suporte ao gem localhost
para certificados autoassinados. Isso é particularmente útil se você quiser usar o Puma com SSL localmente, e certificados autoassinados funcionarão para o seu caso de uso. Atualmente, a integração só pode ser utilizada em ressonância magnética.
O Puma configura SSL automaticamente quando o gem localhost
é carregado em um ambiente development
:
Adicione a gema ao seu Gemfile:
group ( :development ) do
gem 'localhost'
end
E exija isso implicitamente usando o bundler:
require "bundler"
Bundler . require ( :default , ENV [ "RACK_ENV" ] . to_sym )
Como alternativa, você pode exigir a gema em seu arquivo de configuração, config/puma/development.rb
, config/puma.rb
ou definida por meio da opção -C
cli:
require 'localhost'
# configuration methods (from Puma::DSL) as needed
Além disso, o Puma deve estar escutando um soquete SSL:
$ puma -b ' ssl://localhost:9292 ' -C config/use_local_host.rb
# The following options allow you to reach Puma over HTTP as well:
$ puma -b ssl://localhost:9292 -b tcp://localhost:9393 -C config/use_local_host.rb
Para usar ou evitar cifras SSL específicas para TLSv1.2 e anteriores, use as opções ssl_cipher_filter
ou ssl_cipher_list
.
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&ssl_cipher_filter=!aNULL:AES+SHA'
$ puma -b 'ssl://127.0.0.1:9292?keystore=path_to_keystore&keystore-pass=keystore_password&ssl_cipher_list=TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA'
Para configurar os ciphersuites TLSv1.3 disponíveis, use a opção ssl_ciphersuites
(não disponível para JRuby).
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&ssl_ciphersuites=TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256'
Consulte https://www.openssl.org/docs/man1.1.1/man1/ciphers.html para obter o formato do filtro de cifra e a lista completa de conjuntos de cifras.
Desative o TLS v1 com a opção no_tlsv1
:
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&no_tlsv1=true'
Para habilitar flags de verificação oferecidos pelo OpenSSL, use verification_flags
(não disponível para JRuby):
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&verification_flags=PARTIAL_CHAIN'
Você também pode definir vários sinalizadores de verificação (separando-os com vírgula):
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&verification_flags=PARTIAL_CHAIN,CRL_CHECK'
Lista de sinalizadores disponíveis: USE_CHECK_TIME
, CRL_CHECK
, CRL_CHECK_ALL
, IGNORE_CRITICAL
, X509_STRICT
, ALLOW_PROXY_CERTS
, POLICY_CHECK
, EXPLICIT_POLICY
, INHIBIT_ANY
, INHIBIT_MAP
, NOTIFY_POLICY
, EXTENDED_CRL_SUPPORT
, USE_DELTAS
, CHECK_SS_SIGNATURE
, TRUSTED_FIRST
, SUITEB_128_LOS_ONLY
, SUITEB_192_LOS
, SUITEB_128_LOS
, PARTIAL_CHAIN
, NO_ALT_CHAINS
, NO_CHECK_TIME
(ver https://www.openssl.org/docs/manmaster/man3/X509_VERIFY_PARAM_set_hostflags.html#VERIFICATION-FLAGS).
Para habilitar a descriptografia em tempo de execução de uma chave SSL criptografada (não disponível para JRuby), use key_password_command
:
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&key_password_command=/path/to/command.sh'
key_password_command
deve:
Por exemplo:
#! /bin/sh
echo " this is my password "
key_password_command
pode ser usado com key
ou key_pem
. Se a chave não estiver criptografada, o executável não será chamado.
O Puma possui um aplicativo integrado de status e controle que pode ser usado para consultar e controlar o Puma.
$ puma --control-url tcp://127.0.0.1:9293 --control-token foo
O Puma iniciará o servidor de controle na porta localhost 9293. Todas as solicitações ao servidor de controle precisarão incluir o token de controle (neste caso, token=foo
) como parâmetro de consulta. Isso permite uma autenticação simples. Confira Puma::App::Status
ou status.rb para ver o que o aplicativo de status tem disponível.
Você também pode interagir com o servidor de controle via pumactl
. Este comando irá reiniciar o Puma:
$ pumactl --control-url 'tcp://127.0.0.1:9293' --control-token foo restart
Para ver uma lista de opções pumactl
, use pumactl --help
.
Você também pode fornecer um arquivo de configuração com o sinalizador -C
(ou --config
):
$ puma -C /path/to/config
Se nenhum arquivo de configuração for especificado, o Puma procurará um arquivo de configuração em config/puma.rb
. Se um ambiente for especificado (por meio do sinalizador --environment
ou por meio das variáveis de ambiente APP_ENV
, RACK_ENV
ou RAILS_ENV
), o Puma procura um arquivo de configuração em config/puma/<environment_name>.rb
e depois volta para config/puma.rb
.
Se você quiser evitar que o Puma procure um arquivo de configuração nesses locais, inclua o sinalizador --no-config
:
$ puma --no-config
# or
$ puma -C "-"
Os outros efeitos colaterais da configuração do ambiente são mostrar rastreamentos de pilha (em development
ou test
), e a configuração RACK_ENV pode potencialmente afetar o middleware que procura esse valor para alterar seu comportamento. O valor padrão do puma RACK_ENV é development
. Você pode ver todos os valores padrão de configuração em Puma::Configuration#puma_default_options
ou configuration.rb.
Confira Puma::DSL
ou dsl.rb para ver todas as opções disponíveis.
Puma inclui a capacidade de reiniciar sozinho. Quando disponível (MRI, Rubinius, JRuby), Puma realiza uma "reinicialização a quente". Esta é a mesma funcionalidade disponível no Unicorn e NGINX que mantém os soquetes do servidor abertos entre reinicializações. Isso garante que nenhuma solicitação pendente seja descartada enquanto a reinicialização estiver ocorrendo.
Para obter mais informações, consulte a documentação sobre reinicialização.
Puma responde a vários sinais. Um guia detalhado para usar sinais UNIX com Puma pode ser encontrado na documentação de Sinais.
Algumas plataformas não suportam todos os recursos do Puma.
Para as versões 2.2.7, 2.2.8, 2.2.9, 2.2.10, 2.3.4 e 2.4.1 do MRI, você poderá ver stream closed in another thread (IOError)
. Pode ser causado por um bug do Ruby. Isso pode ser corrigido com a gema https://rubygems.org/gems/stopgap_13632:
if %w( 2.2.7 2.2.8 2.2.9 2.2.10 2.3.4 2.4.1 ) . include? RUBY_VERSION
begin
require 'stopgap_13632'
rescue LoadError
end
end
A Puma tem suporte para Capistrano com uma joia externa.
Além disso, o Puma tem suporte para daemonização integrada por meio da gema ruby puma-daemon. A gem restaura a opção daemonize
que foi removida do Puma a partir da versão 5, mas apenas para MRI Ruby.
É comum usar monitores de processo com o Puma. Monitores de processos modernos como systemd ou rc.d fornecem monitoramento contínuo e reinicializações para maior confiabilidade em ambientes de produção:
Guias da comunidade:
Encontre detalhes para contribuir no guia de contribuições.
Puma é propriedade de Evan Phoenix e colaboradores, licenciado sob a licença BSD 3-Clause. Consulte o arquivo LICENSE incluído para obter detalhes.