【问题标题】:How to reload the mojolicious built-in webserver daemon?如何重新加载 mojolicious 内置的网络服务器守护进程?
【发布时间】:2012-06-21 15:04:42
【问题描述】:

我从lighttpd-package 复制了这个systemd service 文件,并对其进行了修改,以使systemd 启动mojolicious 内置服务器守护进程。 我可以保留 mojolicious 守护进程的 ExecReloadKillSignal 设置吗?

[Unit]
Description=Start mojolicious.pl daemon
After=syslog.target network.target

[Service]
ExecStart=/path/to/mojolicious.pl daemon --listen "http://*:3001"
ExecReload=/bin/kill -HUP $MAINPID
KillSignal=SIGINT

[Install]
WantedBy=multi-user.target

【问题讨论】:

    标签: perl mojolicious systemd


    【解决方案1】:

    我认为亚历克斯说它自动重新加载时正在考虑morbo。对于生产,您最好使用hypnotoad。如果您确实切换到hypnotoad,那么会有各种有用的信号。例如/bin/kill -USR2 $MAINPID 将进行优雅的重新加载,避免对任何当前连接造成干扰。更多信号(用于催眠蟾蜍)见http://mojolicio.us/perldoc/Mojo/Server/Hypnotoad#SIGNALS

    【讨论】:

    • 请先阅读@RussellEGlaue 的answer(我认为这应该是公认的),然后再继续。
    【解决方案2】:

    我不知道您为什么需要“重新加载”,Mojolicious 会在应用程序代码更改时执行内部重新加载。您可以将其替换为

    /bin/kill -0 $MAINPID
    

    如果该行应该在那里,HUP 将是正常应用程序的终端(除非您以不同方式处理它)

    【讨论】:

      【解决方案3】:

      systemd reload 和 hypnotoad reload 需要一个包装脚本才能正常工作

      注意:此解决方法适用于 Mojolicious 6.x。在 Mojolicious 7.x 中修复了 SystemD 兼容性

      如果您想在 systemd 下重新加载,那么标准的 hypnotoad 重新加载(即hypnotoad myapp.pl)或kill -USR $MAINPID 是不可取的。 SystemD 假设一旦重新加载 hypnotoad 服务器的命令返回,重新加载就完成了。但是,相反,这两个选项都会立即退出,并且不要等待重新加载完成。

      当我尝试了这些标准的重新加载选项后,systemd 完成了重新加载命令的执行,然后,当 hypnotoad 执行“开始零停机时间软件升级 > 升级成功”时,监视 pid 文件被删除和替换。

      如果您已将 systemd 配置为始终运行 hypnotoad 应用程序,则 systemd 将在 hypnotoad 正常运行之后再次重新启动(停止并启动)应用程序。

      会发生什么:

      • systemd 重新加载 hypnotoad-app (ExecReload=hypnotoad myapp.pl)
      • hypnotoad-app 在被告知重新加载后退出
      • hypnotoad 使用最新的 myapp.pl 启动一个新进程
      • systemd 认为重新加载刚刚完成,并且看到 PIDFile 中的 pid 没有改变
      • hypnotoad 看到旧进程没有负载,杀死它们,并在“升级[is]成功”时删除并使用新进程的 PID 创建一个新的 PIDFile(这是 hypnotoad 的“零停机时间”重新加载过程)
      • systemd 看到 pid 文件被删除(它忽略它是重新创建的,可能是因为 systemd 在设计上希望控制分叉)
      • systemd 等待 HOLDOFF (RestartSec=<seconds>)(如果已配置)
      • systemd 对 hypnotoad-app 进行完整的单元启动

      systemd 文档特别指出,当ExecReload= 命令返回时,systemd 期望进程已经完成重新加载,并且 pid 文件具有重新加载进程的新 PID。但是 Hypnotoad 不能像那样同步工作。所以 systemd 和 hypnotoad 不能很好地协同工作。

      https://www.freedesktop.org/software/systemd/man/systemd.service.html

      但是请注意,通过发送信号来重新加载守护进程(与 上面的示例行)通常不是一个好的选择,因为这是一个 异步操作,因此不适合订购重新加载 多个服务相互对抗。强烈建议 将 ExecReload= 设置为不仅会触发配置的命令 重新加载守护进程,但也会同步等待它完成。

      解决方案是围绕重新加载过程编写一个包装器。

      #!/bin/bash
      
      SERVER="/path/to/myapp.pl"
      HYPNOTOAD="/usr/bin/hypnotoad"
      PIDFILE="/var/run/myapp.pid"
      
      # Timeout == LOOPSAFE x SLEEPTIME
      SLEEPTIME="0.5"
      LOOPSAFE=20
      LOOPCOUNT=0
      #
      
      if [ ! -f "${PIDFILE}" ]; then
        # The PID files does not exist, maybe $SERVER is not running
        exit 1
      fi
      
      OLDPID=$(cat ${PIDFILE})
      NEWPID=$OLDPID
      
      # Reload the application
      ${HYPNOTOAD} ${SERVER}
      
      while (( $LOOPCOUNT <= $LOOPSAFE )); do
        let LOOPCOUNT++
        if [ -f ${PIDFILE} ]; then
          NEWPID=$(cat ${PIDFILE})
          if (( $NEWPID > 1 )) && (( $NEWPID != $OLDPID )); then
            exit 0
          fi
        fi
        sleep ${SLEEPTIME}
      done
      
      exit 1
      

      这是 Hypnotoad 所需的 systemd 单元文件

      [Unit]
      Description=Hypnotoad-app
      Requires=network.target
      After=network.target
      
      [Service]
      Type=simple
      SyslogIdentifier=hypnotoad-app
      PIDFile=/var/run/myapp.pid
      EnvironmentFile=-/etc/sysconfig/myapp
      ExecStart=/usr/bin/hypnotoad --foreground /path/to/myapp.pl
      ExecStop=/usr/bin/hypnotoad --stop /path/to/myapp.pl
      ExecReload=/path/to/reload-myapp.sh
      KillMode=process
      Restart=always
      RestartSec=5
      User=myuser
      Group=mygroup
      
      [Install]
      WantedBy=multi-user.target
      

      这是重新加载过程现在的工作方式

      • systemd 重新加载 hypnotoad-app
      • systemd 执行重新加载脚本
      • reload 脚本重新加载 hypnotoad-app,并等待“成功升级” - 实质上是休眠,直到 PID 文件具有新重新加载的 myapp.pl 进程的 PID
      • systemd 现在使用新的 PID 监视 pid 文件,该 PID 不再更改 - 所以现在 systemd 不会尝试重新启动它

      【讨论】:

      • 我向 hypnotoad github.com/kraih/mojo/issues/1130 提交了 --reload-wait 选项的错误/功能请求
      • 在此处转发该问题的解决方案。这个问题大约在文档开始建议 systemd 的同时被注意到,并且很快得到解决。此答案的发布者使用的是不包含修复的过时版本(版本 7.01 及更高版本应该可以工作)。
      • 我在 CentOS 7 上使用 Mojolicious 6.31。将 Mojolicious 升级到 7.45,并将 IO::Socket::IP 升级到 >= 0.37(0.37+ 不适用于 CentOS 7 的 RPM)系统。
      【解决方案4】:

      另一种选择是使用-f 在前台运行hypnotoad 并使用runit 和一个简单的/etc/sv/myapp/run 脚本使用服务监督:

      #!/bin/sh
      
      app=/path/to/my/app
      daemon=/path/to/hypnotoad
      
      exec 2>&1
      exec $daemon -f $app
      

      然后您可以让hypnotoad 使用sv hup myapp 重新读取它的配置

      Red Hat 不提供runit,但最新版本的rpm 可以是built from here

      别忘了ln -s /etc/sv/myapp /etc/service/myapprunit启用服务。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-12-16
        • 1970-01-01
        • 1970-01-01
        • 2013-05-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-20
        相关资源
        最近更新 更多