<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>по стопам webkill&#039;а &#187; кэш</title>
	<atom:link href="http://blog.lukmus.ru/tag/%d0%ba%d1%8d%d1%88/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.lukmus.ru</link>
	<description>это наш химический дом для печальных жителей Земли</description>
	<lastBuildDate>Sat, 21 Oct 2023 19:10:13 +0000</lastBuildDate>
	<language>ru-RU</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.4.2</generator>
		<item>
		<title>страничное кэширование мультидоменного сайта на Rails 3+Nginx</title>
		<link>http://blog.lukmus.ru/2013/03/07/stranichnoe-keshirovanie-multidomenn/</link>
		<comments>http://blog.lukmus.ru/2013/03/07/stranichnoe-keshirovanie-multidomenn/#comments</comments>
		<pubDate>Thu, 07 Mar 2013 14:46:48 +0000</pubDate>
		<dc:creator>lukmus</dc:creator>
				<category><![CDATA[ruby & ruby on rails]]></category>
		<category><![CDATA[cache_page]]></category>
		<category><![CDATA[expire_cache]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[ruby on rails 3]]></category>
		<category><![CDATA[subdomain]]></category>
		<category><![CDATA[кэш]]></category>

		<guid isPermaLink="false">http://blog.lukmus.ru/?p=1902</guid>
		<description><![CDATA[«Наиболее эффективными считаются те запросы, которые никогда не выдаются», ― говорит Сэм Руби. Страничное кэширование с этой точки зрения не максимально эффективно, но близко к максимуму т.к. страница загруженная полностью из кэша не делает ни одного запроса к БД. Однако, в случае если сайт имеет поддомены, например, для определения локали (en.site.com, ru.site.com), кэш страницы в [...]]]></description>
			<content:encoded><![CDATA[<p>«Наиболее эффективными считаются те запросы, которые никогда не выдаются», ― говорит Сэм Руби. Страничное кэширование с этой точки зрения не максимально эффективно, но близко к максимуму т.к. страница загруженная полностью из кэша не делает ни одного запроса к БД. Однако, в случае если сайт имеет поддомены, например, для определения локали (en.site.com, ru.site.com), кэш страницы в одной локале будет затираться кэшом в другой. В этой статье мой опыт борьбы с этой проблемой.<br />
<img src="http://blog.lukmus.ru/wp-content/uploads/2013/03/patriarh.jpg" alt="" title="патриарх Кирилл" width="517" height="388" class="alignnone size-full wp-image-1903" /><span id="more-1902"></span><br />
Если загуглить решение этой проблемы, то одно из первых, что выскакивает это статья Ryan Stout <a href="http://www.agileproductions.com/blog_posts/16-Page-Caching-by-Subdomain-in-Rails-and-Nginx" target="_blank" rel='nofollow'>«Page Caching by Subdomain in Rails and Nginx»</a>. Собственно, по ней я и пытался кэшировать на поддоменах, но не все так гладко как там описано. Поэтому я кое-что добавил от себя, а кое-что изменил.</p>
<h3>ApplicationController</h3>
<p>Прежде всего, как и описано в статье надо добавить кое-что в <code>ApplicationController</code>, но тут помимо указанного у Ryan&#8217;а метода <code>cache_page</code> надо будет еще перегрузить <code>expire_page</code> иначе обновить кэш из под рельс можно будет только на велосипеде.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
</pre></td><td class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> ApplicationController <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActionController::Base</span>
...
  <span style="color:#9966CC; font-weight:bold;">def</span> cache_page<span style="color:#006600; font-weight:bold;">&#40;</span>content = <span style="color:#0000FF; font-weight:bold;">nil</span>, options = <span style="color:#0000FF; font-weight:bold;">nil</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    path = <span style="color:#996600;">&quot;/#{request.host}/&quot;</span>
    path <span style="color:#006600; font-weight:bold;">&lt;&lt;</span> <span style="color:#9966CC; font-weight:bold;">case</span> options
    <span style="color:#9966CC; font-weight:bold;">when</span> <span style="color:#CC00FF; font-weight:bold;">Hash</span>
      url_for<span style="color:#006600; font-weight:bold;">&#40;</span>options.<span style="color:#9900CC;">merge</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:only_path</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>, <span style="color:#ff3333; font-weight:bold;">:skip_relative_url_root</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>, :<span style="color:#CC0066; font-weight:bold;">format</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> params<span style="color:#006600; font-weight:bold;">&#91;</span>:<span style="color:#CC0066; font-weight:bold;">format</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">when</span> <span style="color:#CC0066; font-weight:bold;">String</span>
      options
    <span style="color:#9966CC; font-weight:bold;">else</span>
      <span style="color:#9966CC; font-weight:bold;">if</span> request.<span style="color:#9900CC;">path</span>.<span style="color:#9900CC;">empty</span>? <span style="color:#006600; font-weight:bold;">||</span> request.<span style="color:#9900CC;">path</span> == <span style="color:#996600;">'/'</span>
        <span style="color:#996600;">'/index'</span>
      <span style="color:#9966CC; font-weight:bold;">else</span>
        request.<span style="color:#9900CC;">path</span>
      <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#9966CC; font-weight:bold;">super</span><span style="color:#006600; font-weight:bold;">&#40;</span>content, path<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> expire_page<span style="color:#006600; font-weight:bold;">&#40;</span>options = <span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    path = <span style="color:#996600;">&quot;/#{request.host}/&quot;</span>
    params<span style="color:#006600; font-weight:bold;">&#91;</span>:<span style="color:#CC0066; font-weight:bold;">format</span><span style="color:#006600; font-weight:bold;">&#93;</span>=:html <span style="color:#9966CC; font-weight:bold;">if</span> options<span style="color:#006600; font-weight:bold;">&#91;</span>:<span style="color:#CC0066; font-weight:bold;">format</span><span style="color:#006600; font-weight:bold;">&#93;</span>
    path <span style="color:#006600; font-weight:bold;">&lt;&lt;</span> <span style="color:#9966CC; font-weight:bold;">case</span> options
    <span style="color:#9966CC; font-weight:bold;">when</span> <span style="color:#CC00FF; font-weight:bold;">Hash</span>
      url_for<span style="color:#006600; font-weight:bold;">&#40;</span>options.<span style="color:#9900CC;">merge</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:only_path</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>, :<span style="color:#CC0066; font-weight:bold;">format</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> params<span style="color:#006600; font-weight:bold;">&#91;</span>:<span style="color:#CC0066; font-weight:bold;">format</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">when</span> <span style="color:#CC0066; font-weight:bold;">String</span>
      options
    <span style="color:#9966CC; font-weight:bold;">else</span>
      <span style="color:#9966CC; font-weight:bold;">if</span> request.<span style="color:#9900CC;">path</span>.<span style="color:#9900CC;">empty</span>? <span style="color:#006600; font-weight:bold;">||</span> request.<span style="color:#9900CC;">path</span> == <span style="color:#996600;">'/'</span>
        <span style="color:#996600;">'/index'</span>
      <span style="color:#9966CC; font-weight:bold;">else</span>
        request.<span style="color:#9900CC;">path</span>
      <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9966CC; font-weight:bold;">class</span>.<span style="color:#9900CC;">expire_page</span><span style="color:#006600; font-weight:bold;">&#40;</span>path<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
...
<span style="color:#9966CC; font-weight:bold;">end</span></pre></td></tr></table></div>

<h3>настройка самого rails-приложения</h3>
<p>Согласно статье, кэш будет храниться в директории <code>public/cache</code>. Чтобы так и было нужно, во-первых, создать папку <code>cache</code> в <code>public</code>, а, во-вторых, сообщить о пути кэша самому приложению. Для этого можно, например, в <code>config/environments/production.rb</code> дописать:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#6666ff; font-weight:bold;">MyApp::Application</span>.<span style="color:#9900CC;">configure</span> <span style="color:#9966CC; font-weight:bold;">do</span>
...
  <span style="color:#9900CC;">config</span>.<span style="color:#9900CC;">action_controller</span>.<span style="color:#9900CC;">page_cache_directory</span> = Rails.<span style="color:#9900CC;">root</span>.<span style="color:#9900CC;">join</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;public/cache&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></td></tr></table></div>

<h3>nginx</h3>
<p>В настройке сайта в <code>nginx.conf</code> нужно указать, что и в оригинальной статье:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="text" style="font-family:monospace;"># If the file exists in the public folder, send it
if (-f $request_filename) {
  break;	  
}
&nbsp;
# Check / files with index.html
if (-f $document_root/cache/$host/$uri/index.html) {
  rewrite (.*) /cache/$host/$1/index.html break;
}
&nbsp;
# Check the path + .html
if (-f $document_root/cache/$host/$uri.html) {
  rewrite (.*) /cache/$host/$1.html break;
}
&nbsp;
# Check directly
if (-f $document_root/cache/$host/$uri) {
  rewrite (.*) /cache/$host/$1 break;
}</pre></td></tr></table></div>

<p>Добавление этих условников говорит Nginx&#8217;у куда записывать кэш если его нет и откуда его читать если для данного адреса есть кэш. Вот тут и возникает проблема, Nginx не будет различать это GET-запрос или POST. И если в случае с GET, все хорошо, то когда поступает PUT-запрос на обновление модели (экшены <code>update</code> и <code>show</code> имеют один и тот же URL по умолчанию) Nginx с радостью обнаружит закэшированную страницу и выдаст ошибку 505.<br />
Язык конфигурации Nginx не поддерживает вложенные условники и не понимает конъюнкцию (&#038;&#038; или AND или еще как угодно), все, что остается это строить велосипед что-то типа:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="text" style="font-family:monospace;">if ( $request_method = GET ) {
  set $method_and_file &quot;method&quot;;
}
&nbsp;
if (-f $request_filename) {
  set $method_and_file $method_and_file+&quot;&amp;file&quot;;
}
&nbsp;
if ($method_and_file = &quot;method&amp;file&quot;) {
  break;
}</pre></td></tr></table></div>

<p>Но эти костыли у меня не завелись с первого раза и я забил на эти грязные мысли.</p>
<h2>как же тогда обновить кэш?</h2>
<p>Для обновления кэша я предлагаю такой, на мой взгляд, не самый кровавый вариант. Надо делать форму модели AJAX-вую и в вызове <code>expire_cache</code> явно указывать формат кэша.</p>
<h3>пример на модели Page</h3>
<p><strong>app/controllers/pages_controller.rb:</strong></p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> PagesController <span style="color:#006600; font-weight:bold;">&lt;</span> ApplicationController
...
  <span style="color:#9900CC;">caches_page</span> <span style="color:#ff3333; font-weight:bold;">:show</span>
  caches_page <span style="color:#ff3333; font-weight:bold;">:index</span>
...
  <span style="color:#9966CC; font-weight:bold;">def</span> update
    respond_to <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span><span style="color:#CC0066; font-weight:bold;">format</span><span style="color:#006600; font-weight:bold;">|</span>
      <span style="color:#9966CC; font-weight:bold;">if</span> <span style="color:#0066ff; font-weight:bold;">@page</span>.<span style="color:#9900CC;">update_attributes</span><span style="color:#006600; font-weight:bold;">&#40;</span>params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:page</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
        expire_page<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#123;</span>action: <span style="color:#ff3333; font-weight:bold;">:show</span>, id: <span style="color:#0066ff; font-weight:bold;">@page</span>.<span style="color:#9900CC;">id</span>, <span style="color:#CC0066; font-weight:bold;">format</span>: <span style="color:#ff3333; font-weight:bold;">:html</span><span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
        expire_page<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#123;</span>action: <span style="color:#ff3333; font-weight:bold;">:index</span>, <span style="color:#CC0066; font-weight:bold;">format</span>: <span style="color:#ff3333; font-weight:bold;">:html</span><span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
        <span style="color:#CC0066; font-weight:bold;">format</span>.<span style="color:#9900CC;">html</span> <span style="color:#006600; font-weight:bold;">&#123;</span> redirect_to <span style="color:#0066ff; font-weight:bold;">@page</span>, notice: <span style="color:#996600;">'Page was successfully updated.'</span> <span style="color:#006600; font-weight:bold;">&#125;</span>
        <span style="color:#CC0066; font-weight:bold;">format</span>.<span style="color:#9900CC;">js</span>
      <span style="color:#9966CC; font-weight:bold;">else</span>
        <span style="color:#CC0066; font-weight:bold;">format</span>.<span style="color:#9900CC;">html</span> <span style="color:#006600; font-weight:bold;">&#123;</span> render action: <span style="color:#996600;">&quot;edit&quot;</span> <span style="color:#006600; font-weight:bold;">&#125;</span>
        <span style="color:#CC0066; font-weight:bold;">format</span>.<span style="color:#9900CC;">js</span>
        <span style="color:#008000; font-style:italic;">#format.json { render json: @page.errors, status: :unprocessable_entity }</span>
      <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
...
<span style="color:#9966CC; font-weight:bold;">end</span></pre></td></tr></table></div>

<p><strong>/app/views/pages/update.js:</strong></p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="javascript" style="font-family:monospace;">setTimeout<span style="color: #009900;">&#40;</span> <span style="color: #3366CC;">'window.location.replace(&quot;&lt;%=page_path(@page)%&gt;&quot;)'</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">1500</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p><strong>/app/views/pages/_form.html.erb:</strong></p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#006600; font-weight:bold;">&lt;%</span>= form_for<span style="color:#006600; font-weight:bold;">&#40;</span>@page, remote: <span style="color:#0000FF; font-weight:bold;">true</span>, <span style="color:#CC0066; font-weight:bold;">format</span>: <span style="color:#ff3333; font-weight:bold;">:js</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>f<span style="color:#006600; font-weight:bold;">|%&gt;</span>
...
<span style="color:#006600; font-weight:bold;">&lt;%</span>end<span style="color:#006600; font-weight:bold;">%&gt;</span></pre></td></tr></table></div>

<p><meta property="og:image" content="http://blog.lukmus.ru/wp-content/uploads/2013/03/patriarh.jpg" /></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.lukmus.ru/2013/03/07/stranichnoe-keshirovanie-multidomenn/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
