Задания 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 секунд, она также может быть меньше или больше, в зависимости от времени, которое сервер берет на отправку электронной почты и обрабатывает запрос на вставку.

Каждый запрос будет запущен, и отметка времени будет вставлена ​​в соответствии с временем в этот момент (время сервера).