在我们的业务中,需要定时任务去执行php脚本,对苹果自动续费用户进行续约。某次发现有大量的定时任务在执行,有些开始时间是半年前,所有进程都处于睡眠中。
root 31625 0.0 0.0 108124 1304 ? Ss Mar22 0:00 /bin/sh -c /usr/local/php7/bin/php -r 'Crontab::debug("/data/erge_api", "Cron_Apple_Pay_Subscribe");' >> /tmp/cronapplepaysubscribe.log 2>&1
root 31634 0.0 0.0 233520 10064 ? S Mar22 0:49 /usr/local/php7/bin/php -r Crontab::debug("/data/erge_api", "Cron_Apple_Pay_Subscribe");
通过lsof命令可以发现,该进程打开了两个socket,一个是连接数据库的,一个是请求苹果服务器的。
php 31634 root 3u IPv4 3973134538 0t0 TCP localhost:63880->localhost:27017 (ESTABLISHED)
php 31634 root 4u IPv4 3973134589 0t0 TCP 192.168.10.100:17462->17.154.66.159:https (ESTABLISHED)
再通过strace命令,可以发现进程一直在进行如下调用,而且文件描述符就是4,也就是说,进程一直轮询地获取从苹果服务器那边的数据。
restart_syscall(<... resuming interrupted call ...>) = 0
poll([{fd=4, events=POLLIN|POLLPRI|POLLRDNORM|POLLRDBAND}], 1, 0) = 0 (Timeout)
clock_gettime(CLOCK_MONOTONIC, {41212631, 418739828}) = 0
clock_gettime(CLOCK_MONOTONIC, {41212631, 418821856}) = 0
clock_gettime(CLOCK_MONOTONIC, {41212631, 418887370}) = 0
为了确认这个现象,可以在应用程序中加上日志。Logger打印日志的时候还会加上进程ID。
Logger::crontab($value, 'start', __CLASS__);
$ch = curl_init($endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
$response = curl_exec($ch);
$errno = curl_errno($ch);
$errmsg = curl_error($ch);
curl_close($ch);
Logger::crontab($response, "applepay|notify|receiptdata", __CLASS__);