Skip to content
This repository has been archived by the owner on Dec 31, 2022. It is now read-only.

Commit

Permalink
feat(appserver): move appserver processes to foreground
Browse files Browse the repository at this point in the history
Start puma, thin and unicorn processes in foreground and add proper
monit configurations for them. This is mainly done due to fact, that
puma removed daemonization completely for the gem, but also because
starting app servers in foreground is a "proper" way of doing this.

Option `app['appserver']['after_deploy']` becomes obsolete.

Fixes #244

BREAKING CHANGE: Theoretically everything should work out of the box,
and you shouldn't notice any change on your environment. However if your
appserver start behave oddly (or probably - won't start at all) - this
may be the first reason for that. Check generated monit files, check if
monit is running and also check the syslog (monit is configured to write
all the appserver output there).
  • Loading branch information
ajgon committed Dec 8, 2020
1 parent 8823930 commit 37b9465
Show file tree
Hide file tree
Showing 25 changed files with 296 additions and 408 deletions.
1 change: 0 additions & 1 deletion attributes/default.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@
default['defaults']['appserver']['preload_app'] = true
default['defaults']['appserver']['timeout'] = 60
default['defaults']['appserver']['worker_processes'] = 4
default['defaults']['appserver']['after_deploy'] = 'stop-start' # (restart|clean-restart)

## puma

Expand Down
14 changes: 0 additions & 14 deletions docs/source/attributes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -463,20 +463,6 @@ appserver
version provided by the Passenger APT PPA. Set this to a non-nil
value to lock your Passenger installation at a specific version.

- ``app['appserver']['after_deploy']``

- **Default:** ``stop-start``
- **Supported values:** ``stop-start``, ``restart``, ``clean-restart``
- Tell the appserver how to restart following a deployment. A ``stop-start``
will instruct the appserver to stop and then start immediately. This is
can cause requests from the webserver to be dropped since it closes the socket.
A ``restart`` sends a signal to the appserver instructing it to restart while
maintaining the open socket. Requests will hang while the app boots, but
will not be lost. A ``clean-restart`` will perform a ``stop-start`` if the
Gemfile has changed or a ``restart`` otherwise. The behavior of each of
these approaches varies between appservers. See their documentation for more
details.

- ``app['appserver']['port']``

- **Default:** None
Expand Down
71 changes: 30 additions & 41 deletions libraries/drivers_appserver_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,22 @@ module Appserver
class Base < Drivers::Base
include Drivers::Dsl::Notifies
include Drivers::Dsl::Output
include Drivers::Dsl::Packages

def setup
handle_packages
end

def configure
super
add_appserver_config
add_appserver_service_script
add_appserver_service_context
end

def before_deploy
setup_application_yml
setup_dot_env
end

def after_deploy
action = node['deploy'][app['shortname']].try(:[], 'appserver').try(:[], 'after_deploy') ||
node['defaults']['appserver']['after_deploy']
manual_action(action)
end
alias after_undeploy after_deploy

def validate_app_engine; end

def webserver_config_params
Expand All @@ -41,18 +37,36 @@ def appserver_config
raise NotImplementedError
end

private
def add_appserver_monit
opts = { app_shortname: app['shortname'], appserver_name: adapter, appserver_command: appserver_command,
deploy_to: deploy_dir(app), environment: environment }

def manual_action(action)
deploy_to = deploy_dir(app)
service_script = File.join(deploy_to, File.join('shared', 'scripts', "#{adapter}.service"))
file_path = File.join(node['monit']['basedir'], "#{opts[:appserver_name]}_#{opts[:app_shortname]}.monitrc")
context.template file_path do
mode '0640'
source 'appserver.monitrc.erb'
variables opts
end

context.execute 'monit reload'
end

def restart_monit
return if ENV['TEST_KITCHEN'] # Don't like it, but we can't run multiple processes in Docker on travis

context.execute "monit restart #{adapter}_#{app['shortname']}" do
retries 3
end
end

context.execute "#{action} #{adapter}" do
command "#{service_script} #{action}"
live_stream true
def unmonitor_monit
context.execute "monit unmonitor #{adapter}_#{app['shortname']}" do
retries 3
end
end

private

def add_appserver_config
opts = { deploy_dir: deploy_dir(app), out: out, deploy_env: deploy_env,
webserver: Drivers::Webserver::Factory.build(context, app).adapter,
Expand All @@ -67,31 +81,6 @@ def add_appserver_config
end
end

def add_appserver_service_script
opts = { deploy_dir: deploy_dir(app), app_shortname: app['shortname'], name: adapter, environment: environment,
command: appserver_command, deploy_env: deploy_env }

context.template File.join(opts[:deploy_dir], File.join('shared', 'scripts', "#{opts[:name]}.service")) do
owner node['deployer']['user']
group www_group
mode '0755'
source 'appserver.service.erb'
variables opts
end
end

def add_appserver_service_context
deploy_to = deploy_dir(app)
name = adapter

context.service "#{name}_#{app['shortname']}" do
start_command "#{deploy_to}/shared/scripts/#{name}.service start"
stop_command "#{deploy_to}/shared/scripts/#{name}.service stop"
restart_command "#{deploy_to}/shared/scripts/#{name}.service restart"
status_command "#{deploy_to}/shared/scripts/#{name}.service status"
end
end

def setup_application_yml
return unless raw_out[:application_yml]

Expand Down
8 changes: 1 addition & 7 deletions libraries/drivers_appserver_passenger.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,11 @@ class Passenger < Drivers::Appserver::Base
].freeze
output filter: WEBSERVER_CONFIG_PARAMS

def manual_action(action); end

def add_appserver_config; end

def add_appserver_service_script; end

def add_appserver_service_context; end

def webserver_config_params
o = out
Hash[WEBSERVER_CONFIG_PARAMS.map { |k| [k, o[k]] }].reject { |_k, v| v.nil? }
Hash[WEBSERVER_CONFIG_PARAMS.map { |k| [k, o[k]] }].reject { |_k, v| v.nil? } # rubocop:disable Style/CollectionCompact
end
end
end
Expand Down
22 changes: 21 additions & 1 deletion libraries/drivers_appserver_puma.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,33 @@ class Puma < Drivers::Appserver::Base
output filter: %i[log_requests preload_app thread_max thread_min timeout
on_restart worker_processes before_fork on_worker_boot on_worker_shutdown
on_worker_fork after_worker_fork after_deploy port]
packages 'monit'

def configure
super
add_appserver_monit
end

def after_deploy
super
restart_monit
end

def after_undeploy
super
restart_monit
end

def shutdown
unmonitor_monit
end

def appserver_config
'puma.rb'
end

def appserver_command
'puma -C #{ROOT_PATH}/shared/config/puma.rb' # rubocop:disable Lint/InterpolationCheck
"bundle exec puma -C #{deploy_dir(app)}/shared/config/puma.rb"
end
end
end
Expand Down
26 changes: 25 additions & 1 deletion libraries/drivers_appserver_thin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,37 @@ class Thin < Drivers::Appserver::Base
allowed_engines :thin
output filter: %i[max_connections max_persistent_connections timeout worker_processes
port]
packages 'monit'

def configure
super
add_appserver_monit
end

def after_deploy
super
restart_monit
end

def after_undeploy
super
restart_monit
end

def shutdown
unmonitor_monit
end

def appserver_config
'thin.yml'
end

def appserver_command
'thin -C #{ROOT_PATH}/shared/config/thin.yml' # rubocop:disable Lint/InterpolationCheck
"bundle exec thin -C #{deploy_dir(app)}/shared/config/thin.yml start"
end

def webserver_config_params
{ worker_processes: out[:worker_processes] }
end
end
end
Expand Down
24 changes: 21 additions & 3 deletions libraries/drivers_appserver_unicorn.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,33 @@ class Unicorn < Drivers::Appserver::Base
backlog delay preload_app tcp_nodelay tcp_nopush tries timeout worker_processes
port
]
packages 'monit'

def configure
super
add_appserver_monit
end

def after_deploy
super
restart_monit
end

def after_undeploy
super
restart_monit
end

def shutdown
unmonitor_monit
end

def appserver_config
'unicorn.conf'
end

def appserver_command
# rubocop:disable Lint/InterpolationCheck
'unicorn_rails --env #{DEPLOY_ENV} --daemonize -c #{ROOT_PATH}/shared/config/unicorn.conf'
# rubocop:enable Lint/InterpolationCheck
"bundle exec unicorn_rails --env #{deploy_env} -c #{deploy_dir(app)}/shared/config/unicorn.conf"
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion libraries/drivers_webserver_apache2.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def setup
def configure
define_service
add_ssl_directory
%i[private_key certificate chain].each(&method(:add_ssl_item))
%i[private_key certificate chain].each { |item| add_ssl_item(item) }
add_dhparams

remove_defaults
Expand Down
2 changes: 1 addition & 1 deletion metadata.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
depends 'chef_client_updater', '~> 3.6.0' # 3.7 introduces breaking change
depends 'logrotate', '2.2.1' # 2.2.2 breaks tests for whatever reason
depends 'nginx', '< 9.0'
depends 'nodejs'
depends 'nodejs', '< 7.0'
depends 'ohai', '< 5.3'
depends 'ruby-ng'
depends 's3_file'
Expand Down
3 changes: 1 addition & 2 deletions spec/fixtures/node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@
},
appserver: {
adapter: 'unicorn',
worker_processes: 8,
after_deploy: 'stop-start'
worker_processes: 8
},
webserver: {
adapter: 'nginx',
Expand Down
2 changes: 1 addition & 1 deletion spec/unit/libraries/drivers_appserver_puma_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@
end

it 'returns proper out data' do
expect(driver.out).to eq(worker_processes: 8, thread_min: 0, thread_max: 16, after_deploy: 'stop-start')
expect(driver.out).to eq(worker_processes: 8, thread_min: 0, thread_max: 16)
end
end
Loading

0 comments on commit 37b9465

Please sign in to comment.