我必须确保某个PHP脚本(由Web请求启动)不会再运行一次。
使用二进制文件,可以很容易地检查某个二进制文件的进程是否已经存在。
但是,PHP脚本可能由多个路径运行,例如。 CGI,FCGI,内部网络服务器模块等,所以我无法使用系统命令来查找它。
那么如何可靠地检查某个脚本的另一个实例当前是否正在运行?
答案 0 :(得分:4)
使用与本地应用程序选择完全相同的策略:
该过程管理“锁定文件”。
您在文件系统中定义静态位置。在脚本启动时,您检查该位置是否存在锁定文件,如果是,则进行纾困。如果不是,首先创建该锁定文件,然后继续。在拆除脚本期间,您再次删除该锁定文件。这样的锁文件是一个简单的被动文件,只有它的存在才有意义,往往不是它的内容。这是一个标准程序。
如果您将锁定文件不仅用作被动信号量,而且将生成过程的进程ID存储在其中,则可以赢得额外的糖果积分。这允许随后尝试验证该过程实际上仍然存在或者在同一时间内崩溃。这是有道理的,因为这样的崩溃会留下陈旧的锁定文件,从而产生死锁。
要解决在评论中讨论的问题,这些评论正确地指出在一些在wen环境中使用php脚本的场景中,进程ID本身可能不足以可靠地测试如果给定任务已成功完成并且已完全处理,则可以使用稍微修改的设置:
传入的请求不直接触发执行php脚本本身的任务,但仅仅是一个包装脚本。该包装器管理锁文件,同时将要执行的实际任务委托给http服务器的子请求。这允许控制包装器脚本使用请求状态的附加信息。 如果执行php脚本的实际任务确实在没有事先通知的情况下崩溃,那么请求包装器知道这一点:每个请求都以特定的http状态代码终止,该代码允许确定执行请求的任务是否已正常终止或不。对于大多数用途,该设置应该足够可靠。琐碎的包装器脚本崩溃或被终止的可能性落入系统故障的区域,这是锁定策略无法可靠处理的。
答案 1 :(得分:0)
由于PHP并不总是提供可靠的文件锁定方式(它取决于脚本的运行方式,例如CGI,FCGI,服务器模块和配置),因此应该使用其他一些锁定环境。
PHP脚本可以调用其中的另一个PHP解释器的CLI变体。这将提供可以检查锁定的唯一PID。应该将PID存储到某个锁定文件中,然后通过查询使用PID的进程是否仍然存在来检查是否存在失效锁定。
也许还可以在shell脚本中执行所有需要锁定的任务。 Shell脚本还提供唯一的PID并在退出后释放它。 shell脚本也可以使用唯一的文件名,可用于检查它是否仍在运行。
也可以使用信号量(http://php.net/manual/de/book.sem.php),这些信号量由PHP解释器明确管理,以反映脚本的生命周期。它们看起来效果很好,但是对于过早死亡的情况下,它们的可靠程度并不多。
还要记住,即使脚本结束,PHP脚本启动的外部进程也可能继续执行。例如,用户在FCGI上的中止会释放passthru
进程,尽管客户端连接已关闭,但仍会继续工作。如果积累了足够的输出或者根本没有输出,它们可能会被杀死。
因此,这样的外部进程也必须锁定,而不能仅由PHP获取的信号量来完成。