WordPin revisando el cron de WordPress que no ejecuta las tareas programadas

El cron de WordPress que nunca se ejecutaba · WordPin 013

🎧 Escuchar: El cron de WordPress que nunca se ejecutaba · WordPin 013

La agenda cultural tenía un funcionamiento bastante predecible. Cada semana entraban nuevas entradas de eventos programadas con antelación, el sitemap se regeneraba solo y los procesos internos de limpieza corrían sin que nadie tuviera que tocar nada. Era uno de esos sitios que, en apariencia, se mantenían solos. Hasta que dejaron de hacerlo.

El sitio respondía con normalidad. Las páginas cargaban, el admin funcionaba, no había errores visibles en pantalla. Pero algo en la cadena de procesos automáticos había dejado de girar. La pregunta era si el problema estaba en WordPress, en algún plugin, en el servidor, o en la combinación de los tres.

imagen que representa el archivo 013 como abierto
Ficha del archivo Nº: 013

Operario: WordPin

Archivo del caso: El cron de WordPress que nunca se ejecutaba

Empresa o negocio: Agenda cultural con eventos programados

Archivado en: Configuración de WordPress

Nivel: Intermedio

El cron de WordPress y los procesos que nadie veía ejecutarse

El primer síntoma llegó sin alerta visible. Una entrada programada para publicarse el jueves seguía en estado programado el viernes por la tarde. Nadie la había tocado. Podría ser un olvido, un fallo al guardar el estado. Pero dos días después apareció otro evento en la misma situación, y el cron de WordPress empezó a figurar como sospechoso. No de forma definitiva. Solo como una posibilidad entre varias.

Lo primero que revisé fue el plugin de sitemap. La agenda usaba un generador automático que debería reconstruir el índice cada vez que se publicaba contenido nuevo. Al entrar en su configuración, todo parecía correcto: programación activa, frecuencia definida, sin errores visibles en el panel. La última ejecución registrada por el plugin tenía fecha de varios días atrás, pero eso podía explicarse por la falta de publicaciones recientes. O eso parecía.

Para tener más contexto, revisé los logs del servidor buscando peticiones al endpoint del sitemap. El archivo se estaba sirviendo sin error, lo que me hizo dudar un momento: si el sitemap respondía, ¿dónde estaba el fallo? Al comparar el contenido del sitemap con las URLs realmente publicadas en WordPress, la diferencia era clara. Varias entradas nuevas no aparecían. El archivo se servía, sí, pero con datos de hace días. La regeneración no estaba ocurriendo.

El sospechoso obvio era el plugin. Pero antes de apuntarle directamente revisé si había algún conflicto con otro plugin activo que pudiera estar bloqueando su ejecución. Deshabilité temporalmente los plugins de caché y de seguridad, forzé una publicación de prueba y esperé. El sitemap seguía sin actualizarse. Eso me sacó al plugin de la lista de culpables principales: el problema no estaba en su lógica interna, sino en algo que impedía que se llamara en el momento correcto.

Un sitio que cargaba bien y aun así entregaba respuestas viejas

La segunda hipótesis apuntó a la caché. El hosting tenía caché de página activa a nivel servidor, y era plausible que estuviera sirviendo versiones antiguas tanto del sitemap como del contenido del admin. Si la caché no se purgaba al publicar, todo podría parecer roto sin que WordPress tuviera la culpa directa.

Probé con bypass de caché añadiendo un parámetro a las URLs, revisé las cabeceras HTTP con curl para confirmar si la respuesta venía de caché o desde WordPress directamente, y comprobé el comportamiento en un navegador en modo privado sin cookies. En todos los casos, el resultado era el mismo. Las entradas programadas seguían sin publicarse. La caché no era el origen.


curl -I https://ejemplo-agenda.com/?nocache=1

HTTP/2 200
x-cache: MISS
content-type: text/html; charset=UTF-8

La respuesta venía fresca, sin caché. El servidor no estaba ocultando nada. El contenido simplemente no estaba ahí porque WordPress no lo había publicado. Esto no encajaba con un problema de capa de entrega. Era algo anterior a eso.

Al listar los eventos del cron de WordPress con
WP-CLI
la imagen cambió bastante:


wp cron event list

+------------------------------------------+---------------------+---------------------+------------+
| hook                                     | next_run_gmt        | next_run_relative   | recurrence |
+------------------------------------------+---------------------+---------------------+------------+
| publish_future_post                      | 2024-03-14 09:00:02 | 2 days ago          | -          |
| wp_scheduled_auto_draft_delete           | 2024-03-13 08:30:00 | 3 days ago          | -          |
| wp_update_plugins                        | 2024-03-12 14:00:00 | 4 days ago          | daily      |
| sitemap_generate                         | 2024-03-11 10:00:00 | 5 days ago          | daily      |
+------------------------------------------+---------------------+---------------------+------------+

La columna next_run_relative lo decía todo. Había tareas con fecha de ejecución vencida de hace días, algunas de hace casi una semana. No era un retraso puntual. Era una cola paralizada. Los eventos estaban registrados correctamente en WordPress, con sus horarios definidos. Pero nadie los estaba llamando.

Lo que el sistema de tareas no ejecutaba por sí solo

El cron de WordPress no es un cron real. Funciona como un pseudo-cron: cuando alguien visita el sitio, WordPress comprueba si hay tareas pendientes y, si las hay, intenta ejecutarlas en segundo plano. El mecanismo tiene sentido en sitios con tráfico constante. Pero en una agenda cultural con picos de visitas irregulares y periodos de baja afluencia, ese modelo tiene un problema estructural: si no hay visitas, no hay ejecuciones.

La evidencia que lo confirmó fue doble. Por un lado, el listado de WP-CLI mostraba eventos vencidos acumulados durante exactamente los periodos de menor tráfico del sitio. Por otro, al revisar los logs del servidor buscando peticiones a wp-cron.php, aparecían llamadas esporádicas y muy separadas en el tiempo, sin ningún patrón regular. Las tareas estaban ahí, esperando ser invocadas. Pero la invocación dependía de que alguien cargara una página, y en los momentos clave nadie lo hacía.

El impacto era concreto. Las publicaciones programadas para coincidir con fechas de eventos culturales llegaban tarde o directamente no se publicaban. El sitemap se regeneraba con retraso, lo que afectaba a la indexación de contenido nuevo. Y procesos internos como la limpieza de borradores automáticos o la verificación de actualizaciones quedaban en espera indefinida. Un error parcial suele ser más peligroso que una caída total, porque deja demasiadas cosas funcionando.

Con
WP Crontrol
confirmé visualmente el estado de la cola: varias tareas aparecían con tiempos de próxima ejecución en el pasado, sin señal de haber corrido en ningún momento reciente. Algunas llevaban más de 72 horas vencidas.

Desconectar el pseudo-cron para que el cron real pudiera tomar el control

La primera idea que surgió fue forzar la ejecución manual de los eventos atrasados con WP-CLI para limpiar la cola y ver si el sistema se recuperaba solo. Era una opción rápida, pero no resolvía el problema de fondo: si el pseudo-cron seguía siendo el único mecanismo, el atasco volvería en cuanto el tráfico bajara otra vez.

La solución real pasaba por dos pasos. Primero, añadir en wp-config.php la constante que desactiva el pseudo-cron interno de WordPress:


define('DISABLE_WP_CRON', true);

Esto evita que WordPress intente ejecutar tareas en cada visita, eliminando el comportamiento errático y la carga adicional que genera en sitios con tráfico irregular. Pero desactivarlo sin un sustituto real deja el sistema completamente sin ejecución de tareas, lo que es peor que el estado anterior. El riesgo de hacerlo mal estaba en ese hueco: si la constante se activaba sin que el cron de servidor estuviera listo, todas las tareas quedarían indefinidamente bloqueadas.

Encadenar los dos pasos sin dejar la cola desatendida

El segundo paso fue configurar un cron real a nivel servidor desde cPanel, apuntando directamente a wp-cron.php con una frecuencia de un minuto. Así WordPress podría ejecutar sus tareas con independencia del tráfico:


* * * * * php /home/usuario/public_html/wp-cron.php > /dev/null 2>&1

La secuencia correcta era: primero confirmar que el cron de servidor estaba activo y ejecutándose, después añadir DISABLE_WP_CRON. No al revés. Una vez activado el cron real, esperé unos minutos y volví a listar los eventos con WP-CLI. Las fechas de próxima ejecución empezaron a actualizarse. Las tareas empezaron a ejecutarse de nuevo con el cron real. La entrada de prueba que había dejado en estado programado se publicó sola, sin intervención manual.

Para validar que el cron de servidor estaba llamando a wp-cron.php de forma consistente, revisé los logs del servidor durante las siguientes horas. Las peticiones aparecían con regularidad cada minuto, independientemente de si había tráfico real en el sitio o no. El mecanismo ya no dependía de las visitas.

También aproveché para ejecutar manualmente los eventos que habían quedado atascados durante el periodo de fallo:


wp cron event run --due-now

Eso ejecutó los eventos que habían quedado vencidos y dejó el sistema en un estado conocido. El sitemap se regeneró, las publicaciones programadas pendientes aparecieron en el frontal, y los procesos de mantenimiento interno volvieron a correr con normalidad.

archivo 013 de WordPin marcado como completado

💡 Qué he aprendido

Lo que más me quedó de este caso no es la solución técnica, que es conocida, sino lo fácil que es asumir que el cron de WordPress funciona bien porque nadie se ha quejado de él. En sitios con tráfico alto y constante, el pseudo-cron es invisible porque siempre hay visitas que lo disparan. En sitios con tráfico irregular, el fallo también es invisible, pero por la razón opuesta: nadie nota que las tareas no corren porque el sitio sigue respondiendo con normalidad.

Este caso me confirmó que la diferencia entre un cron fiable y uno que depende del azar no se ve en el panel de WordPress. Se ve en la cola de tareas vencidas, en los logs del servidor y en la comparación entre lo que debería haberse ejecutado y lo que realmente se ejecutó. Antes de dar por válido el sistema de tareas en cualquier instalación, ahora reviso el estado real de la cola con WP-CLI. No basta con que los eventos estén registrados.

También aprendí a encadenar bien los dos pasos de la solución. Desactivar el pseudo-cron antes de tener el cron de servidor activo crea un vacío que puede agravar el problema. El orden importa, y en este caso el orden era la mitad de la solución.

Cuaderno de WordPin

Forense WordPress

Archivo Nº 013: El cron de WordPress que nunca se ejecutaba

🧩 Notas técnicas

⬋⬋

Una agenda cultural con tráfico irregular presentaba fallos silenciosos en sus procesos automáticos: publicaciones programadas sin publicar, sitemap sin regenerar y tareas de mantenimiento acumuladas. El sitio respondía con normalidad, lo que retrasó la detección.

La causa era estructural: WP-Cron utiliza las visitas al sitio para comprobar y lanzar tareas, y en periodos de baja afluencia los eventos quedaban pendientes indefinidamente. La cola llegó a acumular tareas con más de cinco días de retraso. La solución combinó la desactivación del pseudo-cron y la configuración de un cron de WordPress real a nivel servidor.

🔎 Pistas detectadas

⬋⬋

  • Publicaciones en estado programado que no se publicaban en su fecha y hora establecidas.
  • Sitemap con contenido desfasado respecto a las URLs realmente publicadas en WordPress.
  • Eventos cron con next_run_relative vencida de días visibles en la salida de WP-CLI.
  • Peticiones a wp-cron.php en los logs del servidor aparecían de forma esporádica y sin patrón regular.
  • Los fallos coincidían con los periodos de menor tráfico del sitio, sin afectar a la disponibilidad general.

🚫 Errores en WordPress detectados

⬋⬋

  • WP-Cron sin cron real de respaldo: el pseudo-cron de este sitio dependía de las visitas para dispararse, lo que lo hacía infiable en sitios con visitas irregulares.
  • Cola de tareas vencida sin supervisión: los eventos acumulados no generaban ningún aviso en el panel, lo que ocultó el problema durante días.
  • Tareas de publicación programada bloqueadas: entradas marcadas para publicarse en fechas concretas permanecían en estado programado porque el hook publish_future_post nunca se disparaba.
  • Regeneración de sitemap detenida: el plugin de sitemap funcionaba correctamente pero dependía del cron para ejecutarse; al no recibir la llamada, el índice no se actualizaba.
  • Procesos de mantenimiento interno sin ejecutar: tareas como la eliminación de borradores automáticos o la verificación de actualizaciones llevaban días en espera sin procesar.

📘 Glosario de WordPress

⬋⬋

  • WP-Cron: sistema de tareas programadas de WordPress que utiliza las visitas al sitio para comprobar y lanzar las tareas pendientes, sin depender de un cron real del servidor.
  • DISABLE_WP_CRON: constante en wp-config.php que desactiva el pseudo-cron interno para que las tareas las gestione un cron externo real.
  • wp-cron.php: archivo de WordPress que contiene la lógica de ejecución de tareas programadas; puede llamarse desde un crontab del servidor.
  • Cola de eventos cron: lista interna de tareas pendientes en WordPress con su hook, frecuencia y próxima fecha de ejecución prevista.
  • publish_future_post: hook de WordPress que se encarga de cambiar el estado de una entrada con post_status = future a publicada en la fecha y hora definidas.

📏 Mini guía práctica

⬋⬋

  1. Comprueba el estado real de la cola de tareas con wp cron event list y observa si hay eventos con fecha de ejecución vencida de horas o días.
  2. Revisa los logs del servidor buscando peticiones a wp-cron.php y verifica si aparecen con regularidad o de forma esporádica.
  3. Configura un cron real en el servidor apuntando a wp-cron.php con una frecuencia de un minuto antes de tocar nada en WordPress.
  4. Añade define('DISABLE_WP_CRON', true); en wp-config.php solo después de confirmar que el cron de servidor ya está activo y ejecutándose.
  5. Ejecuta los eventos vencidos con wp cron event run --due-now y valida que las tareas críticas se procesan correctamente tras el cambio.

Comparte el conocimiento. Comparte la historia

Expedientes y Archivos

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Respetamos tu privacidad. Los datos que proporciones se utilizarán únicamente para gestionar y mostrar tu comentario, así como para prevenir el uso indebido o el spam. Puedes consultar más información en nuestra política de privacidad.

Subir