PHP进程ID和唯一性

7

我想在后台运行一个php脚本,并将其PID存储在数据库中,以便稍后检查特定脚本是否正在运行。

我们可以使用getmypid获取当前PID。

但根据PHP手册的说法:

进程ID并不唯一,因此它们是一个弱熵源。我们建议不要在安全相关的上下文中依赖pid。

...所以我不能依靠PID。

我的第二个想法是将进程创建时间存储到数据库中。

如何获取当前脚本创建时间?稍后如何与任务列表进行比较以检查特定脚本是否正在运行?

我在共享主机上运行,环境为Windows / Linux。


1
在与安全相关的情境中,有关PID的评论是指“熵源”,例如srand(getmypid());。你似乎需要某种进程监控机制,如daemontools、perp、minit等:大多数这些机制都会派生出一个子进程,并监视文件描述符和信号来查看子进程是否仍然活动。对于你的想法,你必须解决时序问题、权限等问题(以确定在数据库中存储的PID所对应的进程实际上是否是同一个进程)。 - akira
1
http://kr.github.io/beanstalkd/(这是一个作业队列),顺便使用了一些好东西:已经接受了给定工作的进程必须向队列报告它仍然活着并正在处理任务。您也可以在PHP中实现类似的功能:如果进程本身没有及时使用给定标识符报告回来,则可以将该任务视为被中断/失败等。在我看来,观察生成/分叉子进程的信号/文件描述符仍然更容易。 - akira
1
可能会有用:https://github.com/CHH/kue - 一个极简、通用且独立于框架的作业队列接口 - akira
@akira 非常感谢..让我检查一下.. - Red
3个回答

4

php.net/getmypid获取到的内容,稍微修改以禁用非 cli 访问。

脚本可以使用/usr/bin/php script.php执行。

此外,使用nohup /usr/bin/php script.php > nohup.out &在后台启动nohup进程。

#!/usr/bin/php 
<?php 

if ( PHP_SAPI !== 'cli' ) {
    die( "Cmd line access only!\n" );
}

define( 'LOCK_FILE', "/var/run/".basename( $argv[0], ".php" ).".lock" );  // can also use /tmp
if( isLocked() ) die( "Already running.\n" ); 

# The rest of your script goes here.... 
echo "Hello world!\n"; 
sleep(30); 

unlink( LOCK_FILE ); 
exit(0); 

function isLocked() 
{ 
    # If lock file exists, check if stale.  If exists and is not stale, return TRUE 
    # Else, create lock file and return FALSE. 

    if( file_exists( LOCK_FILE ) ) 
    { 
        # check if it's stale 
        $lockingPID = trim( file_get_contents( LOCK_FILE ) ); 

       # Get all active PIDs. 
        $pids = explode( "\n", trim( `ps -e | awk '{print $1}'` ) ); 

        # If PID is still active, return true 
        if( in_array( $lockingPID, $pids ) )  return true; 

        # Lock-file is stale, so kill it.  Then move on to re-creating it. 
        echo "Removing stale lock file.\n"; 
        unlink( LOCK_FILE ); 
    } 

    file_put_contents( LOCK_FILE, getmypid() . "\n" ); 
    return false; 

} 
?>

1
这完全取决于您对目标机器的访问级别。您可以使用PHP CLI,存储PID(它们是特定时间点的唯一标识,因此您不会有两个具有相同PID的进程在运行),并在ps -ax的输出中grep它们以检查它们是否正在运行。如果没有-从数据库中删除它们,以便您不会遇到相同PID的问题。

不要立即翻译。您将能够在数据库中标记为已完成。请包括日期/时间以区分。 - David Jashi

0

您可以尝试使用PID与另一个ID,例如:

如果您有一个使用文件ID = 327的压缩作业,请尝试存储{PID} 327,并检查此特定作业是否仍在运行。

即使PID被重用,您也不会将具有ID 327存储的PID,或者如果您重新启动具有此特定ID 327的压缩过程,则PID可能会更改。

但是,为了避免使用此ID 327获取相同的PID,您需要先检查数据库,然后在组成的ID末尾添加计数器,例如{PID} 327_1。

希望这可以帮助到您。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接