diff --git a/Gemfile b/Gemfile index a808f9a3872..d9c4c11dcdd 100644 --- a/Gemfile +++ b/Gemfile @@ -106,6 +106,7 @@ gem 'maxmind-db', '~> 1.0.0' gem 'mahoro', '~> 0.5' gem 'nokogiri', '~> 1.14.1' gem 'open4', '~> 1.3.0' +gem 'puma', '~> 6.0.2' gem 'rack', '~> 2.2.6' gem 'rack-utf8_sanitizer', '~> 1.8.0' gem 'recaptcha', '~> 5.12.3', require: 'recaptcha/rails' @@ -120,7 +121,6 @@ gem 'strip_attributes', :git => 'https://github.com/mysociety/strip_attributes.g gem 'stripe', '~> 5.55.0' gem 'syck', '~> 1.4.1', require: false gem 'syslog_protocol', '~> 0.9.0' -gem 'thin', '~> 1.8.1' gem 'vpim', '~> 13.11.11' gem 'will_paginate', '~> 3.3.1' gem 'xapian-full-alaveteli', '~> 1.4.21.1' diff --git a/Gemfile.lock b/Gemfile.lock index 97b2a05c40e..fbcf9f5900b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -174,7 +174,6 @@ GEM crack (0.4.5) rexml crass (1.0.6) - daemons (1.4.0) dalli (3.2.3) dante (0.2.0) date (3.3.3) @@ -184,7 +183,6 @@ GEM rake (>= 12.0.0, < 14.0.0) docile (1.4.0) erubi (1.12.0) - eventmachine (1.2.7) exception_notification (4.5.0) actionmailer (>= 5.2, < 8) activesupport (>= 5.2, < 8) @@ -358,6 +356,8 @@ GEM coderay (~> 1.1) method_source (~> 1.0) public_suffix (5.0.1) + puma (6.0.2) + nio4r (~> 2.0) racc (1.6.2) rack (2.2.6.2) rack-test (2.0.2) @@ -494,10 +494,6 @@ GEM syck (1.4.1) syslog_protocol (0.9.2) text (1.3.1) - thin (1.8.1) - daemons (~> 1.0, >= 1.0.9) - eventmachine (~> 1.0, >= 1.0.4) - rack (>= 1, < 3) thor (1.2.1) tilt (2.0.10) timeout (0.3.1) @@ -593,6 +589,7 @@ DEPENDENCIES open4 (~> 1.3.0) pg (~> 1.4.5) pry (~> 0.14.2) + puma (~> 6.0.2) rack (~> 2.2.6) rack-utf8_sanitizer (~> 1.8.0) rails (~> 7.0.4) @@ -618,7 +615,6 @@ DEPENDENCIES stripe-ruby-mock! syck (~> 1.4.1) syslog_protocol (~> 0.9.0) - thin (~> 1.8.1) uglifier (~> 4.2.0) unicode (~> 0.4.4) unidecoder (~> 1.1.0) diff --git a/bin/puma b/bin/puma new file mode 100755 index 00000000000..01a92a32422 --- /dev/null +++ b/bin/puma @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'puma' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("puma", "puma") diff --git a/bin/pumactl b/bin/pumactl new file mode 100755 index 00000000000..c93cff2107e --- /dev/null +++ b/bin/pumactl @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'pumactl' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("puma", "pumactl") diff --git a/bin/thin b/bin/thin deleted file mode 100755 index 80d4e141010..00000000000 --- a/bin/thin +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'thin' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('thin', 'thin') diff --git a/config/boot.rb b/config/boot.rb index e6a5f1c48da..5df8ee545d5 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,10 +1,4 @@ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) require "bundler/setup" # Set up gems listed in the Gemfile. - -# TODO: Remove this. This is a hacky system for having a default environment. -# It looks for a config/rails_env.rb file, and reads stuff from there if -# it exists. Put just a line like this in there: -# ENV['RAILS_ENV'] = 'production' -rails_env_file = File.expand_path(File.join(File.dirname(__FILE__), 'rails_env.rb')) -require rails_env_file if File.exist?(rails_env_file) +require File.expand_path('load_env.rb', __dir__) diff --git a/config/load_env.rb b/config/load_env.rb new file mode 100644 index 00000000000..3b257efd3af --- /dev/null +++ b/config/load_env.rb @@ -0,0 +1,7 @@ +# TODO: Remove this. This is a hacky system for having a default environment. +# It looks for a config/rails_env.rb file, and reads stuff from there if +# it exists. Put just a line like this in there: +# ENV['RAILS_ENV'] = 'production' + +rails_env_file = File.expand_path('rails_env.rb', __dir__) +require rails_env_file if File.exist?(rails_env_file) diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 00000000000..452301a592a --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,41 @@ +require File.expand_path('load_env.rb', __dir__) + +# This configuration file will be evaluated by Puma. The top-level methods that +# are invoked here are part of Puma's configuration DSL. For more information +# about methods provided by the DSL, see https://puma.io/puma/Puma/DSL.html. + +# Puma can serve each request in a thread from an internal thread pool. +# The `threads` method setting takes two numbers: a minimum and maximum. +# Any libraries that use thread pools should be configured to match +# the maximum value specified for Puma. Default is set to 5 threads for minimum +# and maximum; this matches the default thread size of Active Record. +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +# Specifies that the worker count should equal the number of processors in +# production. +if ENV["RAILS_ENV"] == "production" + concurrency = ENV.fetch("WEB_CONCURRENCY") do + Concurrent.physical_processor_count + end + worker_count = Integer(concurrency) + workers worker_count if worker_count > 1 +end + +# Specifies the `worker_timeout` threshold that Puma will use to wait before +# terminating a worker in development environments. +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +# Specifies the `port` that Puma will listen on to receive requests; default is +# 3000. +port ENV.fetch("PORT") { 3000 } + +# Specifies the `environment` that Puma will run in. +environment ENV.fetch("RAILS_ENV") { "development" } + +# Specifies the `pidfile` that Puma will use. +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# Allow puma to be restarted by `bin/rails restart` command. +plugin :tmp_restart diff --git a/config/sysvinit-thin.example b/config/sysvinit-puma.example similarity index 95% rename from config/sysvinit-thin.example rename to config/sysvinit-puma.example index 987f3ac233a..b3539598500 100755 --- a/config/sysvinit-thin.example +++ b/config/sysvinit-puma.example @@ -1,7 +1,7 @@ #! /bin/sh # ### BEGIN INIT INFO -# Provides: application-thin-<%= site %> +# Provides: application-puma-<%= site %> # Required-Start: $local_fs $network # Required-Stop: $local_fs $network # Default-Start: 2 3 4 5 @@ -23,7 +23,7 @@ CPUS=<%= cpus %> # RAILS_ENV=<%= rails_env %> # export RAILS_ENV -CMD="bundle exec thin" +CMD="bundle exec puma -C config/puma.rb" <% if use_rbenv? %> RBENV_ROOT="/home/<%= user %>/.rbenv" diff --git a/script/site-specific-install.sh b/script/site-specific-install.sh index 9a456170900..9c0a49e793d 100755 --- a/script/site-specific-install.sh +++ b/script/site-specific-install.sh @@ -287,7 +287,7 @@ echo $DONE_MSG if [ ! "$DEVELOPMENT_INSTALL" = true ]; then echo -n "Creating /etc/init.d/$SITE... " - (su -l -c "cd '$REPOSITORY' && bundle exec rake config_files:convert_init_script DEPLOY_USER='$UNIX_USER' VHOST_DIR='$DIRECTORY' VCSPATH='$SITE' SITE='$SITE' RUBY_VERSION='$RUBY_VERSION' USE_RBENV=$USE_RBENV RAILS_ENV='$RAILS_ENV' SCRIPT_FILE=config/sysvinit-thin.example" "$UNIX_USER") > /etc/init.d/"$SITE" + (su -l -c "cd '$REPOSITORY' && bundle exec rake config_files:convert_init_script DEPLOY_USER='$UNIX_USER' VHOST_DIR='$DIRECTORY' VCSPATH='$SITE' SITE='$SITE' RUBY_VERSION='$RUBY_VERSION' USE_RBENV=$USE_RBENV RAILS_ENV='$RAILS_ENV' SCRIPT_FILE=config/sysvinit-puma.example" "$UNIX_USER") > /etc/init.d/"$SITE" chgrp "$UNIX_USER" /etc/init.d/"$SITE" chmod 754 /etc/init.d/"$SITE" echo $DONE_MSG