Indexers de Magento: atascados, inválidos o silenciosamente incorrectos

Indexers de Magento: atascados, inválidos o silenciosamente incorrectos

El aviso casi nunca es «nuestros indexers están rotos». Es «este producto no sale en la categoría», o «el precio del sitio no coincide con el admin», o «la búsqueda lo encuentra pero la categoría no». Alguien vuelve a guardar el producto, aparece, y todo el mundo sigue adelante sin preguntarse por qué hizo falta un guardado manual.

La indexación es donde viven muchos de los fallos silenciosos de Magento, porque cuando falla la tienda sigue sirviendo páginas. Solo que sirve las equivocadas.

Para qué sirven los indexers en realidad

Magento guarda los datos de producto en EAV: atributos repartidos en tablas separadas según su tipo de dato. Leer una página de categoría directamente de esa estructura significaría decenas de joins por producto, así que en su lugar Magento precalcula tablas planas optimizadas para lectura, y los indexers son lo que mantiene esas tablas sincronizadas con los datos de origen.

Hay alrededor de una docena. Los que causan problemas visibles:

  • Category Products y Product Categories: qué productos pertenecen a qué categoría. Este es el que está detrás de «el producto no está en la categoría».
  • Product Price: precios calculados, incluidos los precios por nivel y los especiales. Detrás de «el precio está mal».
  • Stock: cantidad vendible.
  • Catalog Rule Product: qué reglas de precio de catálogo se aplican a qué.
  • Catalog Search: lo que se envía a OpenSearch.

Cuando uno de estos está desactualizado, la tienda sirve la última versión buena que tiene. Sin error, sin aviso, sin 500. La página se renderiza perfectamente y el contenido está desfasado.

Dos modos, y el que importa

Cada indexer funciona en uno de dos modos.

Update on Save reindexa las filas afectadas durante el propio guardado. Simple, inmediato, y hace más lento cada guardado del admin, a veces drásticamente. Una importación masiva con este modo activado puede tardar horas, porque cada fila dispara trabajo de indexación.

Update by Schedule escribe los IDs de entidad cambiados en una tabla de changelog y deja que el cron los procese por lotes. Los guardados siguen siendo rápidos y la indexación ocurre en segundo plano.

Para cualquier tienda con un catálogo real, Update by Schedule es la respuesta correcta. Compruebe qué tiene:

bin/magento indexer:show-mode

La consecuencia importante es que Update by Schedule depende por completo del cron. El cron se para, la indexación se para, y nada lo anuncia. Esta es la versión más habitual del problema con diferencia, y por eso la comprobación del cron de más abajo va antes que cualquier otra cosa.

El mecanismo, brevemente

Cuando un indexer se pasa a Update by Schedule, Magento crea triggers de base de datos sobre las tablas de origen y una tabla de changelog llamada <indexer>_cl. Un cambio en un producto escribe su ID en catalog_category_product_cl. El cron lee las filas nuevas desde la última versión procesada, reindexa esos IDs y avanza el puntero en mview_state.

Tres cosas pueden fallar ahí, y producen síntomas distintos:

  • El cron no está corriendo. Las filas se acumulan en el changelog y nada las consume. El índice está desactualizado y cada vez más.
  • El puntero está mal o faltan los triggers. Los cambios no se registran, o se registran y nunca se leen. El changelog crece sin límite.
  • mview_state está atascado en working. Una ejecución anterior murió a medias. El cron la ve como si siguiera en marcha y nunca arranca otra.

Averiguar cuál de ellos tiene

Empiece aquí, en este orden.

1. ¿Qué dicen los indexers?

bin/magento indexer:status

Ready está bien. Reindex required significa inválido y a la espera. Processing en cada ejecución, o durante horas, significa que algo está atascado.

2. ¿El cron está corriendo de verdad?

SELECT job_code, status, executed_at, finished_at
FROM cron_schedule
WHERE status = 'success'
ORDER BY finished_at DESC
LIMIT 10;

Si la fila correcta más reciente tiene horas de antigüedad, esa es la respuesta y todo lo que sigue es un síntoma de ello. Compruebe también que la tabla no se ha llenado de filas pending que nunca se ejecutaron, y que no es enorme: un cron_schedule sin limpiar con millones de filas se convierte en un problema por sí mismo.

3. ¿Cómo de grandes son las tablas de changelog?

SELECT table_name, table_rows
FROM information_schema.tables
WHERE table_schema = DATABASE() AND table_name LIKE '%_cl'
ORDER BY table_rows DESC;

Unos miles de filas es normal en una tienda con actividad. Millones significa que no se están consumiendo. Una tabla de changelog que ha crecido hasta los gigabytes es una razón habitual de que un reindex arranque y nunca termine: cada ejecución intenta procesar un retraso enorme y agota el tiempo antes de poder avanzar el puntero, así que el retraso tiene el mismo tamaño la próxima vez.

4. ¿Están los triggers?

SHOW TRIGGERS LIKE 'catalog_product_entity';

Que falten triggers en un indexer configurado en Update by Schedule significa que los cambios nunca se registran. Esto pasa tras restaurar una base de datos desde un volcado que no incluía los triggers, un accidente lo bastante común como para comprobarlo de forma específica después de cualquier migración.

5. ¿Hay algo atascado en working?

SELECT * FROM mview_state;

Una fila en working con un updated antiguo es una ejecución muerta que bloquea todas las siguientes.

Arreglarlo

Las soluciones dependen de la causa, que es la razón de diagnosticar primero. Reindexar todo es el reflejo, y normalmente solo esconde el problema durante un día.

Si el cron no está corriendo, arregle eso. Nada más importa hasta que lo esté, y una vez que lo esté, el retraso puede despejarse solo.

Si un changelog ha crecido hasta ser inmanejable, el enfoque habitual es resetear el indexer afectado y dejar que se reconstruya, lo que trunca el changelog y hace un reindex completo. Hágalo en una ventana de mantenimiento en un catálogo grande, porque un reindex completo en una tienda grande no es rápido.

Si mview_state está atascado, hay que limpiar la fila working obsoleta antes de que el cron arranque una ejecución nueva.

Si faltan los triggers, pasar el indexer a Update on Save y de vuelta a Update by Schedule los vuelve a crear.

En todos los casos: haga primero una copia de seguridad de la base de datos, y hágalo antes en staging si hay un entorno de staging. Estas operaciones tocan las tablas de las que lee la tienda.

La parte que debería preocuparle

Nada de esto hace saltar una alarma.

Un índice desactualizado no lanza un error, no aparece en el admin como un aviso que alguien vaya a ver y no rompe ninguna página. Los productos dejan de aparecer en una categoría en silencio. Un precio deja de coincidir en silencio. La tienda sigue aceptando pedidos de todo lo que sigue visible, y nadie se entera hasta que un cliente pregunta por un producto que no encuentra, o alguien se fija en los números.

Lo que significa que lo útil no es saber cómo arreglar esto: es tener algo que lo compruebe. El estado de los indexers y la antigüedad de la fila correcta más reciente del cron son dos consultas. Cualquier cosa que las ejecute de forma programada y se queje vale más que el tiempo que cuesta montarla, y la mayoría de las tiendas no tiene nada parecido.

Esa comprobación es parte de lo que compra un retainer, y es una de las primeras cosas que miramos en un diagnóstico gratuito de su tienda, porque un indexer desactualizado es invisible desde fuera de la tienda, y está costando dinero todo el tiempo que está mal.

Si esto le está pasando ahora en su tienda, cuéntenos lo que está viendo y le diremos cuál de las cinco comprobaciones de arriba ejecutar primero.

Preguntas frecuentes

¿Por qué mis productos no aparecen en una categoría de Magento?

La mayoría de las veces el índice de productos por categoría está desactualizado o inválido, así que la tienda sirve una vista antigua de qué productos pertenecen a cada sitio. Compruebe primero el estado de los indexers con bin/magento indexer:status antes de mirar la configuración de la propia categoría: si el índice es inválido, la configuración de la categoría probablemente está bien y simplemente no se está aplicando.

¿Los indexers de Magento deberían estar en Update on Save o en Update by Schedule?

En Update by Schedule, para cualquier tienda con un catálogo más que trivial. Update on Save reindexa durante el propio guardado, lo que hace lentos los guardados del admin y extremadamente lentas las importaciones masivas. Update by Schedule registra el cambio y deja que el cron lo procese por lotes. El intercambio es que depende de que el cron esté corriendo de verdad.

¿Qué son las tablas de changelog de Magento y por qué crecen?

Cada indexer en Update by Schedule tiene una tabla cl que registra qué IDs de entidad cambiaron. El cron la lee, reindexa esas filas y avanza un puntero de versión. Si las suscripciones o el puntero se desincronizan, las filas dejan de consumirse y la tabla crece sin límite, que es una causa habitual de un reindex que nunca termina.

¿Cómo sé si el cron de Magento está corriendo de verdad?

Consulte la tabla cron_schedule buscando filas recientes con estado success. Si la fila correcta más reciente tiene horas de antigüedad, el cron no está funcionando bien, y todos los indexers en Update by Schedule han dejado de actualizarse con él.

Trabaje con Emyrix

¿Quiere saber cómo está su propia tienda?

Envíenos la URL y un ingeniero de Magento la revisará (versión y estado de parches, velocidad, cache, indexación, checkout) y después le enviará por correo lo que encontró. Gratis, y sin ninguna obligación.