rails + jenkinsでgithubにpushしたらテストというところまでは下記を参照してください。

ウェブオペレーション継続的デプロイというキャッチーな単語を知ったので試してみた。

kowabana Config [Jenkins]

継続的デプロイなんつっても、上記の様にいつものテストにcapのタスクを追加するだけ。簡単。

kowabana [Jenkins]

githubにpushされると勝手にjenkinsが動き出して…

怖話 | スマホで怖い話

ステージング環境にデプロイ。

これでデザイナーの@machidaさんがgit pushした時も勝手にステージング環境が最新になる。デザインが変わっただけでも頻繁にデプロイされるので問題点などが議論し易い。(特にスマホサイトは実機からアクセス出来る環境があると便利。)

最近はデザイナーも簡単にGithubが使える環境が揃ってきたので、テスト・開発・チェックイン・デプロイというサイクルにデザイナーが入る良いタイミングかも。

デザイナーのためのGithub for Mac の使い方「リポジトリ作成編」 - KUROIGAMEN(黒い画面)

% rake
`include Capybara` is deprecated please use `include Capybara::DSL` instead.

include Capybaraがdeprecatedになってたので指示通り書き換えました。

# test/test_helper.rb:
class ActiveSupport::TestCase  
  (...)
  class ActionDispatch::IntegrationTest 
    include Capybara::DSL      
    Capybara.app = KowabanaJp::Application
  end
end

Unit::TestとCapybaraでのIntegrationTestは簡単なのにちゃんと動く(バグを見つけたりデグレを防ぐ役割をちゃんと果たすという意味で)のでお気に入りです。

unicornのデフォルトとportが被ってるので変更した。Debianパッケージ版jenkinsは下記に設定がある。

# /etc/defaults/jenkins:
# port for HTTP connector (default 8080; disable with -1)
#HTTP_PORT=8080
HTTP_PORT=8000

毎日昼飯をどこで食べるのかに本業より頭を使ってる気がするので自動化した。

require 'rubygems'
require 'nokogiri'
require 'open-uri'
require 'mail'

api_key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
version = 'v1.0'
station_ids = ['2800', '2811'] # hatagaya, hatsudai
page = 1
entries = 10
total_entries = 100

restaurants = []

station_ids.each do |station_id|
  while page * entries < total_entries
    url = "http://api.gourmet.livedoor.com/#{version}/restaurant/?api_key=#{api_key}&station_id=#{station_id}&sort=total"
    doc = Nokogiri::XML(open("#{url}&page=#{page}"))
    total_entries = doc.xpath('/results/total_entries').text.to_i

    doc.xpath('/results/restaurant').each do |restaurant|
      restaurants << {:name => restaurant.xpath('name').text,
                      :link => restaurant.xpath('permalink').text}
    end

    page += 1
  end
end

restaurants.shuffle!

body = ''
restaurants[0, 10].each_with_index do |restaurant, i|
  body += <<-EOS
#{i + 1}. #{restaurant[:name]}
#{restaurant[:link]}

  EOS
end

mail = Mail.new do
  from    'komagata@gmail.com'
  to      'komagata@gmail.com,machidanohimitsu@gmail.com'
  subject "Today's recommended restaurants"
  body    body
end

mail.delivery_method :sendmail
mail.deliver

ライブドアグルメの初台、幡ヶ谷の店からランダムで10個、12時になったらメールしてくれる。(これを前のエントリーの要領でcronに登録する)

Today's recommended restaurants - komagata@gmail.com - Gmail

こういうメールが届く。

これをWebサービスとして公開し、ユーザー同士で同じ店に行くことになったら偶然を利用してマッチングするというのを考えた。でもkowabana.jpをやりたいので誰か作って。

Lokkathon #4 : ATND

LokkathonはLokka + Hack + Marathonです。 Lokkaに関する作業をモクモクとするイベントです。会場は用意されますが、Lingrのチャットのみでの参加も可能です。(むしろ推奨)

予定通り毎週やってきます。スゴイ捗るんですが、スゴク疲れたので3時間から2時間にしました。あと、腹が減るので飯食ってからもしくは食いながらがいいと思います。

時間中はLingrにみんな常駐しますので何か言いたいとか聞きたいなどあれば是非。

0 12 * * 1,2,3,4,5 bash -c 'source ~/.rvm/scripts/rvm; rvm ruby-1.9.2p290@default exec ~/code/random_lunch/random_lunch.rb'

Use bash -c and rvm exec

コレ、解決してませんでした。

複数カラムに対してORDER指定は可能だけど、ASC,DESCの指定が最初の一個しか効かない。ソースを読んでも確かにそうなってる。

それはquery_postsの仕様で少なくとも今日時点ではそうなってる。WordPress Query APIはSQLのBad Wrapperだ。

具体的には勝手なパラメーターを追加することで強制的にORDER句を指定することにした。

// functions.php
function force_order($orderby, $query) {
	return $query->get('force_order') ? $query->get('force_order') : $orderby;
}
add_filter('posts_orderby','force_order');

こんな感じで使う。

query_posts('force_order=menu_order ASC, ID DESC')

俺のこの対応方法も酷い。

この「ORDERに複数指定可能だったら当然ASC,DESCも指定可能だろう」という期待が通用しないのがWordPressという修羅の国。

その肌感覚を散々味わってきたハズが、最近触ったpostMashというプラグインのコードがマトモだったことで油断してた俺をWordPress Query APIのコードが打ちのめした。

僕の仕事はWeb開発者ですが、時々、

「何が仕事で何が仕事でないんだろう?」

と思うことがあります。

  • Webと全く関係無い趣味のコードを書いてる時、それは仕事なのか。 
  • FacebookのEmpires & Alliesをやってる時、それは仕事なのか。
  • レストランで食事をする時、それは仕事なのか。 
  • くだらないジョークをTweetする時、それは仕事なのか。

仕事と遊びを区別することなどナンセンスだという考えもありますが、ある時、仕事の条件についてのアイデアを思いつき、以来気に入って使っています。

そのアイデアとは「URLを持ったら仕事だ」というものです。

  • 趣味のプログラムをネットにアップロードし、URLを持ったらそれは仕事です。
  • Empires & Alliesをプレイして感じたことをブログに書いたら、URLを持つのでそれは仕事です。 
  • レストランで食事をしてその写真をInstagramにアップロードしたら、URLを持つのでそれは仕事です。 
  • ジョークTweetもURLを持つのでそれは仕事です。(自分のサービスのマーケティングになっているかもしれません)

逆に、どんなに充実して深い考察を得たとしても、URLを持たず、ネットからアクセス可能な形を持たないとしたらそれは遊びです。

極端なアイデアなので全くの的外れかもしれません。しかし僕は直感的に気に入って使っています。

怖話.jpをHerokuからさくらVPS 512に移行したのでパフォーマンスを測ってみました。(怖話.jpのアプリに大きく依存しています。また日本向けのサービスなので手元から計測したためネットワーク的にHerokuは不利です。)

  • Heroku
    • kowabana.jp
  • さくら
    • oulu.fjord.jp

さくらVPSではnginx + unicorn + mysqlを使っています。

Apache Bench

% ab -n 1000 -c 100 http://kowabana.jp/
Requests per second:    6.12 [#/sec] (mean)
Time per request:       163.526 [ms] (mean, across all concurrent requests)
% ab -n 1000 -c 100 http://oulu.fjord.jp/
Requests per second:    38.29 [#/sec] (mean)
Time per request:       26.114 [ms] (mean, across all concurrent requests)

Chrome Developer ToolsでのDOMContent event fired

トップページをスーパーリロードした場合。

  • Heroku
    • 1.69s
  • さくら
    • 540ms

結果

人気サイトじゃないのでabの結果はそれほど気にしてませんが、DOMContent event firedはパラパラと残りのパーツが表示されるのは別として、ユーザーにとって「ページが表示された」と感じる実際の時間に近いと思います。それが3倍違うというのは結構な違いだなと思います。確かに体感速度でも速くなったように思います。

怖話.jpをHerokuからさくらVPS 512に移行することにしました。理由は下記です。

  • DB容量が無料の範囲を大幅に超えている。(一応容量オーバーしていても使える)
  • slug(リポジトリ)のサイズが制限(100MB)を超えた。(これはオーバーしているとpushできない)
  • ファイルアップロードが必要になった。(S3を使えば対応は可能)
  • 回線が遅い。(us westとかなので仕方が無い)

Amazon EC2にしなかった理由はまだ人気が無いのでお金をかけられないからです。もし売上が月数十万になったら移行します。

DB移行

HerokuのDBはPostgreSQLです。さくらVPS 512ではMySQLを使うことにしました。

現在のDB容量は37.4MB。レコード数は約2万件ぐらいです。heroku db:pullをしたら1時間たっても終わる気配がなかったので次の方法を取ることにしました。

  • herokuからローカルにpg_dumpを持ってくる。
  • ローカルのpostgresにpg_restore。
  • ローカルのmysqlにtapsサーバーを立てる。
  • ローカルのpostgresからtapsサーバーへpush。
  • ローカルのmysqlからmysqldump。
  • さくらVPSのmysqlにrestore。

大したデータ量じゃないのに、要はネット経由でtapsするととてつもなく時間がかかるのです。

「これ絶対もっと楽な方法あるよなあ」

などと思いながら作業しました。