WP Cron No Se Ejecuta Cuando El Tiempo Transcurre

27 mar 2013, 17:12:16
Vistas: 22K
Votos: 19

El objetivo

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

El problema

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 a schedule-event:

schedule_event( $_SESSION['insert_id'] ); // la variable $_SESSION contiene un INT

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

Lo que intenté

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

Pantalla de Core Control mostrando trabajos cron programados

Después de un par de cambios logré que funcionaran bastante bien y, mejor aún, cuando presiono "Ejecutar ahora", realmente recibo 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é podría estar mal con este código? Debo decir que esta es mi primera vez usando WP Cron.

Intenté más

Después del comentario de vancoder decidí probar si el código funciona si pongo el siguiente código directamente en el 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 tiene que ir a otra página antes de que este código se ejecute. Pero por otro lado, esto tampoco funciona, así que ese no sería mi primer problema...

5
Comentarios

¿Dónde y cómo se ejecuta schedule_event( $_SESSION['insert_id'] );?

vancoder vancoder
27 mar 2013 18:23:31

Un shortcode incluye un archivo separado (con un formulario) en una página, cuando ese formulario se envía la página se recarga, el mismo archivo luego ejecuta el schedule_event( ), digamos al principio del archivo incluido cargado por el shortcode.

Mike Madern Mike Madern
28 mar 2013 09:48:50

¿Funciona algún cron? ¿wp_version_check etc?

vancoder vancoder
28 mar 2013 19:28:37

No pude hacer que ningún cron funcionara. ¿Cuál podría ser el problema?

Mike Madern Mike Madern
29 mar 2013 10:09:15

Para confirmar - ¿incluso los cron jobs principales fallan?

vancoder vancoder
4 abr 2013 19:44:42
Todas las respuestas a la pregunta 6
8
18

Primero, define tus programaciones personalizadas de cron jobs.

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

public function cron_schedules($schedules){
    $prefix = 'cron_';// Evitar conflicto con otros cron jobs. Ejemplo de referencia: cron_30_mins
    $schedule_options = array(
        '30_mins' => array(
            'display' => '30 Minutos',
            'interval' => '1800'
        ),
        '1_hours' => array(
            'display' => 'Hora',
            'interval' => '3600'
        ),
        '2_hours' => array(
            'display' => '2 Horas',
            'interval' => '7200'
        )
    );
    /* Añade cada programación personalizada al sistema de cron jobs. */
    foreach($schedule_options as $schedule_key => $schedule){
        $schedules[$prefix.$schedule_key] = array(
            'interval' => $schedule['interval'],
            'display' => __('Cada '.$schedule['display'])
        );
     }
     return $schedules;
}

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

Aquí tienes un ejemplo de fragmento de código que llama a un método personalizado de una clase:

$schedule = $this->schedule_task(array(
    'timestamp' => current_time('timestamp'), // Determina cuándo programar la tarea.
    'recurrence' => 'cron_30_mins',// Elige una de las programaciones establecidas anteriormente.
    'hook' => 'custom_imap_import'// Establece el nombre de tu tarea cron.
));

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

private function schedule_task($task){
    /* Debe tener información de la tarea. */
    if(!$task){
        return false;
    }
    /* Establece la lista de claves requeridas para la tarea. */
    $required_keys = array(
        'timestamp',
        'recurrence',
        'hook'
    );
    /* Verifica que exista la información necesaria de la tarea. */
    $missing_keys = array();
    foreach($required_keys as $key){
        if(!array_key_exists($key, $task)){
            $missing_keys[] = $key;
        }
    }
    /* Comprueba si faltan claves. */
    if(!empty($missing_keys)){
        return false;
    }
    /* La tarea no debe estar ya programada. */
    if(wp_next_scheduled($task['hook'])){
        wp_clear_scheduled_hook($task['hook']);
    }
    /* Programa la tarea para que se ejecute. */
    wp_schedule_event($task['timestamp'], $task['recurrence'], $task['hook']);
    return true;
}

Ahora, todo lo que necesitas hacer es llamar al nombre de tu 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(){
    // .... Haz algo cuando se active el cron ....
}

Así que en este ejemplo, $this->do_imap_import(); se llama cada 30 minutos (asumiendo que tienes suficiente tráfico en tu sitio web).


Notas

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

Ejemplo: Si programaste una tarea en intervalos de 30 minutos, pero nadie visita tu sitio durante 4 horas, tu cron job no se activará hasta que un visitante llegue a tu sitio 4 horas después. Si realmente necesitas que tu tarea se active cada 30 minutos, se recomienda configurar un cron job legítimo a través de tu proveedor de alojamiento web para visitar tu sitio en los intervalos deseados.

¡Los cron jobs de WordPress no hacen que tu sitio web sea lento!

Quizás estés pensando qué pasa si el script cron tarda mucho tiempo en ejecutarse, ¿los visitantes tendrán que esperar hasta que el script se ejecute? ¡No! ¿Cómo es eso posible? Si miras el archivo wp-cron.php encontrarás una línea

ignore_user_abort(true);

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

Si miras el archivo wp-includes/cron.php encontrarás 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 que WordPress esperará solo 0.01 segundos para activar la ejecución y luego abortará, pero como has establecido ignore_user_abort en true, el script seguirá ejecutándose. Esta funcionalidad es una gran ventaja para ejecutar scripts grandes en los cron jobs de WordPress.

Funciones disponibles para ayuda:

4 abr 2013 17:22:45
Comentarios

Esta es una respuesta notablemente exhaustiva, que hasta donde puedo ver, no aborda la pregunta real: por qué fallan todas las tareas programadas (incluidas las tareas principales).

vancoder vancoder
4 abr 2013 19:40:42

Esta respuesta tiene como objetivo guiar al usuario en la dirección correcta para comprender y programar correctamente las tareas cron de WordPress.

Michael Ecklund Michael Ecklund
4 abr 2013 20:07:54

Esto definitivamente me ayudó mucho a entender las programaciones cron con WordPress

Mike Madern Mike Madern
9 abr 2013 16:08:17

Miguel, deberías responder más seguido. Excelente aporte +1

kaiser kaiser
3 oct 2013 05:36:35

¿En qué momento deberías hacer "add_action('custom_imap_import', array($this, 'do_imap_import'))", asumiendo una clase de plugin? ¿En el constructor?

codecowboy codecowboy
11 oct 2013 20:25:13

@codecowboy Sí, o en algún lugar donde pueda cargarse cuando el cron esté listo para ejecutarse.

Michael Ecklund Michael Ecklund
21 oct 2013 23:12:25

WordPress Core ya proporciona un intervalo hourly, por lo que no necesitas usar 1_hours.

Ian Dunn Ian Dunn
25 nov 2014 03:06:29

Creo que WP_Cron utiliza GMT internamente, como el resto de WordPress, por lo que sería mejor programar el primer evento en time() en lugar de current_time().

Ian Dunn Ian Dunn
25 nov 2014 03:09:08
Mostrar los 3 comentarios restantes
2

Primero, ¿puedes confirmar que no tienes ningún plugin de caché activado? Los plugins de caché pueden interferir con los trabajos cron porque tus visitantes no reciben una página en vivo sino una versión en caché de tu página.

Si tienes un plugin de caché activado, puedes elegir una de tus páginas, agregar una exclusión en la configuración de tu plugin de caché para esa página específica, de modo que nunca se almacene en caché.

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

¡Espero que esto ayude!

5 abr 2013 17:59:13
Comentarios

¡Tengo un plugin de caché activado! W3 Total Cache para ser precisos

Mike Madern Mike Madern
9 abr 2013 16:04:55

Hay opciones para desactivar toda la caché, pero no veo una opción para habilitar/deshabilitar la caché solo para plugins

user1019042 user1019042
2 nov 2020 21:53:06
1

El Cron de WordPress te permite programar tareas, pero solo se ejecutarán si hay una solicitud hecha al sitio. Por cada solicitud que WordPress recibe, verificará si hay trabajos cron para procesar y, de ser así, enviará una solicitud asíncrona a /wp-cron.php?doing_wp_cron para procesar el trabajo. Si el tiempo programado de inicio de un trabajo pasa sin que haya una solicitud, entonces el proceso cron no se iniciará.

Dado que puedes ver y ejecutar tus trabajos programados, es posible que no haya solicitudes que activen el inicio del trabajo cron, especialmente si estás usando un plugin de caché. La mejor opción para delegar esto a un horario más regular es desactivar la verificación predeterminada en WordPress y usar crontab.

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

// Desactivar la verificación predeterminada de trabajos cron de WordPress en las cargas de página
define( 'DISABLE_WP_CRON', true );

Luego, crea una tarea para obtener la página wp-cron.php una vez por minuto y procesar cualquier trabajo en el backend. Desde la línea de comandos, ingresa crontab -e y luego agrega una línea similar a la siguiente:

*/1 * * * * /usr/bin/curl --silent http://ejemplo.com/wp-cron.php?doing_wp_cron=$(date +\%s.\%N) >/dev/null 
6 abr 2013 03:43:17
Comentarios

Si no asignas un valor a doing_wp_cron, es muy probable que esto cause que los trabajos se ejecuten dos veces en ocasiones. Usa doing_wp_cron=$(date +\%s.\%N) para prevenir eso.

Alexander Garden Alexander Garden
10 nov 2013 13:04:14
0

Para cualquiera que esté protegiendo su sitio (de desarrollo) del acceso público, la Autenticación HTTP puede ser la causa de que WP Cron no funcione.

Por si puede ayudar a alguien, aquí está mi lista de cosas que hice antes de identificar y comprender los requisitos de WP Cron:

  • Noté que los eventos se programaban correctamente y podían ejecutarse usando WP-CLI.
  • Y también noté que acceder a /wp-cron.php?doing_wp_cron a través del navegador sí activaba las ejecuciones, como se sugiere en ej. 13625.
  • La documentación oficial fue leída.
  • Me aseguré de que DISABLE_WP_CRON no estuviera configurado.
  • Y aprendí que ALTERNATE_WP_CRON era una solución temporal efectiva, aunque insatisfactoria.
  • Para descartar errores de regresión, probé instalando un par de versiones antiguas de WordPress.
  • Todos los plugins fueron desactivados y el tema cambiado al predeterminado, para aislar el problema.
  • La gente mencionó el término loopbacks, pero al no tener errores o advertencias relacionadas lo consideré irrelevante.
  • Finalmente, encontré una pregunta con una respuesta que realmente explica cómo depurar cron.
  • Una vez que adjunté Xdebug a wp_cron(), pude ver que la ejecución terminaba en wp_remote_post(), lo cual claramente fallaba.

Cuando supe qué buscar, encontré este excelente artículo sobre las causas de los problemas con WP Cron de Jeff Starr. Al final del mismo, enlaza a su plugin wp-cron-http-auth.

17 jun 2020 10:37:19
1

Verifica que DISABLE_WP_CRON no esté configurado en tu archivo de configuración.

Si eso no funciona, intenta desactivar todos los plugins (excepto core control, aunque yo usaría wp-crontrol) y comprueba si tus trabajos principales funcionan. Si es así, estás experimentando interferencia de algún plugin.

De manera similar, prueba cambiar a un tema estándar de la serie twentysomething.

Si nada de esto hace diferencia, lo más probable es que sea un problema del alojamiento.

4 abr 2013 20:19:23
Comentarios

No tengo DISABLE_WP_CRON configurado en mi wp-config.php, probaré más cosas y volveré más tarde

Mike Madern Mike Madern
9 abr 2013 16:07:21
0

Verifica cualquier plugin que oculte WordPress.

¿Cómo comprobar si este es el problema?

  1. Navega a http(s)://tusitio.com/wp-cron.php Deberías ver una página completamente vacía.
  2. Además, debes ver en un gestor de tareas programadas una hora en "Próxima ejecución": Tarea cron programada - si wp-cron.php funciona correctamente (no solo el texto "En cola" - sino una hora específica - para algunas entradas "En cola" está bien en ciertos casos, pero si es lo único que ves -> tu cron no funciona).

+1. No confíes en plugins que "verifican si cron está funcionando" - por ejemplo, el plugin WP Cron status checker mostró que cron funcionaba. Pero en realidad no era así. Lo que sea que muestre - ¡cree en lo que ves y no en este plugin!

Conclusión: Si obtienes un error 404, entonces desactiva a) no solo plugins de caché como otros sugieren b) sino también cualquier plugin que oculte WordPress.

16 abr 2019 00:45:30