0

スケール設定してないRubyで書かれたHerokuアプリを止める方法

いままでPassenger+Apacheとか、あらかじめforkさせて複数プロセス待機させておくとかしていたから気づかなかった。
Herokuにお金を払ってwebサーバー複数プロセス起動させているなら問題ないと思います。


1リクエストずつしか処理できない

HerokuでRailsやSinatraを使うときは、Rubyで書かれたwebサーバー(thinとか)が1プロセスだけでそのまま動いているのだが、webrick/mongrel/thinあたりは1リクエストずつ順番にしか処理できない。


つまりこれとかがそうなんだけど、
http://shokai.herokuapp.com/base64img
リクエスト処理中のアプリ自身にリクエストを送ってしまうと固まってしまう。引数にURLを渡されて別のサイトにHTTPリクエストするのを想定して作られているアプリとかに有り得るミスだと思う。

上は画像のURLを渡されるとbase64encodeしたimgタグを作ってくれるページなんだけど、ここにhttp://shokai.herokuapp.comとか入れると固まるのだった。
(今は固まらないようにしてある)

リクエストうける→自分自身にリクエストしてbase64encodeしようとする→1リクエストずつしか処理できないので、待たされる→最初のレスポンスを返せない!!
となる。


対策

上の画像をbase64エンコードするアプリの例
get '/base64img' do
halt 400, 'bad request' if params[:url] =~ /^https?:\/\/#{env['HTTP_HOST']}#{env['SCRIPT_NAME']}/

## 処理続き〜〜
end

こんな感じでリクエスト送る前にチェックしてhaltすると良いと思う。

でもこれだけだとbitly等の短縮URLを使うとすり抜けられる。
どのHTTPライブラリを使うかにもよるけど、自動的に30x系リダイレクト処理をしてくれるライブラリを使う場合はいちいちHTTPヘッダのLocationの指す先を調べないと、HTTPリクエスト処理中の自分自身にHTTPリクエストしてしまう。


ちなみにNode.jsだと複数リクエスト同時に処理できるので全然問題無かった。

0

HerokuでSinatra+Memcached使う

Memcached使ってみたかった。なんかキャッシュしなきゃならんので
ブラウザ <---> Heroku <---(cache)---> Twitter
なものを作った。

できたもの http://twiticon.herokuapp.com/

twitterのユーザーアイコンをHTMLに簡単に貼れるやつ。ソースコードはここ

こういうHTMLでアイコンがでる。
<img src="http://twiticon.herokuapp.com/shokai">


小さいのや大きいのも貼れる。

テキストや http://twiticon.herokuapp.com/shokai.txt
JSONでも取得できる http://twiticon.herokuapp.com/shokai.json


使い方は http://twiticon.herokuapp.com に詳しく書いてある。


Twitterのアイコン

ここにAPIがある
GET users/profile_image/:screen_name | Twitter Developers
ユーザーが新しいアイコンをアップロードする毎にURLが変わる。
例えば今の俺のアイコンは https://si0.twimg.com/profile_images/2328443341/tmp_normal.png になってる。


Memcached

ふつうのSQL DBみたいにHDDにデータは保存しないけど、メモリ上で高速に動作する。
あとExpireする期限を決めれる。今回は保存したアイコンURLは12時間で消滅するようにした。
12時間1秒経過すると、再度Twitter APIを使ってURLを取りに行く。


Herokuでmemcached使う

Memcache | Heroku Dev Centerにドキュメントがある。
Herokuのmemcachedはユーザー名とパスワードによる認証があって、SASLというプロトコルを使っているので対応しているgemじゃないと使えない。
dalliというpure rubyのgemが推奨されている。

いつも使ってるCで書かれてるmemcached gemはSASLサポートしてるって記述があるんだけど、使い方がドキュメントに書いてないし面倒臭くなってdalliに落ち着いた。


Herokuにmemcached addon追加した。無料だけどクレジットカード番号登録しないと使わせてもらえない。
% heroku create --stack cedar
% heroku addons:add memcache:5mb


パスワードとかは
% heroku config
で見れる。
MEMCACHE_PASSWORD, MEMCACHE_SERVERS, MEMCACHE_USERNAMEがそれ。
これがHerokuで動かしてるアプリの環境変数に入るので、ENV[‘MEMCACHE_SERVERS’]とかで取り出す。


dalliでMemcached使う

認証なし
require 'rubygems'
require 'dalli'
cache = Dalli::Client.new 'localhost:11211'

Heroku用
cache = Dalli::Client.new ENV['MEMCACHE_SERVERS'], {:username => ENV['MEMCACHE_USERNAME'], :password => ENV['MEMCACHE_PASSWORD']}


で、あとはcacheにset/getすればよい。
# cache 1 hour
cache.set('icon_shokai', 'https://si0.twimg.com/profile_images/2328443341/tmp_normal.png', 3600)

# get icon
puts cache.get('icon_shokai')


ちなみにHerokuのmemcachedは自分のローカル環境からも接続できる。
addons:add memcachedしたらすぐに起動するので、手元で開発してるプログラムで
cache = Dalli::Client.new 'xxxxx.ec2.northscale.net', {:username => '123456heroku.com', :password => 'asdf122345hujiko'}
とか書いても動かせる。太平洋横断してるから遅いけど。


ローカル開発環境にMemcachedをインストール

homebrewやapt-getでインストールできる。
% brew install memcached
% memcached -vv -p 11211
これでlocalhost:11211で起動する。


SinatraでMemcachedを使う

ふつうに上に書いたのを組み合わせてredirectするだけなのでgithub見ればわかると思う。
https://github.com/shokai/twiticon


controllerでは
redirect icon user, size
とだけ書いて、iconって関数は適当にキャッシュもしてくれるように書かれている


あと開発時はローカルのlocalhost:11211のmemcachedを見て欲しいので、環境変数が無かったらconfig.ymlから同じ値を探すようにしたらはかどった。


感想

memcache無料の5MBぐらいだと、tmp_cache gem使ったほうが設定もいらないし楽なのでは・・・

1

Ruby1.9のEncodeでUTF-8-MACをUTF-8に変換できた

Macで「ぱぴぷぺぽ」等のファイル名があると「ぱÿぴÿぷÿぺÿぽÿ」みたいな変な文字になる問題について。

UTF-8-MACをUTF-8に変換するではMacのiconvで変換したけど、
Mac以外で動かすにはApple製iconvを自前ビルドしなければならなくて、でもgccでコンパイル通らなかったので困ってた。

Ruby1.9以降のEncodeを使ったら解決した。

0

ネタ画像検索No.1 tiqav.com のrubygemとか作った

レス画像検索No.1/画像会話なら ちくわぶ


インストール

gem install tiqav


画像を検索、保存

require 'rubygems'
require 'tiqav'

## 検索
images = Tiqav.search 'ちくわ'

images.each do |img|
puts "(id:#{img.id}) #{img.permalink} => #{img.url}"
## 全部保存する
img.save(img.filename)
puts "saved!! => #{img.filename}"
end

## ランダム
img = Tiqav.random
puts img.url
puts img.thumbnail
puts img.glitch


## 幸運
puts Tiqav.feeling_lucky 'ちくわ'

最初はスクレイピングで実装した。
v0.0.1を公開して寝て起きたらseiryoさんがJSON APIを作ってくれてpull requestくれてた。
ありがとうございます。

githubにソースコードおいてある。 https://github.com/shokai/ruby-tiqav


おでん

tiqavの画像検索結果からランダムに画像を入れるサービスを作った。HTMLでスライド作るのに便利だと思う。
http://oden.herokuapp.com/

こういう風に埋め込むと
<img src="http://oden.herokuapp.com/あきらめ.jpg">
リロードする毎にランダムな画像がでる。


githubにソースコードある https://github.com/shokai/oden

0

ruby1.9の関数を1.8.7で使う

backports使ったら1.8で1.9の関数が使えるようになる。
https://github.com/marcandre/backports


requireしておくだけでいい。

require 'backports'

最近Heroku使い始めた関係で、ようやくRuby1.9.2を使い始めた。

1.8のArray#choiceという配列の中からランダムに要素を取り出す関数が、1.9ではArray#sampleになっていたりとか、違いがある。backports読み込んだら、Array#sampleって書いておけば1.8/1.9両方で動く。