アクセスがなくても Heroku を止めない

Heroku 上に作ったサイトにアクセスすると遅い時がある。

一度アクセスすれば普通になるけど。

Heroku のリファレンスによると、

Dynos and the Dyno Manager - Dyno sleeping

Apps that have scaled the number of web dynos (dynos running the web process type) so that only a single web dyno is running, will have that web dyno sleep after one hour of inactivity.

とのこと。

Heroku を無料で使っていると Dyno は 1 個しかないから、1 時間アクセスがないとスリープするみたい。

VPS や自宅サーバなどで cron の使える環境があれば定期的に curl なりすれば簡単なんだけど、無料かつ Heroku 単体で何とかしたい。

無料の回避策として、 Easy way to prevent Heroku idling? - Stack Overflow を読むと、昔は

  • New Relic
  • Pingdom

の利用があったけど、今は New Relic をインストールしてもスリープするし、Pingdom は 1 サイト無料から 30 日間無料に変更されたため、恒久的方法にならない。

ということで、Heroku のサイトに Feed を用意し、その Feed を Feedly なり livedoor Reader に登録して、Feed を読みにきたクローラのアクセスで Heroku を Weak up させることにした。

Feed は Rails の AtomFeedHelper を参考にした。

ActionView::Helpers::AtomFeedHelper

変えたのは、クローラに 20 分おきに来てもらえるように 20 分毎に更新しているように見せていること。

app/controllers/posts_controller.rb の @posts = Post.all をこうした。

    d = DateTime.current
    m = 20
    # m = 20 なら min: 0..19->0, 20..39->20, 40..59->40
    @last_updated = d.change(min: (d.minute/m)*m)

    # Feed に出す内容も最終更新日から m 分以内のものにする
    from = @last_updated.advance(minutes: -m)
    to   = @last_updated
    @posts = Post.where(created_at: from...to).order(created_at: :desc)

そして app/views/posts/index.atom.builder の

feed.updated(@posts[0].created_at) if @posts.length > 0

feed.updated(@last_updated)

にした。これでクローラがいつ来ても 20 分おきに更新されているように見えるはず。

Posts の中身は会員登録数や、コメント数などにすれば、RSS リーダでサービス監視的なことができます。

この Feed は自分が読むだけの秘密の Feed だけど、一般公開する Feed なら Generating RSS feed in Rails 3 - Stack Overflow の config/routes.rb に書く

resources :news_items
get '/feed' => 'news_items#feed',
      :as => :feed,
      :defaults => { :format => 'atom' }

と、app/views/layouts/application.html.erb の

<%= auto_discovery_link_tag :atom, "/feed" %>
<%= auto_discovery_link_tag :rss, "/feed.rss" %>

を使うだろうからメモ。