WP Cron no se ejecuta cuando transcurre el tiempo

16

La meta

Quiero usar wp_schedule_single_event( )para ejecutar un solo evento que me envíe un correo electrónico 8 minutos después de que el usuario envíe un formulario.

La cuestión

El siguiente código está en mi functions.php:

function nkapi_send_to_system( $args ) {
  wp_mail( 'xxx', 'xxx', $args );
}

add_action( 'nkapi_send', 'nkapi_send_to_system' );

function schedule_event( $id ) {
  wp_schedule_single_event( current_time( 'timestamp' ) + 480, 'nkapi_send', array( $id ) );
}

Y el siguiente código se usa para llamar schedule-event:

schedule_event( $_SESSION['insert_id'] ); // the $_SESSION var contains an INT

Después de esperar más de 8 minutos, no había un correo electrónico en mi bandeja de entrada.

Lo que probé

Con el complemento Core Control es posible ver qué trabajos cron están programados.

Pantalla de control central

Después de un par de cambios logré corregirlos, y mejor, cuando presioné "Ejecutar ahora", recibí un correo electrónico en mi bandeja de entrada.

Pero por qué los cron no se ejecutan cuando visito mi sitio después de 8 minutos. ¿Qué es lo que posiblemente está mal con este código? Tengo que decir que esta es la primera vez que uso WP Cron.

Intenté más

Después del comentario de vancoder id decidió probar si el código funciona si pongo el siguiente código directamente en functions.php:

function schedule_event( $id ) {
  wp_schedule_single_event( time(), 'nkapi_send', array( $id ) );
}

if ( isset( $_SESSION['insert_id'] ) ) {
  if ( ! array_key_exists( 'insert_scheduled', $_SESSION ) || $_SESSION['insert_scheduled'] != $_SESSION['insert_id'] ) {
    schedule_event( $_SESSION['insert_id'] );
    $_SESSION['insert_scheduled'] = $_SESSION['insert_id'];
  }
}

La desventaja de este código es que el usuario debe ir a otra página antes de ejecutar este código. Pero por otro lado, esto tampoco funciona, así que ese no sería mi primer problema ...

Mike Madern
fuente
1
¿Dónde y cómo se schedule_event( $_SESSION['insert_id'] );despide?
Vancoder
Un shortcode incluye un archivo separado (con un formulario) en una página, cuando ese formulario se publica, la página se recarga, el mismo archivo ejecuta schedule_event( ), digamos, en la parte superior del archivo incluido cargado por el shortcode.
Mike Madern
¿ Funciona algún cron? wp_version_check, etc.
Vancoder
No conseguí ningún cron para trabajar. ¿Cuál podría ser el problema de eso?
Mike Madern
Para confirmar, ¿incluso los trabajos principales de cron fallan?
vancoder

Respuestas:

8

Primero, ¿puede confirmar que no tiene habilitados los complementos de almacenamiento en caché? Los complementos de almacenamiento en caché pueden interferir con los trabajos cron porque sus visitantes no reciben una página en vivo sino una versión en caché de su página.

Si tiene habilitado un complemento de almacenamiento en caché, puede elegir una de sus páginas, agregar una exclusión a la configuración del complemento de almacenamiento en caché para esa página para que nunca se almacene en caché.

Luego tendrá que crear manualmente un trabajo cron (usando cpanel si está en un entorno de alojamiento compartido o desde la terminal si es un servidor VPS / dedicado) que visitará esa página cada pocos minutos.

¡Espero que eso ayude!

WPMU-DEV Ari
fuente
¡Tengo habilitado un complemento de almacenamiento en caché! W3 Total Cache para ser precisos
Mike Madern
14

En primer lugar, defina sus horarios de trabajo cron personalizados.

add_filter('cron_schedules', array($this, 'cron_schedules'));

public function cron_schedules($schedules){
    $prefix = 'cron_';// Avoid conflict with other crons. Example Reference: cron_30_mins
    $schedule_options = array(
        '30_mins' => array(
            'display' => '30 Minutes',
            'interval' => '1800'
        ),
        '1_hours' => array(
            'display' => 'Hour',
            'interval' => '3600'
        ),
        '2_hours' => array(
            'display' => '2 Hours',
            'interval' => '7200'
        )
    );
    /* Add each custom schedule into the cron job system. */
    foreach($schedule_options as $schedule_key => $schedule){
        $schedules[$prefix.$schedule_key] = array(
            'interval' => $schedule['interval'],
            'display' => __('Every '.$schedule['display'])
        );
     }
     return $schedules;
}

Debe decidir dónde y cuándo programar realmente el evento.

Aquí hay solo un fragmento de código de ejemplo, que realiza una llamada a un método de clase personalizado:

$schedule = $this->schedule_task(array(
    'timestamp' => current_time('timestamp'), // Determine when to schedule the task.
    'recurrence' => 'cron_30_mins',// Pick one of the schedules set earlier.
    'hook' => 'custom_imap_import'// Set the name of your cron task.
));

Aquí está el código que realmente programa el evento:

private function schedule_task($task){
    /* Must have task information. */
    if(!$task){
        return false;
    }
    /* Set list of required task keys. */
    $required_keys = array(
        'timestamp',
        'recurrence',
        'hook'
    );
    /* Verify the necessary task information exists. */
    $missing_keys = array();
    foreach($required_keys as $key){
        if(!array_key_exists($key, $task)){
            $missing_keys[] = $key;
        }
    }
    /* Check for missing keys. */
    if(!empty($missing_keys)){
        return false;
    }
    /* Task must not already be scheduled. */
    if(wp_next_scheduled($task['hook'])){
        wp_clear_scheduled_hook($task['hook']);
    }
    /* Schedule the task to run. */
    wp_schedule_event($task['timestamp'], $task['recurrence'], $task['hook']);
    return true;
}

Ahora, todo lo que necesita hacer es llamar al nombre de su tarea cron personalizada. En este ejemplo, el nombre de la tarea cron es custom_imap_import.

add_action('custom_imap_import', array($this, 'do_imap_import'));

public function do_imap_import(){
    // .... Do stuff when cron is fired ....
}

Entonces, en este ejemplo, $this->do_imap_import();se llama cada 30 minutos (suponiendo que tenga suficiente tráfico a su sitio web).


Notas

Requiere una visita a la página para que su cron se active en los momentos correctos.

Ejemplo: si programó una tarea a intervalos de 30 minutos, pero nadie visita su sitio durante 4 horas, su trabajo cron no será despedido hasta que ese visitante llegue a su sitio 4 horas más tarde. Si realmente necesita que su tarea sea disparada cada 30 minutos, se recomienda configurar un trabajo cron legítimo a través de su proveedor de alojamiento web para visitar su sitio web en los intervalos deseados.

¡Los trabajos cron de WordPress no hacen que su sitio web sea lento!

Tal vez esté pensando que si el cron-script tarda mucho en ejecutarse, los visitantes tendrán que esperar hasta que se ejecute el script. No! ¿Cómo puede ser eso posible? Si miras el wp-cron.phparchivo encontrarás una línea

ignore_user_abort(true);

Es una php.iniconfiguración que establece que si deja de cargar el sitio / script, el script no dejará de ejecutarse.

Si observa el wp-includes/cron.phparchivo, encontrará una línea como esta:

wp_remote_post( $cron_url, 
array('timeout' => 0.01,
 'blocking' => false, 
 'sslverify' => apply_filters('https_local_ssl_verify', true)) );

Eso significa WordPress esperará solamente 0,01 segundos para activar la ejecución luego se abortará pero como se ha definido ignore_user_abortpara trueel guión será de ejecución. Esta funcionalidad es una gran ventaja para ejecutar scripts grandes en trabajos cron de WordPress.

Funciones disponibles para ayuda:

Michael Ecklund
fuente
66
Esta es una respuesta notablemente completa, que hasta donde puedo ver, no responde a la pregunta real, que es por qué fallan todas las tareas programadas (incluidas las tareas centrales).
vancoder
Esta respuesta es para guiar al usuario en la dirección correcta para comprender y programar las tareas cron de WordPress correctamente.
Michael Ecklund
44
Esto me ayudó mucho a comprender los horarios cron con WordPress
Mike Madern
2
Michael, deberías responder más a menudo. Great one +1
kaiser
1
Creo que WP_Cronusa GMT debajo del capó, como el resto de WP, por lo que sería mejor programar el primer evento en time()lugar de current_time().
Ian Dunn
3

WordPress Cron le permite programar tareas, pero solo se ejecutarán si se realiza una solicitud al sitio. Para cada solicitud que reciba WordPress, verificará si hay trabajos cron para procesar, y si es así, activa una solicitud /wp-cron.php?doing_wp_cronpara procesar el trabajo de forma asíncrona. Si el inicio programado de un trabajo pasa sin una solicitud, el proceso cron no se iniciará.

Dado que puede ver y ejecutar sus trabajos programados, es posible que no haya solicitudes que activen el inicio del trabajo cron, especialmente si está utilizando un complemento de almacenamiento en caché. La mejor opción para descargar esto a un horario más regular es deshabilitar la verificación predeterminada en WordPress y usarla crontab.

Primero para deshabilitar la verificación predeterminada (que puede ayudar un poco con el rendimiento del lado del cliente), agregue lo siguiente a wp-config.php:

// Disable default check for WordPress cron jobs on page loads
define( 'DISABLE_WP_CRON', true );

A continuación, cree una tarea para recuperar la wp-cron.phppágina una vez por minuto para procesar cualquier trabajo en el back-end, desde la línea de comando, ingrese crontab -ey luego agregue una línea similar a la siguiente:

*/1 * * * * /usr/bin/curl --silent http://example.com/wp-cron.php?doing_wp_cron=$(date +\%s.\%N) >/dev/null 
doble afilado
fuente
2
Si no le da un valor a doing_wp_cron, es muy probable que a veces los trabajos se ejecuten dos veces. Úselo doing_wp_cron=$(date +\%s.\%N)para evitar eso.
Alexander Garden
0

Verifique que DISABLE_WP_CRON no esté configurado en su configuración.

De lo contrario, intente deshabilitar todos los complementos (excepto el control central, aunque usaría wp-crontrol) y vea si sus trabajos principales funcionan. Si lo hacen, está experimentando interferencias de complementos en alguna parte.

Del mismo modo, intente cambiar a un tema estándar de veinteañero.

Si ninguno de estos hace alguna diferencia, es probable que sea un problema de alojamiento.

Vancoder
fuente
No me he DISABLE_WP_CRONpuesto en mi wp-config.php, intentaré más cosas y volveré más tarde
Mike Madern
0

Verifique cualquier complemento que oculte Wordpress.

¿Cómo ver si este es el problema?

  1. Navegue a http (s): //yoursite.com/wp-cron.php Debería ver una página vacía. Una completamente vacía.
  2. Además, debe ver en un administrador de trabajos cron un tiempo en "Próxima ejecución": Cron trabajo programado - si wp-cron.php funciona correctamente (no solo el texto "En cola", sino un tiempo dado, para algunas entradas "En cola" a veces está bien, pero si es lo único ves -> tu cron no funciona)

+1. No crea en ningún complemento que "verifique si cron está funcionando", por ejemplo, el complemento del verificador de estado de WP Cron ha demostrado que cron está funcionando. Pero en realidad no fue así. Lo que sea que muestre, ¡crea en tus ojos y no en este complemento!

Conclusión: si se trata de un error 404, apague a) no solo los complementos de almacenamiento en caché como otros sugieren b) sino también cualquier complemento que oculte Wordpress.

Peter Cz
fuente