Pregunta ¿Los trabajos cron de wordpress se ejecutan secuencialmente o en paralelo?


Estoy tratando de limitar el número de correos electrónicos enviados desde mi sitio web para hacer frente a las limitaciones del correo electrónico del servicio de alojamiento. Estoy usando trabajos cron y un indicador de acumular los correos electrónicos en la base de datos para verificar si el número de correos electrónicos enviados se acerca al límite máximo de correos electrónicos enviados.

La forma en que lo hago es ejecutando directamente el proceso programado y luego lo "duermo" durante un cierto período de tiempo (según su posición en la cola) y luego envío el correo electrónico e inicie sesión en la base de datos. Para explicar más a fondo el motivo por el que estoy usando tareas programadas y 'dormir', considere el siguiente escenario:

  1. Un usuario intenta registrarse en mi sitio web y espera que se le envíe un correo electrónico en breve. Por lo tanto, si se excede la cuota de minutos / correos electrónicos, debo enviar un mensaje diferente: "Nuestro servidor está ocupado, permita 'x' minutos para realizar la tarea requerida".
  2. Las solicitudes para enviar correos electrónicos se realizan a través de AJAX. Usar 'dormir' dentro del proceso en sí no es una opción porque el usuario tendrá que esperar los x minutos hasta que se haga eco del 'mensaje ocupado'.
  3. Intenté con ob_flush, flush ... etc. combinaciones para hacer eco del mensaje, entonces el servidor resuelve todo en el fondo, pero eso nunca funcionó. La llamada AJAX siempre estaba esperando que el script finalizara para hacer eco del resultado.
  4. ¡Necesito multi-threading en el lenguaje PHP de subproceso único! Como solución, utilicé trabajos cron, donde está programado que cada correo electrónico apilado se ejecute en time() (es decir, ejecute directamente el trabajo programado) que está enganchado a la misma función que envía correos electrónicos. Usando una bandera, la función sabe que la solicitud es un correo electrónico acumulado y lo deja "inactivo" hasta el tiempo requerido para restablecer la cuota de correo electrónico.

  5. El problema: si 5 personas se registraron casi al mismo tiempo (mientras todavía tenemos una pila de correo electrónico), tenemos 5 trabajos cron que deberían ejecutarse todos al mismo tiempo y luego dormir por un tiempo (el tiempo de suspensión puede diferir si la cantidad de correos electrónicos en la pila ya es mayor que la cuota de correo electrónico), luego se envían correos electrónicos. Sin embargo, cuando reviso los registros en la base de datos, encuentro que los trabajos programados se ejecutan secuencialmente y no en paralelo. A veces sucede que se dispara un trabajo cron antes de que termine el otro, pero no se activan al mismo tiempo.

Sé que los trabajos cron de wordpress no son realmente trabajos cron y se activan una vez que alguien visita el sitio web (y me aseguro de actualizar las páginas después de enviar las solicitudes de registro para que se activen todas las tareas programadas), pero parecen ser los únicos opción para mí ya que mi servidor de alojamiento no permite el acceso al servidor ni permite la programación de trabajos cron.

Aquí hay una parte del código que ejecuta lo anterior:

//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

Esto es lo que obtengo al iniciar sesión en la base de datos cuando intento enviar 10 correos electrónicos después de exceder la cuota.

MYSQL database logs

Tenga en cuenta que la marca de tiempo tiene una diferencia de 10 segundos entre cada registro y el siguiente, aunque deben dispararse todos al mismo tiempo y cada uno duerme durante 10 segundos, luego todos envían correos electrónicos en paralelo.

Entonces mi pregunta es: ¿por qué wordpress cron dispara los trabajos programados secuencialmente y no en paralelo? y cómo superar este problema?

Cualquier ayuda es muy apreciada.


11
2017-11-11 08:39


origen


Respuestas:


Como se mencionó, la instalación de un plugin cron ayudará a administrar sus crons.

Para responder a su pregunta, Wordpress usa un "cron lock" defined('DOING_CRON') y establece un transitorio $lock = get_transient('doing_cron') cuando el spawn_cron método es invocado

Entonces, si miras wp-includes/cron.php Verás que los crones de Wordpress no se ejecutan al mismo tiempo de manera predeterminada y no se ejecutarán más de una vez cada 60 segundos.

// 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;

3
2017-12-08 23:34



Si solo puede enviar uno o dos correos electrónicos a la vez, esto será difícil de resolver. Una manera más fácil de resolver esto sería probablemente hacer que WordPress use un servidor de correo electrónico SMTP que permita la frecuencia de los correos electrónicos que debe enviar. Solo basta con agregar una nueva cuenta de correo electrónico a su proveedor de alojamiento actual. Si no sabes cómo configurarlo manualmente, hay complementos que lo harán por ti.


0
2017-11-14 22:53



Como PHP se ejecuta de arriba hacia abajo, así que cuando programe un evento usando la función de evento de programación de wordpress, como se muestra a continuación:

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
}

Esta función do_this_hourly() se ejecutará según el cronograma, pero el código que escribirá dentro de esa función se ejecutará uno por uno solamente.

  1. Tomemos como ejemplo el envío de correo electrónico a 5 personas, por lo que el correo electrónico se les enviará uno por uno en un bucle.
  2. El sello de tiempo se ingresa mediante la consulta de inserción que está utilizando, no hay conexión entre el timestamp y el mail sent time, esta marca de tiempo que ha creado para sus propios registros, para que pueda verificar.

Habría alguna diferencia, por supuesto, en 10 segundos, también puede ser menor o mayor, dependiendo del tiempo que tarda el servidor en enviar correos electrónicos y procesar la consulta de inserción.

Cada consulta se activará y la marca de tiempo se insertará según la hora en ese momento (hora del servidor).


0
2017-12-07 06:50