PHP / MySQL中的任务队列:竞争条件

时间:2013-01-30 14:59:12

标签: php mysql queue conditional-statements race-condition

我正在PHP中实现一个脱机任务队列。在线页面在此表中插入记录以安排工作:

create table sl_task_queue (
    task_id int primary key auto_increment,
    task_data varchar(255) not null,
    started_date datetime,
    completed_date datetime,
    priority int not null default 10
) ENGINE=Innodb;

然后,离线,我有一个PHP CLI进程池,它们处于循环中等待工作。要查询工作,他们运行此功能:

$SEMKey = "849039";
$seg = sem_get( $SEMKey, 2, 0666, -1) ; 

function getTask() {
    sem_acquire($GLOBALS['seg']);

    // This function returns null for no results, or a Task ORM object on success
    $Task = eSqlObject("Task", "select * from sl_task_queue 
        where started_date is null 
        order by task_id asc limit 1 for update"); 

    if( $Task ) {
        // Set started_date to claim this task
        $Task = new LucidityTask($hash);
        $Task['started_date'] = date("Ymd H:i:s");
        $Task->save(); // performs an UPDATE query
    }

    sem_release($GLOBALS['seg']);   

    return $Task;
}

我在这里尝试了两件事,PHP信号量和MySQL的“SELECT ... FOR UPDATE”功能。我还尝试了一个完整的LOCK TABLE命令。尽管如此,我仍然遇到了守护进程声称同一行的两个进程的问题,我无法确定原因。几个怀疑 - 当您执行单独的CLI进程时,PHP的信号量是否会进入derp模式?或者MySQL是否花了很多时间来实际更新基础表数据,以便在此函数退出后,SELECT查询仍会在短时间内返回旧数据?

还有其他想法吗?

非常感谢!

2 个答案:

答案 0 :(得分:1)

GAH!这就是复制/粘贴是邪恶的原因。这是问题所在:

$seg = sem_get( $SEMKey, 2, 0666, -1) ; 

“2”允许两个进程一次获取信号量。谢谢路易斯H.!

答案 1 :(得分:0)

添加其他字段...例如uniqueID

1)生成uniqueID ...

$uniqueID = uniqid();

2)更新一行。设置字段uniqueID = $ uniqueID

3)选择uniqueID = $ uniqueID的1行 如果行存在 - >做其他工作 - >尝试标记/获取另一条记录

4)在作业完成时删除uniqueID = $ uniqueID的行。

利润! :)

另外你可以设置“endTime”= currentDateTime + N_Minutes(分钟 - 这一行将被锁定多长时间) 当endTime<时,清除uniqueID现在()