一个脚本引发的思考

问题来源:

前段时间写了一个crontab脚本,每5分钟连接一次数据库,遍历库中待处理的任务,一旦发现待处理(status=0)的任务,则将该任务状态置为处理中(status=1),然后开始执行这个任务(dealing process),执行完成status=2

最初我是一次性将所有任务设为处理中,然后一个一个串行处理,这样效率极低,一个任务可能要1个小时,其他的只能排队等。

Q1:如果一次性插入多个任务到任务表(比如5个,初始都是status=0),当cron执行第三条的时候,5分钟到了,然后开启第二个cron进程,继续扫描任务表,发现有2个待处理,于是去处理。。。可是,这个时候,如果第一个进程刚刚执行完第3个任务,开始执行第4个任务(也就是第二个进程的第1个任务),但是总会有一个进程会拿到这个任务,另一个进程会出现执行失败的情况

原因如下:

先遍历数据库,将待处理任务取出
第一个进程,将5个任务存入数组
$firstTask = array(1,2,3,4,5)
5min后,第二个进程,将2个任务存入数组
$secondTask = array(4,5)
如果第4个任务被第一个进程执行,但是此时4、5任务均位于第二个进程待处理范围,会继续run,这时候update任务表时,返回false;因为第4个任务已经被第一个进程处理了(已经update了)!
当然,这是没有问题的,最终5个任务都会被处理掉,不管他们是那个进程处理的,但是过程中,会出现返回false,伴随更新数据库失败的发生,为了避免这一个问题的发生,在update任务表之前,要先查询任务的状态,如果处理中(status=1),OK,跳出此次循环,continue。。。这样的话,可以充分利用多进程并行处理多任务

Q2:如果一个任务处理时间较长,当处理完成,再次更新任务状态时失败,因为数据库已经失联了!对,断开连接,为什么?因为如果长时间链接数据库,而又没有操作,相当占用服务资源,我们都知道,数据库的链接数量是有限的,如果一直占着资源不放,其他作业就无法进行。就像一句俗语你懂的!

所有数据库一般都设置了连接超时时间,比如30s自动断开连接,再次使用只能重新连接
查看mysql当前连接数
show processlist;
请输入图片描述
查看mysql超时时间设置
show variables like '%timeout%';
请输入图片描述

所以为了保证任务顺利完成,可以在每个sql操作前进行mysql的connection连接(基于单例模式,如果已经连接,则不需再连接)