免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1942 | 回复: 1

CentOS 下管理自定义 PHP 计划任务代码的守护进程脚本 [复制链接]

论坛徽章:
0
发表于 2012-02-17 23:42 |显示全部楼层

CentOS 下管理自定义 PHP 计划任务代码的守护进程脚本







from http://micate.me/centos-php-crontab-script-manage-shell.note
« javascript dialog 对话框的问题总结MySQL的表分区 »CentOS 下管理自定义 PHP 计划任务代码的守护进程脚本
Version: 2011-12-05   Print Published at 02:45 in 技术. 2 Comments
Tags: centos, php, 计划任务.
有需求想实现比 crontab 更频繁一点的计划任务,折腾一通之后,写下这个脚本,目前在 CentOS 6 下测试没有问题:

ChangeLog
2011.12.05
添加 PHP 执行用户设置,用以适应如在计划任务中执行生成文件操作时的文件权限问题,未完成;
2011.12.02
建立文档;
Shell 代码
  1. #!/bin/bash
  2. #
  3. # chkconfig: 35 90 12
  4. # description: Queue Daemon
  5. #

  6. # Get function from functions library
  7. . /etc/init.d/functions

  8. # PHP 访问路径,如果 PHP 是编译安装则需要修改
  9. php_path="/usr/bin/php"

  10. # PHP 执行用户名
  11. # Nginx 环境下常见为 nginx 或 www,
  12. # Apapche 环境下常见为 php 或 apache
  13. # 用在某些时候需要在计划任务中生成文件时文件权限不正确的问题
  14. php_user=nginx

  15. # 要管理的 PHP 计划任务脚本
  16. # 该目录下必须都是 PHP 可执行代码文件
  17. queue_path="/www/micate.dev/crontab/"

  18. # PHP 计划任务执行日志保存路径
  19. # 默认以 脚本名.log 的方式存储
  20. log_path="/var/log/queue/"

  21. # 守护进程 PID 路径
  22. pid_path="/var/run/queued.pid"

  23. # 守护进程在启动退出时的提示名称
  24. prog="Queued"

  25. # Start the service
  26. start() {
  27. echo -n $"Starting $prog: "

  28. if [ -f $pid_path ]; then
  29. echo -n "pid "$pid_path" exists."
  30. failure
  31. echo
  32. return 0
  33. fi

  34. if [ ! -d $log_path ]; then
  35. mkdir -p $log_path
  36. fi

  37. queues=$(ls $queue_path)
  38. for queue in $queues
  39. do
  40. # TODO sudo -u $php_user
  41. nohup $php_path $queue_path$queue 1>>$log_path$queue.log 2>/dev/null &
  42. retval=$?
  43. if [ ! $retval -eq 0 ]; then
  44. echo -n $queue" init failed."
  45. failure
  46. echo
  47. return 0
  48. fi
  49. echo $! >> $pid_path
  50. done

  51. success
  52. echo
  53. return $retval
  54. }

  55. # Stop the service
  56. stop() {
  57. echo -n $"Stopping $prog: "

  58. if [ ! -f $pid_path ]; then
  59.                 echo -n "pid "$pid_path" not exists."
  60.                 failure
  61.                 echo
  62.                 return 0
  63.         fi

  64. queues=$(cat $pid_path)
  65. for queue in $queues
  66. do
  67. kill -9 $queue 1>/dev/null 2>&1
  68. retval=$?
  69.                 if [ ! $retval -eq 0 ]; then
  70.                         echo -n $queue" stop failed."
  71.                         failure
  72.                         echo
  73.                         return 0
  74.                 fi
  75. done

  76. rm -f $pid_path

  77. success
  78. echo
  79. return $retval
  80. }

  81. ### main logic ###
  82. case "$1" in
  83.   start)
  84. start
  85. ;;
  86.   stop)
  87. stop
  88. ;;
  89.   restart)
  90. stop
  91. start
  92. ;;
  93.   *)
  94. echo $"Usage: $0 {start|stop|restart}"
  95. exit 1
  96. esac

  97. exit 0
复制代码
使用方法
1.根据实际情况,按照上面的配置提示,修改相应配置,并保存为 /etc/init.d/queued(建议以这样的方式命名,注意路径必须是 /etc/init.d/)
2.在 Shell 里面执行:

# 为守护进程脚本增加执行权限
chmod +x /etc/init.d/queued
# 设置开机启动
chkconfig queued on守护进程设置完成。

3.在上面配置的目录中添加测试 PHP 计划任务脚本,如 hello.php:
  1. <?php
  2. // 注意,推荐使用死循环的方式
  3. // 这个守护进程脚本也是以这个思路来写的
  4. while (true)
  5. {
复制代码
// 做点事情

    // 注意,这里的输出会记录到日志文件里面,可以输出些有用的信息来帮助排除问题
    echo "hello from queued.\n";

    // 延迟时间,建议用秒级别的,usleep ... 你确定么?
    sleep(20);
}4.好了,来运行看看:

/etc/init.d/queued start查看下日志目录:

less /var/log/queue/hello.php.log收工。

其他的,比如:

# 停止所有计划任务
/etc/init.d/queued stop

# 重新启动守护进程脚本
/etc/init.d/queued restart注意事项
1.由于是基于死循环的方式实现,如果代码里面有引入基础文件后的死循环操作,那依赖基础文件中的变量的代码部分,要注意调整,举例来说:
  1. <?php
  2. define('START_TIME', microtime(true));

  3. // 假如这个文件里面定义了 TIME 常量,
  4. // 以备后面的代码获取当前时间用
  5. //(避免一次请求中多次调用 time() 函数带来的性能损失)
  6. require '../init.php';

  7. $interval = value(config('mail'), 'interval', 20);
  8. $interval_size = value(config('mail'), 'interval_size', 50);
  9. while (true)
  10. {
  11.     $queue = & factory::queue('mail');

  12.     // 这里的定时循环,用到了 TIME 常量
  13.     // 比如记录执行时间,甚至用 TIME 常量做查询条件
  14.     echo $queue->interval($interval_size);
  15.     sleep($interval);
复制代码
}看了上面的注释,问题就比较明显了。
当以普通用户请求过去时,由于是正常流程,每次请求发起后,TIME 都会重新赋予正确的当前时间;
但当使用死循环后,以后的每次 interval 用到的时间都会是 该计划任务脚本启动时间。
这就是问题,需要注意和调整。

2.修改和添加计划任务后,需要重新启动守护进程,方法上面已经介绍了,restart 就可以。
3.担心日志过多?设置下日志自动滚动切割吧:
  1. # 在 /etc/logrotate.d/ 目录下建立 queued 文件
  2. vim /etc/logrotate.d/queued

  3. # 输入如下的信息,路径之类的要和你自己设置的保持一致
  4. /var/log/queue/*log {
  5.     daily
  6.     rotate 10
  7.     missingok
  8.     notifempty
  9.     sharedscripts
  10.     compress
  11.     postrotate
  12.         /etc/init.d/queued restart > /dev/null 2>/dev/null || true
  13.     endscript
  14. }
复制代码
保存文件,完成。
这样,每天日志会自动滚动切割,最多保留 10 个日志文件(未验证这个步骤... 如有问题请反馈)。

4.进程崩溃、服务器断电...导致守护进程起不来或停不了了?
直接 ps -ef | grep *** 关键词,看是否有在运行的 PHP 计划任务代码,kill 掉,然后删除 pid 文件,重新启动即可。
更多...
其实 crontab 也有对应的解决方法:

# 打开 crontab 编辑界面
crontab -e

# 输入类似的设置
* * * * * /bin/date
* * * * * sleep 20; /bin/date
* * * * * sleep 40; /bin/date思想就是... 同时添加多个任务,然后每个之前以适当的延时隔离开,就是说每分钟会有 N 个程序被触发,但会逐个延迟执行,也是个不错的解决思路。




论坛徽章:
0
发表于 2012-02-17 23:43 |显示全部楼层
谢谢分享
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP