Symfony定时任务时区异常:邮件发送时间偏差问题排查
系统信息
Ubuntu系统时区:Asia/Tokyo(JST) MySQL(RDS)时区:跟随系统
定时任务命令
30 * * * * cd project && php bin/console command-name
核心代码实现
命令execute方法
在命令的execute()方法开头通过EntityManager调用查询构建器:
$em = $this->getContainer()->get('doctrine')->getManager(); $newsletters = $em->getRepository('AppBundle:Newsletter')->getNewsletterForDelivery()->getQuery()->getResult();
查询构建器初始代码
命令对应的查询构建器逻辑:
public function getNewsletterForDelivery() { $qb = $this->getEntityManager()->createQueryBuilder(); $qb->select('n') ->from('AppBundle:Newsletter', 'n') ->andWhere("DATE_FORMAT(n.sendDatetime,'%Y-%m-%d %H:%i') <= DATE_FORMAT(NOW(),'%Y-%m-%d %H:%i')") ->andWhere('n.status = :status') ->andWhere('n.sendStatus = :sendStatus') ->setParameter('status', Newsletter::STATUS_DEFAULT) ->setParameter('sendStatus', Newsletter::SEND_STATUS_WAITING); return $qb; }
初始问题现象
预期查询构建器能按条件获取待发送邮件,但通过cron执行时,邮件总是延迟9小时发送,问题出在时间比较条件:
->andWhere("DATE_FORMAT(n.sendDatetime,'%Y-%m-%d %H:%i') <= DATE_FORMAT(NOW(),'%Y-%m-%d %H:%i')")
实际执行结果:
标题 计划发送时间 实际接收时间 Test 1 | 2024-11-06 16:56 | 2024-11-07 01:30 Test 2 | 2024-11-07 13:00 | 2024-11-07 22:30 test 3 | 2024-11-07 13:25 | 2024-11-07 22:30 Test 4 | 2024-11-13 09:15 | 2024-11-13 18:30
可见即使MySQL和系统时区均为JST,实际接收时间仍比计划晚9小时。
尝试修复后的新问题
为补偿时区问题,尝试将now时间加9小时,调整后的查询构建器代码:
public function getNewsletterForDelivery() { // 调整`now`加9小时,解决因系统/Symfony时区问题导致的邮件延迟发送 $adjustedNow = new \DateTime(); // 当前时间 $adjustedNow->modify('+9 hours'); // 增加9小时 $qb = $this->getEntityManager()->createQueryBuilder(); $qb->select('n') ->from('AppBundle:Newsletter', 'n') // 比较sendDatetime与调整后的当前时间 ->andWhere("DATE_FORMAT(n.sendDatetime, '%Y-%m-%d %H:%i') <= DATE_FORMAT(:adjustedNow, '%Y-%m-%d %H:%i')") ->andWhere('n.status = :status') ->andWhere('n.sendStatus = :sendStatus') ->setParameter('adjustedNow', $adjustedNow) // 设置调整后的当前时间 ->setParameter('status', Newsletter::STATUS_DEFAULT) ->setParameter('sendStatus', Newsletter::SEND_STATUS_WAITING); return $qb; }
调整后的执行结果出现新问题:邮件被提前发送,即使计划发送时间未到:
标题 计划发送时间 实际接收时间 Test 1 | 2024-11-21 17:00 | 2024-11-21 17:30 正常 Test 2 | 2024-11-21 17:15 | 2024-11-21 17:30 正常 Test 3 | 2024-11-21 17:30 | 2024-11-21 17:30 正常 Test 4 | 2024-11-21 17:45 | 2024-11-21 17:30 异常 Test 5 | 2024-11-21 18:00 | 2024-11-21 17:30 异常 Test 6 | 2024-11-21 18:15 | 2024-11-21 17:30 异常 Test 7 | 2024-11-21 18:30 | 2024-11-21 17:30 异常 Test 8 | 2024-11-21 18:45 | 2024-11-21 17:30 异常 Test 9 | 2024-11-21 19:00 | 2024-11-21 17:30 异常
关键注意点
- 移除条件中的
DATE_FORMAT,直接比较原始datetime字段,结果与之前一致 - 手动从CLI执行命令时能获取符合条件的邮件数据:
当前时间: 2024-11-22 17:08:18 (执行时的当前时间) Test 1: 2024-11-21 17:00:00 (数据库中的实际时间)
问题总结
手动执行命令时,能正确获取符合计划发送时间的邮件;但通过cron执行时,会提前获取计划发送时间晚于当前时间2小时的邮件。
内容的提问来源于stack exchange,提问作者Mr. Kenneth
相关产品推荐
相关产品推荐

