Dados do sistema:
OS Ubuntu's Timezone: Asia/Tokyo(JST)
MySQL(RDS)'s Timezone: System
comando cron
30 * * * * cd project && php bin/console command-name
Executando o construtor de consultas do EM na parte superior execute()
do comando:
$em = $this->getContainer()->get('doctrine')->getManager();
$newsletters = $em->getRepository('AppBundle:Newsletter')->getNewsletterForDelivery()->getQuery()->getResult();
O construtor de consultas do comando:
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;
}
Minhas expectativas sobre esse construtor de consultas é que ele busque o boletim informativo para entrega com base nas condições acima. No entanto, quando o cron está executando o comando que executa esse construtor de consultas, ele não está enviando no horário atribuído, mas sim após 9 horas.
A condição que tem problema é:
->andWhere("DATE_FORMAT(n.sendDatetime,'%Y-%m-%d %H:%i') <= DATE_FORMAT(NOW(),'%Y-%m-%d %H:%i')")
Resultado:
TITLE Send Date Time Actual receive date time
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
Como você pode ver, a data e hora real recebida é de cerca de 9 horas após a data e hora de envio, mesmo que o fuso horário do MySQL e do SO esteja definido como JST. E então tentamos compensar e ajustar para now
adicionar 9 horas
Abaixo está o ajuste do código para incluir um tempo de +9 horas:
public function getNewsletterForDelivery()
{
// Adjust the `now` +9hours because newsletters are sent after 9hours because of system/symfony timezone issue
$adjustedNow = new \DateTime(); // Current time
$adjustedNow->modify('+9 hours'); // Add 9 hours
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select('n')
->from('AppBundle:Newsletter', 'n')
// Compare sendDatetime with the adjusted current time
->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) // Set the adjusted current time
->setParameter('status', Newsletter::STATUS_DEFAULT)
->setParameter('sendStatus', Newsletter::SEND_STATUS_WAITING);
return $qb;
}
Resultado:
TITLE Send Date Time Actual receive date time
Test 1 | 2024-11-21 17:00 | 2024-11-21 17:30 OK
Test 2 | 2024-11-21 17:15 | 2024-11-21 17:30 OK
Test 3 | 2024-11-21 17:30 | 2024-11-21 17:30 OK
Test 4 | 2024-11-21 17:45 | 2024-11-21 17:30 NOT OK
Test 5 | 2024-11-21 18:00 | 2024-11-21 17:30 NOT OK
Test 6 | 2024-11-21 18:15 | 2024-11-21 17:30 NOT OK
Test 7 | 2024-11-21 18:30 | 2024-11-21 17:30 NOT OK
Test 8 | 2024-11-21 18:45 | 2024-11-21 17:30 NOT OK
Test 9 | 2024-11-21 19:00 | 2024-11-21 17:30 NOT OK
E agora está enviando o boletim informativo mesmo que as cartas supostamente ainda não tenham sido entregues.
Nota 1: Remover o DATE_FORMAT
na condição para comparar a data e hora bruta tem o mesmo efeito.
Nota 2: Executar manualmente o comando da CLI e tentar buscar um dado do boletim informativo
NOW : 2024-11-22 17:08:18 (current datetime when this was executed)
Test 1: 2024-11-21 17:00:00 (actual datetime from DB)
👆 significa que executar o comando manualmente busca o boletim informativo correto
TLDR: Executar manualmente busca o boletim informativo correto (não mais que senddate) enquanto o cron busca o boletim informativo mesmo que senddate seja 2 horas depois de agora