PHP脚本不断“重启”以创建自身的新实例

时间:2018-12-16 05:38:18

标签: php linux apache cron-task

我使用Zend Framework 2开发了一个站点。它基本上是一个价格比较站点,它与许多顶级联盟网络集成在一起。我编写了一个脚本,该脚本检查每个会员网络的价格,然后使用该价格更新我的本地数据库。根据与我联系的联盟网络的不同,我可能正在进行API调用(Amazon或CJ.com),或者正在查看XML产品供稿(Pepperjam或LinkShare)。 XML产品Feed将在本地托管。

目前,我正在使用此脚本检查大约3500 sku。其中绝大多数(95%以上)都针对XML产品供稿。我估计此脚本可能需要大约10分钟才能完成。我正在查看的一些XML文件的大小约为8 MB。

我已经在本地环境中对该脚本进行了彻底的测试,并花了很长时间才能确保没有内存泄漏或其他会导致性能问题的本质。作为示例,我确保尽可能使用数据流,以避免将XML文件一遍又一遍地放在内存中,等等。可以说,脚本在本地运行没有问题。

该脚本旨在作为cron作业运行,但是我确实有一种方法可以通过安全的管理界面ad-hoc触发它。在本地,这就是我启动脚本运行的方式,并且一切都进行得很顺利。

当我将代码部署到共享主机帐户时,我遇到了各种各样的问题。为了进行故障排除,我在该脚本的各个阶段附加了日志记录,以跟踪该脚本的启动时间,进度以及完成每个步骤的时间等。所有这些都记录在MySQL数据库中。

问题1 :如果我通过HTTP请求临时运行脚本,我发现它将运行几分钟,然后脚本再次启动(因此现在有两个实例显然正在运行)。请再等待几分钟,然后第三分钟将开始,依此类推。...这是一个示例,当我通过HTTP请求触发脚本在晚上10:09运行时。

Screenshot of process manager

不用说,我不会通过HTTP请求运行它,因为它只会使我的Web托管提供商陷入困境:)

问题2 :当脚本在服务器上运行(通过cron作业触发)时,脚本无法完成。我已经制作了数据库的生产副本,并将其与XML文件一起放在本地,它运行良好。因此,不良数据公开不良代码应该不会成为问题。我的观察是-脚本几乎在完全相同的时间内运行-在中止,终止或执行任何操作之前。脚本触发后,最后更新的记录通常会在大约4分钟30秒(如果有内存)上加上时间戳。 SKU列表在不断变化,因此结束的记录有所不同,但是上一次更新的时间几乎每次都相同。错误日志中未记录任何内容。我通过SSH top命令监视服务器资源,没有任何异常。正在检查CPU使用情况,并且使用的内存不会增加。

我有一个通过Bluehost共享的托管帐户。我的想法是,这可能是脚本最大执行时间的问题。我通过php.ini扩展了脚本本身的最大执行时间。没什么。

所以我想我正在寻找的是下一步的一些新想法。我应该问托管公司哪些问题,以便他们可以帮助我深入浅出。至少可以说,它们只是有所帮助。我的托管帐户可能会有一些限制吗?触发某种正在杀死脚本的自动监视器?对于这种性质的脚本,哪种类型的Apache设置可能会出现问题? PHP.ini设置?绝对可以提供任何输入。

为什么通过HTTP触发时,它将继续旋转新实例?我想我可以不手动运行它,而只能通过cron作业运行它,但这也不起作用。所以....有兴趣听取社区对此的想法。谢谢!

1 个答案:

答案 0 :(得分:1)

我还没有看过您的脚本,也没有与您的托管人合作,所以下面的所有内容只是一个猜测-和一个建议。

考虑到您的描述,我想您是对的,您的脚本从cron运行时可能已被超时杀死。我不确定为什么当您通过HTTP请求手动执行脚本时,它为什么会继续生成脚本的新实例,但是它也可能与超时有关(例如,如果它们具有在未生成脚本的情况下重新启动脚本的逻辑,在一定时间内或类似的时间输出。

您可以与托管服务提供商联系,以了解如何在其环境中运行长时间运行(或占用内存的脚本),并且他们可能已经编写了一些有关此主题的常见问题解答或文档。

如果您的提供者无法提供帮助,请允许我为您提供一个选择。

根据您所说的,我希望您的脚本运行一个SQL查询以获取SKU列表,然后缓慢地对该列表进行迭代,对每个项目执行一些工作(并据我们所知最终由于某种原因而死亡)。

如果您创建一个临时表(或文件-服务器上任何类型的持久性存储),该临时表将保存脚本的最后处理记录ID,或者如果脚本成功完成,则为NULL。这样,您就可以使脚本从最后处理的记录开始(如果最后处理的记录的id = 1000,则将... WHERE id > 1000添加到获取SKU的主查询中),而您实际上并不在乎如果脚本是否完成了第一次尝试(如果没有完成,则从被杀死时的那一点开始,将继续进行第二次尝试)。

或者,要扩展此方法,您可以将一次调用限制为要处理的一定数量的记录(例如100或1000),再次将最后处理的记录ID保存在数据库或其他地方。

主要思想是:如果脚本无法一次处理所有SKU,只需使其重新启动即可,以免失去进度。