Задания wordpress cron выполняются последовательно или параллельно?
Я пытаюсь ограничить количество писем, отправленных с моего сайта, чтобы справиться с ограничениями электронной почты для хостинга.
Я использую задания cron и индикатор сложения электронных писем в базе данных, чтобы проверить, приближается ли количество отправленных писем к максимальному количеству отправленных сообщений.
То, как я это делаю, заключается в прямом выполнении запланированного процесса, затем делает его "спящим" в течение определенного периода времени (в соответствии с его положением в очереди), а затем отправляет электронное письмо и регистрируется в базе данных.
Чтобы далее объяснить причину, по которой я использую запланированные задачи и "спать", рассмотрим следующий сценарий:
- Пользователь пытается зарегистрироваться на моем сайте и ожидает, что в ближайшее время ему будет отправлено электронное письмо. Таким образом, если превышена квитанция электронной почты/минут, мне нужно отправить другое сообщение: "Наш сервер занят, пожалуйста, разрешите" x "минуты выполнить требуемую задачу".
- Запросы на отправку электронной почты выполняются через AJAX. Использование "сна" внутри самого процесса не является вариантом, потому что пользователю придется ждать минут x до тех пор, пока не появится сообщение "занято".
- Я пытался с ob_flush, flush... и т.д. комбинации для эха сообщения, а сервер работает в фоновом режиме, но это никогда не срабатывало. Вызов AJAX всегда ожидал завершения script для эхо-результата.
-
Мне нужно многопоточность на однопоточном языке PHP! В качестве обходного пути я использовал задания cron, где каждая сложенная электронная почта планируется выполнить в time()
(т.е. Непосредственно запустить запланированное задание), которая подключена к той же функции, которая отправляет электронные письма. Используя флаг, функция знает, что запрос является сложенным электронным письмом и делает его "спящим" до времени, необходимого для квоты электронной почты reset.
-
Проблема: если 5 человек зарегистрированы почти в одно и то же время (в то время как у нас все еще есть куча электронной почты), тогда у нас есть 5 заданий cron, которые должны выполняться одновременно, а затем спать некоторое время ( время сна может отличаться, если количество писем в куче уже больше, чем квота по электронной почте), затем отправляются электронные письма. Однако, когда я проверяю журналы в базе данных, я обнаруживаю, что запланированные задания выполняются последовательно, а не параллельно. Иногда бывает, что задание cron запускается до других целей, но они не срабатывают одновременно.
Я знаю, что задания wordpress cron не являются заданиями cron и увольняются, когда кто-то посещает веб-сайт (и я уверен, что обновляю страницы после отправки запросов на регистрацию для запуска всех запланированных задач), но они, похоже, быть единственным вариантом для меня, так как мой хостинг-сервер не разрешает доступ к серверу, не позволяет планировать задания cron.
Вот часть кода, который выполняет вышеуказанное:
//Test example to pile up emails, where quota is set to 2 emails every 30 seconds
$Emails_Threshold = 2;
$Threshold_Duration = 0.5*60;
//Get email indicator info
$Email_Info = $wpdb->get_row(
"SELECT *
FROM PileEmails
WHERE priority = -1
AND Status='New';"
,ARRAY_A);
if ($sleep ==0 && $Queue_Info_id==0){ //Not a scheduled event
//Check if there are queued emails
$Queue_exist = $wpdb->get_row (
$wpdb->prepare("
SELECT Status
FROM PileEmails
WHERE Status='Queued';"
,$mail_priority)
,ARRAY_A);
if (!empty($Queue_exist) || ($Email_Info['last_email_time'] > (time()-$Threshold_Duration))){
if ($Email_Info['count_emails']>=$Emails_Threshold){
//Code to Pile up
}
}else{
//Reset email counter
}
}else{
$wpdb->insert( "PileEmails",$Sleep_Info,$format);
sleep(10); //10 seconds here just as an example
}
//Code to send emails
Вот что я регистрирую в базе данных, когда пытаюсь отправить 10 писем после превышения квоты.
![Журналы базы данных MYSQL]()
Обратите внимание, что временная метка имеет разницу в 10 секунд между каждым журналом и следующим, хотя все они должны быть запущены одновременно и каждый спящий в течение 10 секунд, после чего все отправляют письма параллельно.
Итак, мой вопрос: почему wordpress cron запускает запланированные задания последовательно, а не параллельно? и как преодолеть эту проблему?
Любая помощь очень ценится.
Ответы
Ответ 1
Как уже упоминалось, установка cron-плагина поможет вам управлять вашими кронами.
Чтобы ответить на ваш вопрос, Wordpress использует "cron lock" defined('DOING_CRON')
и устанавливает переходный $lock = get_transient('doing_cron')
при вызове метода spawn_cron
.
Итак, если вы посмотрите на wp-includes/cron.php
, вы увидите, что коронки Wordpress не запускаются одновременно по умолчанию и не будут запускаться более одного раза каждые 60 секунд.
// don't run if another process is currently running it or more than once every 60 sec.
if ( $lock + WP_CRON_LOCK_TIMEOUT > $gmt_time )
return;
Ответ 2
Если вы можете отправлять только одно или два письма одновременно, это будет сложно решить. Более простой способ решить это, вероятно, будет заключаться в том, чтобы WordPress использовал SMTP-сервер электронной почты, который позволяет частоту писем, которые вам нужно отправить. Возможно, достаточно добавить новую учетную запись электронной почты для вашего текущего хостинг-провайдера. Если вы не знаете, как настроить это вручную, есть плагины, которые сделают это для вас.
Ответ 3
Как php работает сверху вниз, поэтому, когда вы планируете событие, используя функцию события расписания WordPress, как показано ниже:
if (! wp_next_scheduled ( 'my_hourly_event' )) {
wp_schedule_event(time(), 'hourly', 'my_hourly_event');
}
add_action('my_hourly_event', 'do_this_hourly');
function do_this_hourly() {
// do something every hour
}
Эта функция do_this_hourly()
будет выполняться согласно расписанию, но код, который вы будете записывать внутри этой функции, будет запускаться только один за другим.
- Возьмем пример отправки электронной почты на 5 человек, поэтому электронное письмо будет отправлено им по очереди в цикле.
- Временная метка вводится с помощью запроса на вставку, который вы используете, нет связи между
timestamp
и mail sent time
, этой меткой времени, которую вы создали для своих собственных журналов, чтобы вы могли проверить.
Будет определенная разница для уверенности i: e 10 секунд, она также может быть меньше или больше, в зависимости от времени, которое сервер берет на отправку электронной почты и обрабатывает запрос на вставку.
Каждый запрос будет запущен, и отметка времени будет вставлена в соответствии с временем в этот момент (время сервера).