2012-09-28 43 views
0

我正在运行一个需要处理一些“繁重”任务(从30秒到3分钟)的webapp(php)。我知道它不是非常重,但我不能让我的用户等待它们,所以我设置了一个内部API,如:http://localhost/process-picture/745884/,并将此操作存储在MySQL表中。如何运行一个长时间的后台进程,linux服务器

现在我想创建一个“进程”来获取MySQL表并执行最旧的排队操作,一旦完成,它就会得到下一个,等等。

首先我想过做一个PHP脚本,通过卷曲调用系统类似的:

fetchOperation.php连接到数据库并获取URL的操作通过卷曲来调用它。 每个操作:执行本身,然后从队列中删除自己并再次调用(cURL)fetchOperation.php

我觉得这个系统有点棘手,所以我想知道是否有(以及用哪种语言编写它)以任何方式设置后台进程,每15秒检查一次数据库,并执行以下操作:

  • 删除标记为DONE的所有行。
  • 检查是否有任何行标记为PROCESSING,如果是,请退出并等待下一个15秒。
  • 如果没有PROCESSING行,则触发最早的一个(FIFO队列)PENDING

这样我可以管理在任何时间被处理,甚至控制了服务器负载(例如,在夜间允许有多达三个PROCESSING项目)。

对不起,这样长的解释,并提前致谢!

+0

提交到一个队列,并有一个解析队列工作的crontab。 – BugFinder

+0

该进程是否必须在没有webserver调用的服务器(如cron脚本)上运行? – ntvf

+0

“标记为”的行意味着有一列包含此信息?你可以在发生这种情况的服务器上编写并运行脚本吗? – quinestor

回答

0

最后我解决了它那方式:

1st。以可调用URL的方式设计操作。例如:http://localhost/render-image/14523665

2nd。将挂起的操作存储在如下表格中:操作(opertation-id,operation-url,operation-status)。

一旦准备好我设计了一个简短的PHP脚本,执行以下操作:

<?php 
if(WORKER_IS_ONLINE !== true) exit(); 
OperationsQueue::CleanQueue(); 
while(OperationsQueue::RunningOperations() < WORKER_MAX_OPERATIONS) { 
    launch_operation(OperationsQueue::DequeOperation()); 
} 
sleep(WORKER_SLEEP_TIME); 
launch_operation('/operations_queue/deque'); 

此附配的功能(launch_operationOperationsQueue类)做如下(注意,这还没有实现):

<?php 
define('WORKER_SLEEP_TIME', 15);  // Time to sleep between sweeps. 
define('WORKER_HOST', 'localhost'); // Hostname where the operations will be performed. 
define('WORKER_PORT', 80);  // Port where the operations will be performed. 
define('WORKER_SOCKET_TIMEOUT', 80); // Port where the operations will be performed. 
define('WORKER_MAX_OPERATIONS', 2); // Max simultaneous operations. 
define('WORKER_MAX_LAUNCHES', 2); // Max operations launched within a sweep. 
define('WORKER_IS_ONLINE', false); // Bool value that marks whether the worker must be working or not. 

function launch_operation($operation) { 
    $fp = fsockopen(WORKER_HOST, WORKER_PORT, $errno, $errstr, WORKER_SOCKET_TIMEOUT); 
    if ($fp) { 
     $out = 'GET ' . $operation . " HTTP/1.1\r\n"; 
     $out .= 'Host: ' . WORKER_HOST . "\r\n\r\n"; 
     fwrite($fp, $out); 
     fclose($fp); 
    } 
} 

class OperationsQueue { 

    public static function RunningOperations(){ 
     // connect to DB an perform: SELECT COUNT(*) FROM operations WHERE status = 'PROCESSING'; 
     return 1; 
    } 
    public static function CleanQueue(){ 
     // connect to DB an perform: DELETE FROM operations WHERE status IN ('DONE', 'CANCELED'); 
    } 
    public static function DequeOperation(){ 
     // connect to DB an perform: SELECT * FROM operations WHERE status = 'PENDING' ORDER BY id ASC LIMIT 0, 1; 
     // UPDATE operations SET status = 'PROCESSING', tries = tries+1 WHERE id = $id; 
     return 'operation_url'; 
    } 

} 

我认为这可能对其他人有用。正如你所看到的,它将操作链接起来

+0

如果你的cron脚本是php,并且你通过一个url调用一个php脚本,为什么不把这个功能的所有php移动到cron脚本中,你就会摆脱不必要的网络流量(尽管它可能很小) 。 –

+0

虽然这样做我已经到了它可能需要以N秒为基础运行的地步,其中cron以N分钟间隔运行。这指出了我的设计。同时它允许我在没有外壳控制的系统中运行它,否则你无法完成它。我在研究这个系统,我可能很快就会在github上发布它。 –

4

听起来像你需要安排cron工作。 cron只会运行一个脚本/程序,所以它的实现将不同于调度本身。

克朗只会火/忘了,所以你可以调用从任何时间的过程(我看你在下面执行时的评论 - 请修改,如果我误解)

+0

同意。也许额外的PHP执行时间的调整将需要 – ntvf

+0

使用'php.ini'作为CLI解释器默认情况下具有noch执行时间限制,但是:它不会伤害看看'$ php -i | grep -i max_execution_time' – KingCrunch

+0

是的,这可能是一个好方法。所以我只需设置一个连接到数据库的cron php并通过cURL请求触发我想要的内容。对? –

相关问题