El lunes pasado un cliente me informaba de un problema en su tienda de comercio electrónico: en ocasiones, al añadir un producto, aparecían dos en el carrito.
Lo que a priori parecía un problema de rápida solución (algún error de caché, JavaScript, etc), se acabó convirtiendo en un quebradero de cabeza que solucioné al 100 % el viernes.
Los síntomas
Lo primero era reproducir el error. Efectivamente, aunque no siempre, en la mayoría de las ocasiones, cuando entraba en la tienda desde mi navegador principal (Edge), al darle a añadir un producto, aparecían dos en el carrito.
No era un producto en concreto, pasaba con casi todos, pero no siempre.
Además, el cliente me informaba que no le pasaba en el móvil (iPhone). Siempre es importante tener la máxima información posible (navegador, dispositivo, sistema operativo, etc.).
Para complicarlo más, después de varias pruebas, veo que en Firefox tampoco sucede el problema.
Así que acotamos el problema a los navegadores de escritorio basados en Chromium (Edge, Opera, Chrome, Vivaldi…)
La plataforma en la que está la web es un VPS Vultr con stack GridPane y Relay Business + Object Cache Pro y Cloudflare para administrar diferentes reglas de seguridad, además de las de GridPane. Con este stack, el WooCommerce va rapidísimo y puede gestionar miles de conexiones sin apenas inmutarse.
Las reglas de seguridad de Cloudflare (serie de tres artículos sobre seguridad desde Cloudflare) paran unos 3.000-5.000 intentos de intromisión diarios en esta tienda.
Pero en un par de ocasiones tuvimos intentos más «insistentes», con unos 3 millones de peticiones por día, lo que al inicio hizo que la web tardase entre 1 y 3 segundos más en cargar. Pero, al implementar la regla adecuada, se atajaban todas a nivel de DNS antes de llegar al servidor y, por lo tanto, sin afectar en lo más mínimo al rendimiento del VPS. Por lo tanto, el tener Cloudflare funcionando correctamente, es de vital importancia.
Búsqueda de la solución
Aunque no voy a entrar en detalle de todas las pruebas realizadas, decir que una vez reproducido el error, quedaba atajarlo (evidente).
Lo primero a notar, es que no hay ni había ningún fallo de JavaScript en la consola del navegador, ni diferencias sustanciales en las cabeceras entre Chrome y Firefox.
Mientras añadía productos al carrito iba viendo en directo los logs desde mi ordenador gracias a la conexión remota de multitail viendo los logs de acceso y de error en consola dividida. No aparecía nada destacable con ninguno de los navegadores.
Después de pedir ayuda a algunos colegas de Codeable, me sugirieron hacer log de las peticiones:
Dicho y hecho, guardo las peticiones de añadir al carrito si vienen de mi IP:
/**
* Add to cart logging for debugging purposes.
*
* @param string $cart_item_key Item key for current cart.
* @param int $product_id Id of the product.
* @param int $quantity Quantity of the product.
* @param int $variation_id Id of the variation.
* @param array $variation Variation data.
* @param array $cart_item_data Cart item data.
*
* @return void
*/
function cl_add_to_cart_logging( $cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data ) {
if ( '83.69.83.69' === $_SERVER['REMOTE_ADDR'] ) {
$log_file = fopen( ABSPATH . 'log_cart.txt', 'a' );
$log_data = 'Date: ' . date( 'Y-m-d H:i:s:u' ) . "\n";
$log_data .= 'IP: ' . $_SERVER['REMOTE_ADDR'] . "\n";
$log_data .= 'Cart Item Key: ' . $cart_item_key . "\n";
$log_data .= 'ID Product: ' . $product_id . "\n";
$log_data .= 'Quantity: ' . $quantity . "\n";
$log_data .= 'ID Variation: ' . $variation_id . "\n";
$log_data .= 'Variation Data: ' . print_r( $variation, true ) . "\n";
$log_data .= 'Product Data: ' . print_r( $cart_item_data, true ) . "\n";
$log_data .= '-----------------------------------------------------------' . "\n\n";
fwrite( $log_file, $log_data );
fclose( $log_file );
}
}
add_action( 'woocommerce_add_to_cart', 'cl_add_to_cart_logging', 10, 6 );
Y enseguida empiezo a ver el contenido de log_cart.txt
por medio de multitail y comprobar que todo está correcto, aunque se reciben peticiones duplicadas en el mismo milisegundo para el mismo producto.
El siguiente paso es duplicar el servidor con la web a un nuevo VPS igual. Todo idéntico… pero aquí no se da el problema. Y en este momento ya empieza a ser todo un poco raro.
Mientras no reproduzca el fallo en esta copia, no podré hacer cambios para arreglarlo.
La primera solución
Pero lo que parece igual, no siempre es igual. La copia realizada no tenía activado el icono naranja de Cloudflare (proxied), así que… activado y aparece el fallo.
Bien, aquí ya va la primera solución. Mientras no se encuentre la causa definitiva, aunque me pese, desactivo el proxy de CF en el sitio live, rezando para que no haya un ataque, que aunque estamos preparados a nivel servidor, siempre se capea mil veces mejor con la protección de CF.
Y aquí ya puedo comenzar a trabajar con más calma. Por un lado, la web live está funcionando correctamente y por otro, puedo hacer todo tipo de cambios en la copia sin afectar a los usuarios.
En CF desactivo todas las reglas de seguridad, pero el error sigue apareciendo. Es activar el proxy de CF y los productos se añaden casi siempre por duplicado.
Voy al WordPress y desactivo todos los plugins, excepto WooCommerce, cambio el tema a un twenty twenty y a nivel servidor desactivo todas las cachés y reglas de seguridad. Nada, el problema sigue igual
La solución definitiva
Con las herramientas del navegador, descargo los archivos HAR (HTTP Archive) de Edge y Firefox con y sin proxy de CF, los analizo junto con las peticiones en vivo y descubro lo siguiente en los navegadores Chromium:
En la que se ve una petición de más que acaba en error 503… esa petición parece ser la culpable de añadir una nueva unidad al carrito, duplicando la petición. Pero en el tipo vemos que es prefetch.
Si juntamos el error 503, típico de CF en algunas situaciones, el prefetch y las Speculation Rules API, y tenemos en cuenta que no son compatible entre otros navegadores con Firefox… además del culpable, ya casi tenemos una vía para la solución.
Viernes tarde tenía un viaje de un par de horas, en el que me puse a buscar sobre esta información y me encontré con el hecho de que hacía poco, había sido la semana de aniversario de Cloudflare en la que suelen sacar muchas novedades: https://blog.cloudflare.com/birthday-week-2024-wrap-up/
Y efectivamente, ahí estaba Speed Brain, un servicio que promete ser fantástico, pero… que activaron por defecto a todos los dominios de la opción gratuita, a pesar de ser un servicio en fase beta:
El servicio entre otras cosas y muy resumido, valiéndose de las Speculation Rules API y la IA hace una petición de la página sobre la que vamos a hacer click.
Aunque estaba con el móvil, aquí ya estaba seguro al 90 % de que Speed Brain era el culpable de este comportamiento y ya deseando llegar al ordenador para probarlo.
Así fue, web de desarrollo, deshabilitar el servicio y todo funcionando correctamente. Ir a la web live, desactivar ahí Speed Brain y activar de nuevo el proxy de Cloudflare y todo funcionando como hasta hace unos días y de nuevo securizado mediante el proxy de CF.
Conclusión
Toda una aventura y quebradero de cabeza nada más comenzar la semana el lunes. Escribo esto el domingo a última hora, esperando que mañana no surja otra aventura del estilo.
Muchas horas buscando el error y depurando, que al cliente le habría costado bastante más de mil euros si tuviese que pagar el tiempo y trabajo desarrollados. Pero en estos momentos es donde el cliente que tiene contratados los servicios de mantenimiento ve realmente su utilidad, ya que sin pagar nada a mayores ve los resultados y resolución del problema.
En otras ocasiones paga el mantenimiento durante meses y parece que no hay trabajo (que siempre hay un trabajo subyacente para que las cosas no fallen), pero aquí vemos realmente el resultado de por qué merece la pena.
Cloudflare nos da unos servicios gratuitos de 10 y cada poco añaden nuevas funcionalidades, como ha sido en este caso o en el de las novedades de Turnstile, pero a veces, el habilitar estas funcionalidades por defecto, trae consecuencias indeseadas.
P.D. Por cierto, si necesitas desactivar el servicio Speed Brain en tu Cloudflare, está en Speed -> Optimización -> Optimización de contenido.