Puma est un serveur HTTP 1.1 simple, rapide, multithread et hautement parallèle pour les applications Ruby/Rack .
Puma est un serveur pour les applications HTTP rackables écrites en Ruby. C'est:
Conçu à l'origine comme serveur pour Rubinius, Puma fonctionne également bien avec Ruby (MRI) et JRuby.
Sur MRI, il existe un Global VM Lock (GVL) qui garantit qu'un seul thread peut exécuter du code Ruby à la fois. Mais si vous bloquez beaucoup les IO (comme les appels HTTP vers des API externes comme Twitter), Puma améliore toujours le débit de l'IRM en permettant aux IO d'attendre en parallèle. Les implémentations Ruby véritablement parallèles (TruffleRuby, JRuby) n'ont pas cette limitation.
$ gem install puma
$ puma
Sans arguments, puma recherchera un fichier rackup (.ru) dans le répertoire de travail appelé config.ru
.
Puma installera/compilera avec la prise en charge des sockets SSL, en supposant que les fichiers de développement OpenSSL soient installés sur le système.
Si le système n'a pas de fichiers de développement OpenSSL installés, Puma installera/compilera, mais il n'autorisera pas les connexions SSL.
Puma est le serveur par défaut pour Rails, inclus dans le Gemfile généré.
Démarrez votre serveur avec la commande rails
:
$ rails server
De nombreuses options de configuration et fonctionnalités Puma ne sont pas disponibles lors de l'utilisation rails server
. Il est recommandé d'utiliser plutôt l'exécutable de Puma :
$ bundle exec puma
Vous pouvez exécuter votre application Sinatra avec Puma à partir de la ligne de commande comme ceci :
$ ruby app.rb -s Puma
Cependant, afin de configurer réellement Puma à l'aide d'un fichier de configuration, comme puma.rb
, vous devez utiliser l'exécutable puma
. Pour ce faire, vous devez ajouter un fichier rackup à votre application Sinatra :
# config.ru
require './app'
run Sinatra :: Application
Vous pouvez ensuite démarrer votre application en utilisant :
$ bundle exec puma
Puma propose de nombreuses options. Consultez puma -h
(ou puma --help
) pour une liste complète des options CLI, ou consultez Puma::DSL
ou dsl.rb.
Vous pouvez également trouver plusieurs exemples de configuration dans le cadre de la suite de tests.
À des fins de débogage, vous pouvez définir la variable d'environnement PUMA_LOG_CONFIG
avec une valeur et la configuration chargée sera imprimée dans le cadre du processus de démarrage.
Puma utilise un pool de threads. Vous pouvez définir le nombre minimum et maximum de threads disponibles dans le pool avec l'indicateur -t
(ou --threads
) :
$ puma -t 8:32
Puma adaptera automatiquement le nombre de threads, du minimum jusqu'au maximum, en fonction de la quantité de trafic présent. La valeur par défaut actuelle est 0:16
et en IRM, elle est 0:5
. N'hésitez pas à expérimenter, mais veillez à ne pas définir le nombre maximum de threads sur un nombre élevé, car vous pourriez épuiser les ressources du système (ou provoquer un conflit pour le verrouillage global de la VM, lors de l'utilisation de l'IRM).
Sachez qu'en outre Puma crée lui-même des threads à des fins internes (par exemple pour gérer les clients lents). Ainsi, même si vous spécifiez -t 1:1, attendez-vous à environ 7 threads créés dans votre application.
Puma propose également un « mode cluster ». Le mode cluster fork
les travailleurs d'un processus maître. Chaque processus enfant possède toujours son propre pool de threads. Vous pouvez régler le nombre de travailleurs avec l'indicateur -w
(ou --workers
) :
$ puma -t 8:32 -w 3
Ou avec la variable d'environnement WEB_CONCURRENCY
:
$ WEB_CONCURRENCY=3 puma -t 8:32
Notez que les threads sont toujours utilisés en mode cluster et que le paramètre -t
thread flag est par travailleur, donc -w 2 -t 16:16
générera 32 threads au total, avec 16 dans chaque processus de travail.
Si la variable d'environnement WEB_CONCURRENCY
est définie sur "auto"
et que la gem concurrent-ruby
est disponible dans votre application, Puma définira le nombre de processus de travail sur le résultat des processeurs disponibles.
Pour une discussion approfondie sur les compromis entre les paramètres du nombre de threads et de processus, consultez nos documents.
En mode cluster, Puma peut « précharger » votre application. Cela charge tout le code de l’application avant le fork. Le préchargement réduit l'utilisation totale de la mémoire de votre application via une fonctionnalité du système d'exploitation appelée copie sur écriture.
Si la variable d'environnement WEB_CONCURRENCY
est définie sur une valeur > 1 (et que --prune-bundler
n'a pas été spécifié), le préchargement sera activé par défaut. Sinon, vous pouvez utiliser l'indicateur --preload
depuis la ligne de commande :
$ puma -w 3 --preload
Ou, si vous utilisez un fichier de configuration, vous pouvez utiliser preload_app!
méthode:
# config/puma.rb
workers 3
preload_app!
Le préchargement ne peut pas être utilisé avec un redémarrage progressif, car le redémarrage progressif tue et redémarre les travailleurs un par un, et le préchargement copie le code du maître dans les travailleurs.
Lors de l'utilisation du mode cluster, la configuration DSL de Puma fournit des hooks before_fork
et on_worker_boot
pour exécuter du code lorsque les forks du processus maître et les travailleurs enfants sont respectivement démarrés.
Il est recommandé d'utiliser ces hooks avec preload_app!
, sinon les constantes chargées par votre application (telles que Rails
) ne seront pas disponibles à l'intérieur des hooks.
# 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
De plus, il existe un hook on_refork
qui est utilisé uniquement en mode fork_worker
, lorsque le processus enfant Worker 0 forke un Worker petit-enfant :
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
Il est important de noter les considérations suivantes lorsque Ruby lance un processus enfant :
SocketError
, Errno::EPIPE
et EOFError
.Par conséquent, nous recommandons ce qui suit :
before_fork
et on_refork
pour déconnecter les connexions socket du parent lors du forking, afin qu'elles ne soient pas accidentellement copiées dans le processus enfant.on_worker_boot
pour redémarrer tous les threads d'arrière-plan sur l'enfant forké. Le DSL de configuration de Puma fournit des hooks de cycle de vie de processus maître on_booted
, on_restart
et on_stopped
qui peuvent être utilisés pour spécifier des blocs de code à exécuter sur chaque événement :
# 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
Si Puma rencontre une erreur en dehors du contexte de votre application, il répondra par un 400/500 et un simple message d'erreur textuel (voir Puma::Server#lowlevel_error
ou server.rb). Vous pouvez spécifier un comportement personnalisé pour ce scénario. Par exemple, vous pouvez signaler l'erreur à votre service de suivi des erreurs tiers (dans cet exemple, 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
Liez Puma à un socket avec l'indicateur -b
(ou --bind
) :
$ puma -b tcp://127.0.0.1:9292
Pour utiliser un socket UNIX au lieu de TCP :
$ puma -b unix:///var/run/puma.sock
Si vous devez modifier les autorisations du socket UNIX, ajoutez simplement un paramètre umask :
$ puma -b 'unix:///var/run/puma.sock?umask=0111'
Besoin d'un peu de sécurité ? Utilisez des sockets SSL :
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert'
localhost
, à des fins de développement) : Puma prend en charge la gemme localhost
pour les certificats auto-signés. Ceci est particulièrement utile si vous souhaitez utiliser Puma avec SSL localement, et les certificats auto-signés fonctionneront pour votre cas d'utilisation. Actuellement, l’intégration ne peut être utilisée qu’en IRM.
Puma configure automatiquement SSL lorsque la gem localhost
est chargée dans un environnement development
:
Ajoutez la gemme à votre Gemfile :
group ( :development ) do
gem 'localhost'
end
Et exigez-le implicitement en utilisant bundler :
require "bundler"
Bundler . require ( :default , ENV [ "RACK_ENV" ] . to_sym )
Alternativement, vous pouvez exiger la gemme dans votre fichier de configuration, soit config/puma/development.rb
, config/puma.rb
, ou définie via l'option -C
cli :
require 'localhost'
# configuration methods (from Puma::DSL) as needed
De plus, Puma doit écouter un socket 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
Pour utiliser ou éviter des chiffrements SSL spécifiques pour TLSv1.2 et versions antérieures, utilisez les options 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'
Pour configurer les suites de chiffrement TLSv1.3 disponibles, utilisez l'option ssl_ciphersuites
(non disponible pour 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'
Voir https://www.openssl.org/docs/man1.1.1/man1/ciphers.html pour le format de filtre de chiffrement et la liste complète des suites de chiffrement.
Désactivez TLS v1 avec l'option no_tlsv1
:
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&no_tlsv1=true'
Pour activer les indicateurs de vérification proposés par OpenSSL, utilisez verification_flags
(non disponible pour JRuby) :
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&verification_flags=PARTIAL_CHAIN'
Vous pouvez également définir plusieurs indicateurs de vérification (en les séparant par une virgule) :
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&verification_flags=PARTIAL_CHAIN,CRL_CHECK'
Liste des indicateurs disponibles : 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
(voir https://www.openssl.org/docs/manmaster/man3/X509_VERIFY_PARAM_set_hostflags.html#VERIFICATION-FLAGS).
Pour activer le déchiffrement à l'exécution d'une clé SSL chiffrée (non disponible pour JRuby), utilisez 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
doit :
Par exemple:
#! /bin/sh
echo " this is my password "
key_password_command
peut être utilisé avec key
ou key_pem
. Si la clé n'est pas chiffrée, l'exécutable ne sera pas appelé.
Puma dispose d'une application d'état et de contrôle intégrée qui peut être utilisée pour interroger et contrôler Puma.
$ puma --control-url tcp://127.0.0.1:9293 --control-token foo
Puma démarrera le serveur de contrôle sur le port localhost 9293. Toutes les requêtes adressées au serveur de contrôle devront inclure un jeton de contrôle (dans ce cas, token=foo
) comme paramètre de requête. Cela permet une authentification simple. Consultez Puma::App::Status
ou status.rb pour voir ce que l'application de statut est disponible.
Vous pouvez également interagir avec le serveur de contrôle via pumactl
. Cette commande redémarrera Puma :
$ pumactl --control-url 'tcp://127.0.0.1:9293' --control-token foo restart
Pour voir une liste des options pumactl
, utilisez pumactl --help
.
Vous pouvez également fournir un fichier de configuration avec l'indicateur -C
(ou --config
) :
$ puma -C /path/to/config
Si aucun fichier de configuration n'est spécifié, Puma recherchera un fichier de configuration dans config/puma.rb
. Si un environnement est spécifié (via l'indicateur --environment
ou via les variables d'environnement APP_ENV
, RACK_ENV
ou RAILS_ENV
), Puma recherche un fichier de configuration dans config/puma/<environment_name>.rb
puis revient à config/puma.rb
.
Si vous souhaitez empêcher Puma de rechercher un fichier de configuration à ces emplacements, incluez l'indicateur --no-config
:
$ puma --no-config
# or
$ puma -C "-"
Les autres effets secondaires de la configuration de l'environnement sont de savoir s'il faut afficher les traces de pile (en development
ou en test
), et la configuration de RACK_ENV peut potentiellement affecter le middleware recherchant cette valeur pour modifier son comportement. La valeur par défaut de puma RACK_ENV est development
. Vous pouvez voir toutes les valeurs de configuration par défaut dans Puma::Configuration#puma_default_options
ou configuration.rb.
Consultez Puma::DSL
ou dsl.rb pour voir toutes les options disponibles.
Puma inclut la possibilité de se redémarrer. Lorsqu'il est disponible (MRI, Rubinius, JRuby), Puma effectue un "hot restart". Il s'agit de la même fonctionnalité disponible dans Unicorn et NGINX qui maintient les sockets du serveur ouverts entre les redémarrages. Cela garantit qu'aucune demande en attente n'est abandonnée pendant le redémarrage.
Pour en savoir plus, consultez la documentation sur le redémarrage.
Puma répond à plusieurs signaux. Un guide détaillé sur l'utilisation des signaux UNIX avec Puma peut être trouvé dans la documentation Signals.
Certaines plateformes ne prennent pas en charge toutes les fonctionnalités de Puma.
Pour les versions MRI 2.2.7, 2.2.8, 2.2.9, 2.2.10, 2.3.4 et 2.4.1, vous pouvez voir stream closed in another thread (IOError)
. Cela peut être dû à un bug Ruby. Cela peut être corrigé avec la gemme 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
Puma prend en charge Capistrano avec une gemme externe.
De plus, Puma prend en charge la démonisation intégrée via la gemme ruby puma-daemon. La gemme restaure l'option daemonize
qui a été supprimée de Puma à partir de la version 5, mais uniquement pour MRI Ruby.
Il est courant d'utiliser des moniteurs de processus avec Puma. Les moniteurs de processus modernes comme systemd ou rc.d assurent une surveillance et des redémarrages continus pour une fiabilité accrue dans les environnements de production :
Guides communautaires :
Trouvez les détails pour contribuer dans le guide de contribution.
Puma est la propriété d'Evan Phoenix et de ses contributeurs, sous licence BSD 3-Clause. Voir le fichier LICENSE inclus pour plus de détails.