herokuでMemory Quota Exceededと言うのが出るようになったので、puma_worker_killerを入れた話

最近、herokuで稼働させているRailsのアプリが「Memory Quota Exceeded」と言われる事が多くなり、定期的にワーカーの再起動をしたいと思ってました。

memory_quota_exceeded

見る限り、swapも出てしまい、レスポンスも遅くなっているようです。

このような場合、heroku以外だと、unicornを使うので、unicorn_worker_killerを入れるのですが

herokuだとpuma推薦なのでpuma使っていました。

で、pumaもuniconのようにworker killer系の物があるのかな?と探してたところ

puma_worker_killerがあるようなので、使ってみました。

https://github.com/schneems/puma_worker_killer

herokuでの使い方は、「Turn on Rolling Restarts」というのを使うのが推薦のようなので

その設定で行ってみました。

デフォルトだと6時間ごとに再起動ということになるので、ひとまず様子見で3時間に設定してみます。

以下が、3時間でリスタートがかかるようにした設定になります。

こちらを設定したところ

memory_quota_exceeded_after_config

ピーク時は少しswapが出る時もあるものの、割と落ち着いたのかなと思います。

しばらくはこの状態で様子見をし、アラートがまた増えるような感じであれば再度調整という事にしようと思います。

Ruby 2.2 がリリースされました

クリスマスプレゼントなのか

Ruby2.2 がリリースされてました。

https://www.ruby-lang.org/ja/news/2014/12/25/ruby-2-2-0-released/

Rails使いとしては

たとえば、新しい Ruby のガーベージコレクタは Symbol オブジェクトのガーベージコレクトができるようになりました。 2.2 以前の GC は Symbol オブジェクトのガーベージコレクトに対応していなかったため、この新しい GC によって Symbol オブジェクトについてのメモリ使用が削減されます。 Rails 5.0 ではこの Ruby 2.2 以降でのみサポートされる Symbol GC が必須とされる予定です。 (詳細は Rails 4.2 のリリースについてのポスト を参照してください)

との事なので、今後のことを考えると、早めにRubyもバージョンをあげてしまいたいなと思ったりします。

Windowsに複数バージョンのRubyをインストールする

今回の要件

  • Windowsに複数のバージョンのRubyをインストールする。
  • バージョンの切り替えを出来るようにする。
  • ネイティブなgemもインストールしたい。
    たとえばnokogiri とか jsonとか

ダウンロード

ということで、まずは必要なRubyのダウンロード。
以下のページからインストーラをダウンロードします。

http://rubyinstaller.org/downloads/
http://ruby-lang.org/からもリンクがあります。

今回はシステム側に2.0.0、切り替え用として1.8.7をインストールします。

なので、ダウンロードページから

2.0.0のインストーラと1.8.7のインストーラをダウンロード。
現時点でダウンロードページにアップされているインストーラは
Ruby 2.0.0-p353 (x64)
Ruby 1.8.7-p374

続いて、それぞれのバージョンでネイティブのgemをインストール出来るようにするために
DEVELOPMENT KITをダウンロードします。
DevKit-tdm-32-4.5.2-20111229-1559-sfx.exe
DevKit-mingw64-64-4.7.2-20130224-1432-sfx.exe

Ruby本体をインストール

まずは、2.0.0のインストーラで普通にインストールします。

[インストーラ画面割愛]

インストールパスは
C:\Ruby200-x64
とします。

システム環境変数へは、C:\Ruby200-x64\binをPathに追加設定します。

つづいて、1.8.7のインストーラを起動してインストールします。

インストーラ画面割愛

インストールパスは
C:\Ruby187
とします。

この1.8.7の場合はシステム環境変数へはパスを追加しないようにしてインストールします。

これで二つのバージョンをインストールしました。

これを切り替えるためのツールをインストールします。

切り替えるにはpikというツールを使います。

Linuxな環境とかだと、rvmのようなイメージです。

pikは以下のページよりダウンロードします。

https://github.com/vertiginous/pik/downloads

今回はインストーラ形式のものをダウンロードします。

インストールパスは
C:\pik
と指定します。

Append c:\pik\ to system path.

にチェックを入れておきます。

インストールが完了すると、プロンプト画面でpikコマンドが使えるようになります。

pikコマンドでは、rvmと同様、インストール出来るRubyのバージョンが一覧表示できます。

今回はすでに2.0.0と1.8.7をインストールしてあるので、これをpikのconfig.ymlに登録します。

pik add C:\Ruby200-x64\bin
pik add C:\Ruby187\bin

pikの設定は
c:\Users/hoge/.pik
というディレクトリに出来上がるconfig.ymlを編集します。
※出来てない場合、pik listとかをたたくと、出来上がると思います。
それでも出来上がらない場合、手で作りましょう。

設定がファイルに入ったことを確認します。c:\Users/hoge/.pik
というディレクトリに出来上がるconfig.ymlを確認します。

設定をしたら、設定内容をpikからも確認してみます。

を実行。

Rubyのバージョンを切り替えるには

切り替わると、pik listのコマンド結果で矢印の位置が1.8.7の前に来ていると思います。
Rubyのバージョンを確認してみましょう。

を実行。

続いて、

を実行。

これで、devkitがインストール完了です。

ネイティブなgemがインストール出来るか確認します。

ネイティブなgemをインストールする時にエラーが出る場合、オプションに–platform=rubyという指定をつけます。

試しにjsonを入れてみます。

これで問題なくインストール出来ていれば、完了です。

同様の作業をc:\Ruby200に対しても行います。

2.0.0用のdevkitは、また別のインストーラなので、それを使ってインストールします。

rvmを使った環境で、unicornをcrontabなどに登録する時の手順

rvmを使って実行環境を分けつつ、crontabなどで自動起動をさせたい時

まずはrvmでラッパーを作成する

これを実行すると、~/.rvm/binにstart_unicorn_railsというファイルが出来上がる

このファイルに対してunicorn_railsに指定するパラメータを指定してやると

rvmを読み込んだ状態でunicorn_railsを実行してくれる。

Ubuntu 13 and Ruby on Rails 4 で、capybara-webkitを使ってcucumberでテスト

必要なパッケージをインストールする

たぶん、このインストールだけで済むはず。

入れている物は、
libqtwebkit-dev
qtwebkitの開発用モジュール
Qtはデスクトップと組込み開発向けのクロスプラットフォームアプリケーション開発フレームワーク
らしい
xvfb
仮想フレームバッファ
ttf-kochi-mincho-naga10 ttf-kochi-gothic-naga10
日本語フォント

済まなかったら以下を追加

Gemfileにgem追加

bundle実行

インストール完了

続いて、実行です。

lib/tasks/cucumber.rakeファイルが出来ているので、開く

test:prepare

というタスクがあるので、この中に以下の様にheadless起動の処理を書く

以上で、cucumberの設定は完了

続いて、サンプル的に。

Googleのトップページへアクセスして、スクリーンショットを撮って終了するという処理を書いてみます。

features/step_definitions/steps.rb

というファイルを作成します。

この中身は以下の様にします。

続いて、

/features/example.feature

というファイルを作成します。

中身は以下の様に。

最後に、cucumberを実行します。

これで、www.google.co.jpのキャプチャが取得出来ましたでしょうか?

Aptana Studio 3でEGitを入れているのに、Aptana Studio 3でインストールされるPortableGitが優先されてしまう問題

Aptana Studio 3でEGitを入れているのに
Aptana Studio 3でインストールされるPortableGitが優先されてしまう問題

ですが

Preferencesの設定の中にある

[Term] – [Git]

という所が二つあると思います。

これは、Aptana Studio 3が内包しているPortable Gitの設定と、EGitの設定が両方出てきているという事です。

で、EGitの方を優先で使いたい場合ですが

[Term] – [Git]のサブオプションがある方がEGitで、サブオプションがない方がPortableGitの方になります。

このPortableGit側の設定の
「Automatically attach our git support to projects added that have git repositories」
と言う設定をOFFにする事で解決する事が出来ます。preference

Rubyで配列からハッシュを作成する

たまに、配列になっているデータをハッシュに変えてしまいたい時があったりします。

data = [[0, ‘データ1’], [1, ‘データ2’], [2, ‘データ3’], [3, ‘データ4’], [4, ‘データ5’]]

という感じのデータですね。

これをハッシュにするには、ゴリゴリやる場合

hash_data = {}
data.map{|c| hash_data[c[0]] = c[1]}

となりますが、別のやり方として

Hashの「self[*key_and_value] -> Hash」というメソッドを使ってみます。

Rubyのドキュメントにもあるのですが

Hashの[]メソッドとして定義されており

array_data = [a0, ‘データ1’]
Hash[*array_data]という感じにすると、
{0 => ‘データ1’}
というハッシュを作ってくれます。

所が、このメソッドは今回の例のdataの配列のような2重配列は対応していないので

ハッシュを作る際にhash_dataを平滑化する必要があります。

これを踏まえて最終的には

Hash[*data.flatten]

と書くと、良い感じにハッシュになります。

ちなみに、この時self[*key_and_value]に渡す配列ですが、偶数個でしか受け取りません。

奇数個の配列を渡すと例外が発生します。

Ruby(Ruby on Rails)で、使わなくなったメソッドをdepricatedにする

ある程度コードを書いていると、使わなくなったメソッドや、新しいメソッドを作ったので使って欲しくないメソッドなどが多々出てくるかと思います。

コメントで書いておいても、使う人はいるし、既存コードで知らぬ間に使ってあったりもします。

そんな時は

depricatedをログに出力するようにしてしまいましょう。

そうすれば、その処理を通るたびにワーニングとしてdepricatedなメッセージが出力されるので

対処しやくすなります。

書き方としては、

[ruby]def old_method
warn "[DEPRECATION] ‘old_method’ is deprecated. Please use ‘new_method’ instead."
end[/ruby]

という感じに

ScalaのArrayなどで、Rubyのeach_with_indexのようなインデックス付きイテレーションを使う

Rubyでは

[scala][‘one’, ‘two’, ‘three’].each_with_index |value, index|
p "#{index}番目は#{value}です"
end[/scala]

というような書き方が出来ます。

これをScalaで書くにはどうするか。

[scala]
val list = List("one", "two", "three")
list.zipWithIndex.foreach{ case(value, index) => println("%d番目は%sです".format(index, value)) }[/scala]

という感じになります。

さて、このzipWithIndexですが、ややパフォーマンスが悪いのが難点です。

このzipWithIndexというのは、scala.collection.ItelateLikeにあるメソッドなのですが
もう一つ、zipWithIndexscala.collection.Iteratorにも存在しています。
こちらの方はパフォーマンスが良いようで
こちらを使いたいと思います。

[scala]list.iterator.zipWithIndex.foreach{ case(value, index) => println("%d番目は%sです".format(index, value)) }[/scala]

と、listzipWithIndexの間にiteratorを入れるだけですね。

これでパフォーマンスが上がります。

RailsからMySQLのテーブルを作成する時にLONGBLOBなカラムを作成する方法

RailsからMySQLのテーブルを作成するには

Railsのマイグレート機能には、カラム属性としてbinaryがあるのですが、これを指定してもMySQL上ではBLOBというカラム属性になります。

構文としては
[ruby]create_table :user_photos do |t|
  t.string :name
  t.binary :photo_image
end[/ruby]
もっと大容量のLONGBLOBが欲しい!

という時にはbinaryの所にオプションで:limit => 16.megabyte を指定します。
[ruby]create_table :user_photos do |t|
  t.string :name
  t.binary :photo_image, :limit => 16.megabyte
end[/ruby]
こんな感じですね。

RVMをセットアップする

Rubyは、リファレンス実装でC言語によるRuby(CRuby)や、Javaでの実装のJRuby、.NETのIronRubyなど、多くの実装があります。

これを一つ一つ環境構築してたら、大変なので

RVMというRubyの管理ツールをインストールしてみます。

これで出来る事は
Rubyのバージョンを切り替える
CRubyからJRubyに切り替える
gemのセットを作って切り替える

など

お手軽に入れるには、Ubuntuなどのユーザ領域にRVMをインストールする

ということで、インストールして見ます。

まずは本家のサイトを見ます。

https://rvm.io/

rvmを実行するには、必ず必要になるコマンド類をインストールします。
[shell]apt-get install git curl patch[/shell]
RVMのインストールスクリプトをダウンロード&実行します
[shell]curl -L https://get.rvm.io | bash -s stable[/shell]
これで、安定版がインストールされました。

ターミナルに再ログイン後

rvmとやって、コマンド一覧が出たら成功です。

rvmで管理出来るRubyの一覧を見てみます。

rvm list known

CRuby 1.9.3を入れてみます。

※CRubyをインストールする時は、Ubuntuの場合だと、必要なパッケージ、コマンド類がありますので、それをあらかじめ入れておきます。
Additional Dependencies:
# For Ruby / Ruby HEAD (MRI, Rubinius, & REE), install the following:
ruby: /usr/bin/apt-get install build-essential openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake libtool bison subversion pkg-config

rvm install 1.9.3

続いて、1.8.7もインストールして見ます。

rvm install 1.8.7

これで、二つのバージョンがインストールされました。

rvm list

とやると、インストールされているRubyが一覧表示されます。

現在は、デフォルトでカレントが1.9,3になっていると思います。

ruby -v
ruby 1.9.3p327 (2012-11-10 revision 37606) [i686-linux]

ruby 1.8.7を使いたい時は

rvm use 1.8.7

とやれば、切り替えることが出来ます。

ruby -v
ruby 1.8.7 (2012-10-12 patchlevel 371) [i686-linux]

 

ActiveRecordのscopeで作成した条件などをSQLとして出力する

[ruby]scope :active, where(‘deleted_at is null’)[/ruby]
というスコープを設定したとして

この条件を含むSQLをコード内で取得したい場合ってありますよね。

SQL書いてでゴニョゴニョしたい場合とか…。

そんな時には
[ruby]Article.active.to_sql[/ruby]
としてやれば、
[sql]select * from articles where deleted_at is null[/sql]
というSQLが取得出来ます。

参考例
[ruby]# === タグ
class Tag < ActiveRecord::Base
scope :have_article, lambda{|sql| where("tags.id in (#{sql})")}
end

# === 記事
class Article < ActiveRecord::Base
scope :active, where(‘deleted_at is null’)
end

# === ルートコントローラー
class TopController < ApplicationController
def index
# ここで、
# select tag_id from articles group by tag_id
# というSQLが取得出来る
 articles_sql = Article.active.group(‘tag_id’).select(‘tag_id’).to_sql

# ここで、
# select * from tags where tags id in (
# select tag_id from articles group by tag_id
# )
# というSQLが内部で生成される
  @tags_have_articles = Tag.have_article(articles_sql)
end
end[/ruby]

number_with_delimiter (数値をカンマ区切りで出力)

Ruby on Railsで数値を整形する場合、ActionViewには便利なヘルパーがあります。

number_with_delimiter
です。

[ruby]
number_with_delimiter(12345678) # => 12,345,678
number_with_delimiter("123456") # => 123,456
number_with_delimiter(12345678.05) # => 12,345,678.05
number_with_delimiter(12345678, :delimiter => ".") # => 12.345.678
number_with_delimiter(12345678, :delimiter => ",") # => 12,345,678
number_with_delimiter(12345678.05, :separator => " ") # => 12,345,678 05
number_with_delimiter(12345678.05, :locale => :fr) # => 12 345 678,05
number_with_delimiter("112a") # => 112a
number_with_delimiter(98765432.98, :delimiter => " ", :separator => ",")
# => 98 765 432,98

number_with_delimiter("112a", :raise => true) # => raise InvalidNumberError
[/ruby]

DBとは関係ないフォームの項目をバリデートする

[ruby]
class ActiveForm
include ActiveModel::Conversion
extend ActiveModel::Naming
include ActiveModel::Validations

def persisted?; false; end

def initialize(attributes = {})
attributes.each do |name, value|
send("#{name}=", value) rescue nil
end
end
end
</pre>

こんな感じのクラスを一つ準備して、あとはこれを継承して

[ruby]
class SearchForm < ActiveForm
attr_accessor :age
validates :points, :numericality => true
end
[/ruby]

という感じにする。

Rails 3 用のacts_as_paranoid

Rails 2.x系で、論理削除と言ったら、もうこれ!というのが

acts_as_paranoid

でした。

Rails 3.x系では

rails3_acts_as_paranoid
https://github.com/goncalossilva/rails3_acts_as_paranoid

を使います。

インストールの方法は

GemFileに
[shell]gem “rails3_acts_as_paranoid”, “~>0.2.0″[/shell]
と追記して
bundle実行
※Rails3.1の場合は、GemFileに書くプラグインのバージョンが”~>0.1.4″になります。
※Rails3.0の場合は、GemFileに書くプラグインのバージョンが”~>0.0.9″になります。

あとは、論理削除対象のテーブルにdeleted_atカラムを追加し、モデルに
[ruby]class Users < ActiveRecord::Base
acts_as_paranoid
end[/ruby]
という感じで宣言してやればOK。

Rails 3.2.8をUbuntuに一からインストールしてみる

UbuntuにRails3.2.8の実行環境を一からインストールしてみます。

Ubuntuは12.04を使用します。

まずは

Rubyから、と言いたい所ですが、必要パッケージ類から
[shell]sudo apt-get install make build-essential libssl-dev zlib1g-dev \
apache2-mpm-prefork apache2-prefork-dev libapr1-dev libaprutil1-dev \
libcurl4-openssl-dev libmysqlclient-dev[/shell]
MySQLをインストール
[shell]sudo apt-get install mysql-server mysql-client[/shell]
続いて、RubyはUbuntuのパッケージで1.9.3と言うのがあるので、これを入れます。
[shell]sudo apt-get install ruby1.9.3[/shell]
Railsを入れます。
[shell]sudo gem install rails -v3.2.8 –no-ri –no-rdoc[/shell]
riとrdocはいらないので、無しオプション付きで。

MySQLとのコネクタgemをインストール
[shell]sudo gem install mysql[/shell]
Passengerをインストール
[shell]sudo gem install passenger[/shell]
Passengerのコンパイル
[shell]sudo passenger-install-apache2-module[/shell]
Passengerの設定ファイルを作成

passenger-install-apache2-moduleの実行後にpassenger_moduleに関する設定が3行表示されるので、それを

/etc/apache2/conf.d/passenger.conf

に設定

ここからRailsの操作になります。

新しいプロジェクトを作成
データベースはMySQLを使うので、オプション指定
[shell]rails new myproj -d mysql[/shell]
ひとまず、rake -Tをしてみます。
[shell]rake -T[/shell]
rake -T とやると、エラーになります。

Could not find a JavaScript runtime. See https://github.com/sstephenson/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)

これは、JavaScriptのランタイムが設定されていないと言っているので、GemFileに
[shell]gem ‘execjs’
gem ‘therubyracer'[/shell]
という2行を追加して

bundle 実行します。

これで、rake -Tの結果が表示されるようになったと思います。

続いて、MySQL上にデータベースを作成します。
[shell]mysql -uroot -p[/shell]
でMySQLにログイン後、テーブル作成
[shell]create database muproj_development;
exit[/shell]
続いて、実験用にusersテーブルを作ります。
[shell]rails g scaffold users name:string age:integer[/shell]
これで、users用のコントローラやモデルなどが一式作成されます。

データベースにテーブルを作成します。
[shell]rake db:migrate[/shell]
これで、myprojの準備は整いました。
[shell]rails s[/shell]
でmyprojを起動してみましょう。

正常に起動出来たら、ブラウザからアクセス

http://localhost:3000/users