ruby-on-rails caching ruby-on-rails-3.1 asset-pipeline cloudflare

ruby on rails - ¿Cómo evito que Rails 3.1 guarde en caché los activos estáticos en Rails.cache?



ruby-on-rails caching (4)

Después de mucha experimentación, terminé haciendo esto en mi config / application.rb:

if !Rails.env.development? && !Rails.env.test? config.middleware.insert_before Rack::Cache, Rack::Static, urls: [config.assets.prefix], root: ''public'' end

Lo que hace es agregar un middleware Rack :: Static rack antes de solicitudes a Rack :: Cache. El middleware Stack Rack :: sirve urls con un prefijo correspondiente a un directorio raíz. Aquí estoy dando config.assets.prefix como mi prefijo url que por defecto es ''/ assets''. Estoy estableciendo la raíz en el directorio ''public''.

Solicitudes para esta ruta:

/assets/jquery-e8da439bbc8fd345e34ac57c6a216318.min.js

debería encontrarlo en este archivo:

public / assets / jquery-e8da439bbc8fd345e34ac57c6a216318.min.js

Esto debería servir a cualquier activo directamente fuera del directorio público / de activos en lugar de golpear Rails :: Cache en absoluto, lo que impedirá que almacene los activos en la memoria caché de Rails. Esto solo funcionará si ejecuta los activos de rake: precompilación en producción, de lo contrario no habrá activos precompilados en ''public / assets''.

Estoy usando CloudFlare CDN en mi aplicación Rails 3.1. Cloudflare es un CDN que funciona en el nivel de DNS. En el primer golpe a un activo estático, CloudFlare lo carga desde tu aplicación y luego lo almacena en su CDN. Solicitudes futuras de esa carga de activos desde el CDN en lugar de su aplicación.

El problema que tengo es que si configura el almacenamiento en caché del controlador en verdadero:

config.action_controller.perform_caching = true

habilita el middleware Rack :: Cache. Como Rails establece una configuración de control de caché predeterminada para los activos estáticos, esos activos se escriben en el almacén de Rails.cache. Como resultado, mi almacén de caché (en mi caso, redis) se está llenando con activos estáticos con la url como la clave de hash.

Desafortunadamente, no puedo desactivar los encabezados de control de caché de activos estáticos sin afectar la forma en que Cloudflare y los navegadores de mis usuarios almacenan en caché los activos. No puedo desactivar el almacenamiento en caché del controlador o pierdo el almacenamiento en caché de la página / acción / fragmento. El mismo resultado si elimino el middleware Rack :: Cache.

¿Alguien tiene alguna otra idea?

Actualización: he abierto un ticket en GitHub aquí .


Otra forma de resolver el mismo problema y este problema es utilizar el middleware Stained ActionDispatch :: Static en lugar de Rack :: Static así:

if !Rails.env.development? && !Rails.env.test? config.middleware.insert_before Rack::Cache, ::ActionDispatch::Static, ''public'', config.static_cache_control end

¿Cuál es la diferencia entre Rack :: Static y ActionDispatch :: Static preguntas?

  • Rack :: Static toma una matriz de prefijos de URL para verificar contra la url de solicitud. Entonces, en nuestro caso, solo buscará archivos si la ruta de solicitud comienza con ''/ assets''.

  • ActionDispatch :: Static verificará la existencia del archivo en ''public'' en cada solicitud GET / HEAD, independientemente de la ruta.

  • Rack :: Static no comprueba primero el archivo, llama a Rack :: File.new en el archivo, por lo que si no existe, devolverá un 404, no pasará la solicitud a la cadena de middleware.

  • Si ActionDispatch :: Static no encuentra el archivo en su ruta, continuará por la cadena de middleware del rack (el resto de la pila de Rails).

Al final, lo que sea que ActionDispatch :: Static no encuentre en ''public'' simplemente pasará a la pila de Rails. Así que Rails terminará sirviendo los activos que ActionDispatch :: Static no puede encontrar. Esto resuelve mi problema de los activos que Rack :: Cache no encuentra, pero también requiere más recursos ya que cada solicitud activará una verificación de archivos.


El póster original quería evitar que los activos estáticos ingresaran en el caché general de Rails, lo que los llevó a querer inhabilitar Rack :: Cache. En lugar de hacer esto, la mejor solución es configurar Rack :: Cache para usar un caché separado del caché general de Rails.

Rack :: Cache debe configurarse de forma diferente para el almacenamiento de entidades frente al meta almacenamiento. Rack :: Cache tiene dos áreas de almacenamiento diferentes: tiendas meta y entidad. El metastore mantiene información de alto nivel sobre cada entrada de caché, incluidos los encabezados de solicitud y respuesta HTTP. Esta área almacena pequeños fragmentos de datos a los que se accede a alta frecuencia. La tienda de la entidad almacena en caché el contenido del cuerpo de respuesta, que puede ser una cantidad relativamente grande de datos, aunque se accede a ella con menos frecuencia que el metastore.

La siguiente configuración almacena en caché la información del metastore en memcached pero el cuerpo real de los activos en el sistema de archivos.

Usando memcached gem:

config.action_dispatch.rack_cache = { :metastore => ''memcached://localhost:11211/meta'', :entitystore => ''file:tmp/cache/rack/body'', :allow_reload => false }

Usando la gema dalli

config.action_dispatch.rack_cache = { :metastore => Dalli::Client.new, :entitystore => ''file:tmp/cache/rack/body'', :allow_reload => false }

Por cierto, esta configuración es la recomendación para Heroku: https://devcenter.heroku.com/articles/rack-cache-memcached-static-assets-rails31


Puede desactivar el almacenamiento en caché de los archivos de canalización de activos mientras deja otro almacenamiento en caché en su lugar con:

config.assets.cache_store = :null_store

Eso debería evitar que Sprockets guarde algo en el caché.