在其他服务启动后启动时运行 PHP 脚本

在其他服务启动后启动时运行 PHP 脚本

为了将定期的天气更新导入到我的 Redis 数据库中,我尝试使用的方案如下

我有一个 PHP 脚本,可以从相关的天气 API 获取天气信息。它如下所示

<?php
 function getWeather()
 {
  if (weatherupdaterequired)
  {
   //weather API call
   //parse and store to database
  }
 }

 while (true)
 {
  getWeather();
  sleep(30);
 }
?>

它存储在我的/usr/local/bin文件夹中。在同一个文件夹中,我有一个 shell 脚本,runweather它的作用是:

#!/bin/sh
nohup php /usr/local/bin/echoweather.php  >/dev/null 2>&1 &

我通常倾向于使用#!/bin/bash,但在这种情况下,我发现只有在启动时运行(如下所示)才#!/bin/sh有效。我认为这与 bash shell 尚不可用有关。

然后我创建了一个符号链接到runweather

ln -s /usr/local/bin/runweather /etc/init.d/runweather

然后是另一个符号链接

ln -s /etc/init.d/runweather /etc/rc2.d/S99runweather

一些解释性说明

  1. /usr/local/bin/echoweather.php正在做所有实际工作。它以 30 秒为间隔运行,不工作时处于休眠状态
  2. 在每次终止运行之前,它会放置一个临时的 Redis 键$redis-setEx("weatherreport",29,$echoCount)`,我可以使用它来监控它的运行状况
  3. echoweather.php将启动时运行的shell 脚本放入中/usr/local/bin,然后将其符号链接到 中,/etc/init.d然后再将其符号链接到 中,这/etc/rc2.d可能看起来很复杂。我这样做是因为我发现,如果我将实际的 shell 脚本放入 中/etc/init.d,然后将其符号链接到 中,/etc/rc2.d它不会执行。

这个方案很有效。我重启了几次服务器,并通过 redis-cli 在 Redis 中echoweather.php查找weatherreport密钥来检查其运行状况 - 始终存在且正确。但是,在处理 Ubuntu 启动脚本方面,我是个业余爱好者。也许有更简单的方法可以做这些事情?如果有人能发表评论,我将不胜感激。

答案1

如果您没有运行 Ubuntu 的 EOL 版本,您的 init 系统已经基于 systemd,因此使用它是正确的选择。有些人可能会告诉您将其用于Type=idle您的服务单元,但请:(来自systemd 手册页):

请注意,使用除 simple 之外的任何其他类型都可能延迟启动过程,因为服务管理器需要等待服务初始化完成。因此建议不要不必要地使用除 simple 之外的任何其他类型。(另请注意,通常不建议对长时间运行的服务使用 idle 或 oneshot。)

考虑到这一点,我们应该通过设置目标和依赖关系来管理我们的服务排序。脚本要正常工作至少需要满足三个重要要求:

  1. 您的网络堆栈需要正常运行;
  2. 您的脚本应该在启动过程的后期运行,并且;
  3. 您的脚本应该在 Redis 完全启动后运行。

确定了这些要求后,让我们来看看systemd 目标所以我们知道我们想要什么,需要什么,应该依赖什么或等待什么:

  1. 严格需要配置网络连接的单元应该拉入network-online.target,因此我们的单元Wants这个并且应该只运行After这个目标;
  2. multi-user.target设置一个多用户系统,并在完成所有需要的操作后完成,因此单元可能Wants就是WantedBy这样。由于我们确实希望我们的单元在引导过程的后期运行,因此运行After这个目标也是我们想要的;
  3. Redis 是我们正在配置的多用户系统的一部分,并且我们的单元只有在 Redis 启动并运行时才能产生其预期的效果,因此RequiresRedis 必须运行,我们才应该加载After它。

考虑到这一点,我们可以将所有这些都考虑echoweather.service进去写入一个文件:/etc/systemd/system/

[Unit]
Description=Gets regular weather updates into my Redis database
Wants=network-online.target multi-user.target
Requires=redis-server.service
After=network-online.target multi-user.target redis-server.service

[Service]
PIDFile=/var/run/echoweather.pid
ExecStart=/usr/bin/php /usr/local/bin/echoweather.php  >/dev/null 2>&1 &
Type=forking
KillMode=process

[Install]
WantedBy=multi-user.target

完成后,重新加载守护程序文件,启用服务单元并运行进程:

$ sudo systemctl daemon-reload
$ sudo systemctl enable echoweather.service
$ sudo systemctl start echoweather.service

相关内容