在不使用 CRON 的情况下安排脚本
Posted
技术标签:
【中文标题】在不使用 CRON 的情况下安排脚本【英文标题】:Schedule scripts without using CRON 【发布时间】:2011-01-09 18:26:24 【问题描述】:我知道有很多关于使用 CRON 运行 php 文件的帖子。但是,在共享主机和易于用户设置的世界中,我不想搞砸这些。
我在网上找到了另一个与套接字有关的解决方案。只是想让每个人都接受这个,并告诉我这是一个好主意还是坏主意。听起来效果不错。
想法?
//Open socket connection to cron.php
$socketcon = fsockopen($_SERVER['HTTP_HOST'],80,$errorno,$errorstr,10);
if($socketcon)
$socketdata = "GET /cron.php HTTP 1.1\r\nHost: ".$_SERVER['HTTP_HOST']."\r\nConnection: Close\r\n\r\n";
fwrite($socketcon,$socketdata);
//Normally you would get all the data back with fgets and wait until $socketcon reaches feof.
//In this case, we just do this:
fclose($socketcon);
else
//something went wrong. Put your error handler here.
cron.php:
//This script does all the work.
sleep(200);
//To prove that this works we will create an empty file here, after the sleep is done.
//Make sure that the webserver can write in the directory you're testing this file in.
$handle = fopen('test.txt','w');
fclose($handle);
从博客文章中找到脚本:http://syn.ac/tech/13/creating-php-cronjobs-without-cron-and-php-cli/
【问题讨论】:
【参考方案1】:这不是一个坏方法,但您需要确保通过关闭套接字它不仅仅是在脚本完成之前终止脚本。您可以将套接字设置为非阻塞。
我仍然会使用 cron 作业,即使它有点痛苦。
【讨论】:
@Bill Karwin - 因为***实际上是方形的。 :)【参考方案2】:cron 作业基本上是 cron 作业。您设置它,操作系统会为您运行该作业。我不确定您从该站点获得的 PHP 脚本是如何工作的,但如果它需要人工干预,那么它并不真正称为 cron 作业。如果不想使用 cron,可以使用循环,然后使用 PHP 的日期函数来设置日期和时间。伪代码
while (1)
$d=date("d");
if ( $d == "01" )
//run every 1st of month
//code to run here
【讨论】:
或者直接使用time_sleep_until()
。【参考方案3】:
如果我理解得很好,你会从远程机器上运行第一个脚本,然后在你的禁用 cron 的主机上运行第二个脚本?那么,当你立即关闭连接时,由于 php/webserver 交互的错误或奇怪特性,脚本不会超时?
第一部分是相当普遍的做法,甚至有公司提供这种服务(例如,http://www.webcron.org/index.php?lang=english 会在您要求的任何时候自动插入您想要的任何脚本,收费)。
第二部分我不知道。这对我来说似乎是 php/webserver 交互中的一个错误,但我可能错了。无论如何,我会仔细检查它是否是一个错误(等等,这就是你现在正在做的事情吗?)如果它被证明是合法的行为,那就去做吧。如果它似乎是一个错误,那么不要依赖它,因为它可以随时修复。
【讨论】:
【参考方案4】:这是一个功能强大但奇怪的解决方案,它确保您需要整天连接您的机器运行第一个脚本。如果你愿意,我建议你使用 wget 或 curl 的 shell 脚本来达到这个目的。
例如:
#!/bin/sh
curl -O http://www.myserver.com/cron.php 2>&1 > /var/log/remote.cron.log
但我认为,如果您不必非常同步地运行,您希望实施的解决方案是检查 index.php 的末尾以查看上次运行脚本的时间(如果超过两个小时)之前,然后是include('cron.php')
。您还可以将脚本运行时间的时间戳存储在环境变量中,以避免性能损失。
【讨论】:
我假设如果您依赖共享机器,您将无法维持 php 脚本的运行。即使那台机器重新启动,这个解决方案也会继续工作。【参考方案5】:据我阅读该博客文章和查看代码所了解的,这并不是没有 cron 访问权限的真正方法,这是一种避免有人等待服务器响应长查询的方法。如果您绝对必须每隔 10 分钟左右执行一次某个脚本,那么您将需要使用 cron 。如果您只是想避免让用户等待很长的查询完成,那么这个 hack 可能会起作用。即使使用这种方法,我仍然认为如果您的脚本花费的时间比 PHP 允许完成的时间长,那么您将达到时间限制。
查看 wp-cron.php(在博客链接中提到),它看起来好像完全依赖访问该站点的用户来触发对一组带时间戳的作业的检查。
除非您有另一台服务器以特定时间间隔 ping,否则这些技术不会非常可靠。该技术的主要目标是避免用户每隔 15 秒等待清理或维护脚本运行一次,而不是真正替代所有使用 cron。
【讨论】:
【参考方案6】:这会产生与 cron 不同的效果。
cron 作业在您提前设置的特定时间运行。
您的方法基本上是对 PHP 脚本的一种“分叉”或“异步调用”。像您在这里所做的那样通过 HTTP 进行操作是一种廉价且简单的技术。我自己用它。它与 cron 的不同之处在于它立即启动“后台进程”。
不过,有几个 cmets:
首先,您应该在“后台”脚本中调用ignore_user_abort()
。否则,在许多环境中,当“调用”脚本关闭套接字时,您的脚本将中止。
其次,您实际上可以在“后台”脚本中检查$_SERVER['HOST']
变量,这样您就可以拥有不暴露在互联网上的脚本(基本上向localhost
发出请求并检查在后台脚本中)。然后,您大概可以信任来自您自己机器的请求,并跳过所有安全检查、会话等。
第三,谁说“后台”脚本必须用 PHP 运行?如果您打算将 PHP 用作“后台”进程,那么它有很多弱点。主要缺点是它阻塞了 I/O。因此,如果您要发送电子邮件、更新数据库行等,基本上每次发送请求时都会暂停脚本。例如,使用 Node.js,您可以异步触发 I/O 命令并继续执行。如果你打算使用 PHP,至少要确保一次发送 10 封电子邮件,或者一次更新 10 行,或者其他的。
最后,如果后台脚本正在执行某些操作,您可能希望在浏览器上显示一个进度条。因此,您将需要使用通用数据存储(如您的数据库)来记录任务的进度。
【讨论】:
ignore_user_abort
绝对是在这里模拟真实后台作业的关键。【参考方案7】:
我花了几天时间才找到一个可行的解决方案,而不会出现竞争条件和/或淹没我自己的服务器,但最后我认为这应该可行:http://www.programmierer-forum.de/phpcron-cronjobs-ohne-crontab-t348377.htm
【讨论】:
以上是关于在不使用 CRON 的情况下安排脚本的主要内容,如果未能解决你的问题,请参考以下文章
在没有 CronTab 的情况下运行 Perl 脚本 1 分钟间隔