Los avatares tardan mucho en cargar después de moverse a R2 compatible con S3

Hola,

Acabo de migrar a R2 y todo salió perfectamente. Todas las imágenes tienen el enlace de la URL del CDN de S3. Sin embargo, noté un problema: los avatares tardan mucho en cargar. En promedio, tarda entre 3 y 4 segundos, ya sea que haga clic en el avatar de un usuario o que lo observe dentro de una publicación. ¿Es esto esperado?

Mmm, sospecho que podría deberse a uno de tres problemas diferentes, pero el más probable para mí es el redimensionamiento en tiempo real.

1. Redimensionamiento de avatares en tiempo real

Cuando migraste tus subidas a R2, se movieron las imágenes originales; sin embargo, Discourse utiliza muchos tamaños diferentes de avatares (por ejemplo, 45px para los mensajes, 120px para la tarjeta de usuario).

Si esos tamaños optimizados específicos no se migraron perfectamente o aún no se han generado, Discourse tiene que generarlos de forma sincrónica en el momento en que el usuario hace clic en ellos:

  1. Discourse descarga el avatar original desde R2 al servidor local.
  2. Lo redimensiona utilizando ImageMagick.
  3. Sube el nuevo tamaño de vuelta a R2.
  4. Redirige el navegador a la nueva URL, y este proceso tarda entre 3 y 4 segundos.

Para verificar: actualiza forzosamente la página (hard-refresh). Si el avatar tarda 3-4 segundos la primera vez, pero carga instantáneamente la segunda vez, esto es exactamente lo que está ocurriendo.

Para solucionarlo: esto se solucionará naturalmente a medida que los usuarios naveguen y se generen los tamaños. Pero puedes solucionarlo al instante forzando al servidor a pregenerar todos los avatares en segundo plano accediendo por SSH a tu servidor y ejecutando:

./launcher enter app
rake avatars:refresh

2. El tiempo de espera de 3 segundos de IPv6

Si los avatares tardan 3-4 segundos cada vez, incluso después de múltiples actualizaciones, es probable que estén alcanzando un tiempo de espera de red.

Los puntos finales de la API de Cloudflare R2 son de doble pila (dual-stack), es decir, utilizan tanto IPv4 como IPv6. Si tu gota del servidor tiene una dirección IPv6 asignada, pero la puerta de enlace IPv6 del anfitrión no está enrutada correctamente, la conexión interna de Ruby al cubo de R2 intentará usar IPv6 primero, se colgará durante 3 segundos (este es el tiempo de espera TCP predeterminado de Linux), fallará y luego se conectará con éxito de forma instantánea usando IPv4.

Para verificar: accede por SSH al servidor y ejecuta:

curl -I -6 https://cloudflare.com

Si se cuelga durante unos segundos y falla, el IPv6 del servidor está roto, lo que hace que cada verificación interna de la API de S3 sufra un retraso de 3 segundos.

Para solucionarlo: necesitarás corregir el enrutamiento IPv6 en el panel de control de tu anfitrión o quizás incluso desactivar IPv6 en la gota del servidor por completo.

3. Retardos de Gravatar

Si tu sitio está configurado para verificar las actualizaciones de Gravatar, es posible que esté enviando pings a los servidores externos de Gravatar antes de renderizar el avatar. Si el servidor tiene una conexión saliente lenta (también relacionada a menudo con DNS o IPv6), es probable que bloquee la renderización del avatar.

Para verificar: ejecuta esto en tu servidor:
curl -I -6 https://gravatar.com
Si se cuelga durante 3 segundos, el IPv6 está roto (ver arriba).

Solución relacionada con Gravatar: en la configuración de Discourse, ve a descargar automáticamente gravatars, desactívala temporalmente y comprueba si eso lo soluciona. No creo que este sea el problema, pero si lo fuera, puedes dejar la configuración desactivada, o corregir el enrutamiento IPv6 como se indica en el punto 2 anterior, o quizás cambiar el resolvedor DNS.

Gracias por su rápida respuesta. Creo que ya había intentado antes el comando ‘rake avatars:refresh’, pero no estoy completamente seguro.

Lo que solía funcionar para mí para ver que el avatar se abriera inmediatamente era hacer clic en él por primera vez; la segunda vez, se abría instantáneamente. Pero eso probablemente se deba a la caché. Además, acabo de probar su segundo consejo y devuelve un «HTTP/2 301», junto con varias otras líneas. Lo mismo ocurre con el consejo 3. Ejecutaré avatars:refresh nuevamente en unos días, ya que necesité restaurar una instantánea. ¡Gracias de nuevo!

Gravatar

server: nginx
date: Mon, 22 Jun 2026 19:29:00 GMT
content-type: text/html; charset=utf-8
content-length: 0
content-language: en
expires: Wed, 11 Jan 1984 05:00:00 GMT
cache-control: no-cache, must-revalidate, max-age=0
x-redirect-by: Gravatar
location: https://en.gravatar.com/
alt-svc: h3=":443"; ma=86400
strict-transport-security: max-age=31536000; includeSubdomains; preload

CF

HTTP/2 301
date: Mon, 22 Jun 2026 19:27:00 GMT
content-type: text/html
content-length: 167
location: https://www.cloudflare.com/
cache-control: max-age=3600
expires: Mon, 22 Jun 2026 20:26:59 GMT
set-cookie: __cf_bm=eBP2aJ7Eg30nHPuvMMNxxKrgNtcNwKs0WDgnYyONeus-1782156420-1.0.1.1-sXpW27iuhGDF615cOfwNFybH4IMxgvZy3uA_3X_o..402T_3KSgT7CSymipL5RjdpGe3raWEqsVxQFFLPKRoDjfoT7B.0rqyDt.osbkOF98; path=/; expires=Mon, 22-Jun-26 19:57:00 GMT; domain=.cloudflare.com; HttpOnly; Secure; SameSite=None
report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=QfYqSekEDPJHC2k%2BMjHN0cGjz172tmUWe2GSR8EgwNLh3TGjFYkQ0vwPxlzY1NcBcKFOMaAi4FlgjqjhETOOtHf%2BH9KdQSvqN3OME2Uh1i4nHIw%2Fy1qkvSpf4jxDchM7CaDW80tJkjBV4OqF"}],"group":"cf-nel","max_age":604800}
nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
strict-transport-security: max-age=15780000; includeSubDomains
server: cloudflare
cf-ray: a0fda5d8ecd6b26d-LAX
alt-svc: h3=":443"; ma=86400

sí, dada tu respuesta, estoy casi seguro de que se trata del problema #1 porque los resultados del comando curl para cloudflare y gravatar parecen ser los esperados. Prueba con rake avatars:refresh cuando te sea conveniente y avísame si funciona.

Hola Lilly, sigo teniendo el mismo problema. Incluso después de ejecutar rake avatars:refresh. El problema persiste incluso en /latest. Probé limpiando la caché desde mi navegador y desde Cloudflare, pero sin éxito todavía. ¿Quizás necesito esperar un poco? Lo estoy probando en un foro con 4500 usuarios.

no borres más el caché de tu navegador o de Cloudflare: cuando ejecutas rake avatars:refresh para tantos usuarios, esto no ocurre de forma instantánea. En su lugar, se envían miles de trabajos a Sidekiq para que se procesen en segundo plano, lo que puede tardar varias horas dependiendo de la CPU de tu servidor. Lo siento, debería haber mencionado Sidekiq y que puede tardar un poco dependiendo de cuántos usuarios haya.

Ve a your-forum.com/sidekiq/queues y observa la cola. Espera a que se vacíe por completo. Una vez que Sidekiq termine, todos los tamaños deberían estar en tu bucket de R2 de forma permanente, y creo que la carga de tus avatares volverá a la velocidad normal.

Ok, creo que está pasando algo más. No tengo nada en mis colas. Pero si hago clic en el avatar de cualquier usuario, esto aparece en ‘tail -f log/production.log’: Sent file /var/www/discourse/tmp/avatar_proxy/3689d91eb5e1013beef831c585b5e62edeeecbd6.jpeg (0.2ms)

¡Vaya, vale! Esto probablemente sea la prueba definitiva y apunta a un problema diferente.

avatar_proxy en los registros suele significar que Discourse se niega a servir la imagen directamente desde el CDN R2 de Cloudflare. En su lugar, Discourse intercepta agresivamente la solicitud, descarga la imagen desde R2 a la carpeta /tmp del servidor local y luego usa Ruby para servirla al navegador. Así que creo que esto está evitando por completo el CDN y explica el retraso de 3 segundos: sospecho que el servidor está obteniendo y cargando el archivo manualmente en cada solicitud :grimacing:

Discourse utiliza avatar_proxy en algunos escenarios muy específicos y, por lo general, es una configuración de privacidad o seguridad que obliga al servidor a enmascarar la URL externa.

Verifica estas configuraciones en Administración > Configuración del sitio:

Busca external system avatars url (URL de avatares de sistemas externos). Si hay algo en ese cuadro (como /letter_avatar_proxy/v4/...), bórralo para que quede vacío. Eso debería evitar que Discourse proxye los avatares predeterminados de letras. También vale la pena verificar uploaded avatars allowed groups (grupos permitidos para avatares cargados) y asegurarse de que diga TL_0.

Tal vez verifiquen también DISCOURSE_S3_CDN_URL para asegurarse de que sea correcta, sin una barra al final ni errores tipográficos.

Reasignar avatares personalizados:
Parece probable que tu base de datos aún contenga las URL crudas del bucket R2 en lugar de tu nueva URL de CDN; como no coinciden, tu foro probablemente las está proxyando por razones de seguridad.

Verifica en la consola de Rails para ver exactamente con qué está luchando Discourse:

./launcher enter app
rails c

Elige un nombre de usuario con un avatar de carga lenta.

u = User.find_by_username("el_nombre_de_usuario_seleccionado")
u.user_avatar.custom_upload.url

Si la salida devuelve una URL cruda del bucket, tus reasignaciones anteriores no capturaron todo (quizás se haya pasado por alto un subdominio o un esquema).

Para solucionarlo, inicia sesión por SSH en tu servidor, vuelve a tu contenedor nuevamente (no a rails) (./launcher enter app) y ejecuta la herramienta de reasignación (de nuevo, jaja) para cambiar la URL cruda por tu URL de CDN:

discourse remap "https://<tu-url-cruda-de-cloudflare>.r2.cloudflarestorage.com" "https://cdn.tu-dominio.com"

Luego ejecútala una segunda vez usando // en lugar de https:// por si acaso.

Por cierto, solo por curiosidad, ¿qué servicio de hosting estás utilizando? Tengo una configuración general similar a la tuya y aún no he experimentado este problema. Así que también estoy interesado en tu configuración y quiero intentar reproducirlo de alguna manera.

La URL que obtengo muestra la URL de la CDN de S3 y puedo abrir la imagen en el navegador.

Por ahora dejaré de lado S3, ya que realmente no lo necesito en este momento.

Además, llevo mucho tiempo usando Advinservers.

Gracias por tu ayuda, lo aprecio mucho.

He terminado las pruebas adicionales y puedo confirmar que el problema no está relacionado con R2. El mismo comportamiento (los avatares se cargan lentamente en las publicaciones y al hacer clic en un nombre de usuario) persiste incluso con un AWS S3 configurado correctamente. Tampoco es un problema de firewall, ya que «ufw status» confirma que el firewall está actualmente desactivado. Planeo realizar más pruebas este fin de semana en un entorno de staging, donde puedo mantener el foro en funcionamiento durante períodos más largos y ponerlo fuera de línea si es necesario sin ningún problema.

¿Tienes configurados tanto el CDN del sitio como el CDN de S3?

Sí, estoy usando ambos. El bucket está conectado con CloudFront para la URL de CDN de S3, y lo mismo para la URL de CDN de Discourse.

Para las pruebas de R2, no estaba usando la URL de CDN de Discourse.

¿Excepto en el que no funciona?

¿Y el R2 sin CDN de Discourse es donde tienes problemas?

No voy a pretender que entiendo exactamente cuál es tu problema ni exactamente cómo funcionan las imágenes de avatar, pero configuraría el CDN antes de hacer más pruebas, y podría ser que el problema sea que te mudaste a un nuevo bucket y que el problema sea que esas imágenes necesitan regenerarse.

Los avatares aquí se cargan desde lo que parece un CDN de Discourse: https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/lilly/48/555832_2.png

¿Se cargan los perfiles de usuario más rápido después de la primera carga?

Nuevamente, no prometo que entienda y no he revisado el código, pero mi suposición es que estos se están sirviendo desde el CDN de Discourse, y Discourse luego confía en que las solicitudes posteriores obtengan el contenido del CDN. Creo que esto explica por qué no funciona (o funciona lentamente) en la versión de R2 que no tiene un CDN de Discourse.

quizás no estoy entendiendo lo que quieres decir aquí, pero tengo 2 sitios ejecutándose con almacenamiento de objetos R2 que no experimentan este problema. :woman_shrugging:t2:

¿No tienen CDNs de Discourse? Si no los tienen, me equivoco. Si los tienen, entonces puede ser que no tener un CDN de Discourse (cuando tienes un bucket de S3) cause este problema.

Pero parece extraño que los avatares se comporten de manera diferente con S3 que sin él.

En realidad, probé esto con 4 configuraciones diferentes:

  1. R2 sin Discourse CDN

  2. R2 con Discourse CDN

  3. AWS S3 con Discourse CDN

  4. AWS S3 sin Discourse CDN

En todos los casos, utilicé la URL del CDN de S3: files.mydomain.com.

Para los casos con Discourse CDN, utilicé: cdn.mydomain.com.

El problema es que, en cada escenario, la carga de los avatares es siempre muy lenta.

Si abro un tema, veo que los avatares se cargan uno por uno. Sin embargo, esto solo ocurre una vez. Por ejemplo, si voy a admin/users, solo veo los nombres de usuario, y luego los avatares comienzan a cargarse uno por uno.

Si hago clic en un nombre de usuario, se abre la tarjeta del usuario y el avatar aparece 3-4 segundos después. Esto también solo ocurre una vez; si vuelvo a hacer clic, el avatar aparece inmediatamente, probablemente debido a la caché.

PD: Al realizar cada prueba, restauré la instantánea de cuando no estaba usando S3/R2, eliminé el bucket y empecé de nuevo.

Simplemente voy a suponer que no tiene nada que ver con la configuración del almacenamiento de objetos. Creo que tus avatares son lentos en los cuatro configuraciones porque tu cuello de botella no es el proveedor de almacenamiento, sino la latencia de red entre tu droplet del sitio y tu bucket, o quizás el CPU de tu servidor está teniendo problemas para redimensionar las imágenes en tiempo real. No sé nada sobre tu configuración de servidor/CDN ni qué distancias están involucradas aquí. Pero creo que una vez que se construya la caché de borde, no debería importar qué almacenamiento uses, siempre que te quedes con uno y dejes que la caché se construya por sí misma. Sin embargo, solo estoy teorizando en este punto porque no tengo otras ideas. :woman_shrugging:t2: :grinning_cat_with_smiling_eyes:

Ya no sé qué pensar. Para R2, estaba usando la región de Europa Occidental (WEUR), y para S3, estaba usando eu-north-1. Estas son las especificaciones de mi VPS:

Procesador AMD Turin (4 vCores) 8GB de memoria DDR5 ECC 256GB de almacenamiento NVMe SSD 5TB de ancho de banda (10 Gbit) Ubicado en Los Ángeles, CA

¿Quizás debería probar con una región en Estados Unidos la próxima vez? No creo que pueda hacerlo con R2.

Es lo que yo esperaba. La generación de todos los avatares es lenta. Las tareas de rake lo harán posible, pero llevan mucho tiempo, especialmente si hay muchos usuarios. La primera vez que accedes a un usuario, se genera el avatar y tarda unos segundos en ejecutar un programa externo que procesa los datos de la imagen en varios tamaños. Después de eso, todo funciona bien. Creo que solo necesitas ejecutar la tarea de rake y esperar a que se generen todos los avatares en los distintos tamaños.

sí, supongo que eso es a lo que me refería aquí, pero quizás no me expliqué bien:

pero creo que dijiste que se cargaba lento cada vez. :thinking:

creo que cada vez que cambias tu configuración de S3 o limpias la caché, estás empezando de cero. Si tienes muchos avatares de usuario, esto llevará mucho tiempo.