Назад | Перейти на главную страницу

Puma с активацией systemd и сокетом - Errno :: EADDRINUSE

У меня есть приложение Rails 5, работающее на puma 3.12.1, MRI 2.6.2 и Ubuntu 18.04. Раньше он работал с pumactl и настраиваемый сценарий управления, но я хочу правильно настроить его с помощью systemd, используя активацию сокета для развертывания с нулевым временем простоя.

Проблема в том, что сокет содержит порт, и puma хочет привязаться к тому же порту, поэтому выдает эту ошибку:

/opt/myapp/shared/vendor/ruby/2.6.0/gems/puma-3.12.1/lib/puma/binder.rb:273:in `initialize': 
Address already in use - bind(2) for "0.0.0.0" port 3000 (Errno::EADDRINUSE)

Я все настроил согласно puma docs и системные документы.

Я, конечно, перезагрузил конфигурацию systemd и несколько раз пытался перезапустить. Я не очень понимаю, как systemd выполняет эту активацию сокета, но для меня сообщение об ошибке puma кажется разумным: /

Может пума не стоит пытаться привязаться к этому порту? Но как я могу связаться с puma, чтобы не привязываться к ней, а использовать перенаправленный поток systemd?

Моя конфигурация:

$ cat /etc/systemd/system/puma.socket
[Unit]
Description=Puma HTTP Server Accept Sockets

[Socket]
ListenStream=0.0.0.0:3000

# Socket options matching Puma defaults
NoDelay=true
ReusePort=true
Backlog=1024

[Install]
WantedBy=sockets.target
$ cat /etc/systemd/system/puma.service
[Unit]
Description=API with Puma server
After=network.target
Requires=puma.socket

[Service]
Type=simple
WorkingDirectory=/opt/myapp/current
ExecStart=/opt/myapp/current/script/bootup_puma
SyslogIdentifier=api-puma
PIDFile=/opt/myapp/current/tmp/pids/puma.pid
Restart=no
TimeoutSec=30
User=ubuntu

[Install]
WantedBy=multi-user.target
$ cat script/bootup_puma
#!/bin/bash

# [setting up some envvars here]

bundle exec puma -C config/puma.rb
$ cat config/puma.rb
# frozen_string_literal: true

app_dir = File.expand_path("..", __dir__)

workers ENV.fetch("API__PUMA_WORKERS", 4).to_i
threads 1, ENV.fetch("RAILS_MAX_THREADS", 8).to_i

bind "tcp://0.0.0.0:#{ENV.fetch('PORT', 3000)}"

pidfile "#{app_dir}/tmp/pids/puma.pid"

directory ENV.fetch("API__PUMA_DIRECTORY") unless ENV.fetch("RAILS_ENV", "development") == "development"

В качестве отчаянной попытки я также попытался использовать сокет unix вместо TCP, но это закончилось аналогичной ошибкой, несмотря на то, что я старался не ссылаться на сокет через символическую ссылку.

/opt/myapp/shared/vendor/ruby/2.6.0/gems/puma-3.12.1/lib/puma/binder.rb:367:in `add_unix_listener': 
There is already a server bound to: /opt/myapp/shared/tmp/puma.sock (RuntimeError)

Другие полезные ресурсы, которые я уже просмотрел:

Проблема заключалась в промежуточном сценарии оболочки bootup_puma как указал Майкл Хэмптон в Комментарии.

Смена службы на ExecStart=/opt/myapp/current/bin/puma -C config/puma.rb и обеспечение окружающей среды EnvironmentFile директивы решили проблему.