2012年08月19日

暴走するJenkins神の怒りを鎮める儀式を執り行いました

単にJenkins先生を1.464から1.476にバージョンアップしたら やたらめったら不安定になったのですよ。

具体的には、あれこれリンクをクリックしてページ遷移していると 10回もクリックしたらもう暴走。 Javaさんがコア1個食い潰してくださいましてURL叩いても無反応という感じで。

仕方がないから公式サイトを見てみたら、 とりあえず1.477が出ていたのでそれに乗り換えてみたけども やっぱりお怒りは鎮まらず。

ググっても特に何か情報があるわけでもないので 本体は実は平気でプラグインが悪さしている予感。

ということでいくらかのプラグインを無効にしてみた。 割と余計なプラグイン入れまくってるからね。

ってことで無効にしたプラグイン一覧

  • Girls Plugin
  • Hudson global-build-stats plugin
  • build-metrics
  • Gerrit Trigger
  • Jenkins Jabber notifier plugin

こんなところか。意外と少ないな。 一応無効にしたやつらの紹介してみる。

Girls Pluginは、Jobの成功状況で 女の子の画像の表示を切り換えるというプラグイン。 パターンが少ない上に趣味がアメリカーンなのですぐ飽きる。

global-build-stats と build-metricsは それぞれのJobの状態なんかを記録してくれるようなものらしいけど 結局よくわかってないからとりあえず無効化。

Gerrit Triggerは、 GerritとかいうGitのツールからbuildのtriggerを引いてくれるものらしいけど 個人プロジェクトじゃあそもそもGerritを使わないよねってことで無効化。

Jabber notifier pluginは、その名の通り Jabberで通知してくれるはず。 JabberってことはGoogle Talkもいけるはず。 なんだけど設定がうまくいってないしこいつが一番不安定にさせてくれてる気もしてたので無効化。

という感じ。

どうも、プラグインによっては最近のJenkinsさんと相性が悪いみたいね。

こいつらとりあえず無効化したら大分安定したけど その後も数回暴走しているのでさらに無効化するとか必要かもなあ……。

posted by 麦汁 at 22:26 | Comment(0) | TrackBack(0) | Jenkins | このブログの読者になる | 更新情報をチェックする

2012年08月18日

Railsでstate_machineってgemの状態、イベントをDBから持って来て動的追加する調査

Rails3でstate_machineでもにゃりたいのでちょろっと調査。

もにゃりたいってのが、こう、状態をとりあえずDBにぶっこんで それをいじることでコードいじらずに状態を増やしたりできないかなあなどと。

ってことでとりあえずプロジェクトを立ち上げる。

$ rails new state_machine

別に名前はなんでもいいけどこれがわかりやすいでしょう。 proto_ とか付けてもよかったな。まあいいか。

で、プロジェクトの中に移動してGemfileを開いて

gem "state_machine"

を追加。 そして

$ bundle install

準備はとりあえずこんなもんでいいか。 この際rspecなんて、テストなんて要らぬ! (この手の調査系の記事って、見る側としてはテストが書かれてないのが悲しかったりするけどめんどい)

で、とりあえずなんか状態がありそうなモデルでも考える。

自動販売機でいいか。よく状態遷移マシンの題材になる気がするし。 他にもオブジェクト思考の話でわりとよく出る気がするな。 そっちだと、Animalクラスを継承したDogとCatを鳴かせたらワンとかニャーの方が印象強いけど。

で、「自動販売機」で調べたら「coin machine」って言葉もあるのな。それを使おう。

$ bundle exec rails g model CoinMachine state

めんどくさいからstateだけあればいいよね。 あとめんどくさいからmodelだけでいいよね。

さて、これ以上進む前にそもそもどういう状態があって どういう状態に遷移するのか考えようか。

電源をONにしたりOFFにしたりコイン入れたり何か買ったりする感じかな。 投入額については無視。めんどい。

ってことでstate_machineを使った場合のstaticな定義の書き方で書いてみると

state_machine :initial => "動いてない" do
  event "電源オン" do
    transition "動いてない" => "動いている"
  end

  event "コイン投入" do
    transition "動いている" => "金入ってる!!"
  end

  event "ボタン押す" do
    transition "金入ってる!!" => "動いている"
  end
  after_transition "金入ってる!!" => "動いている", :do => :sell_out

  event "電源オフ" do
    transition all => "動いてない"
  end
end

def sell_out
  puts "ほらよ。くれてやる。このいやしんぼめっ"
end

コイン投入して電源落としたら吸われてなくなる素敵仕様。 っていうか返却機能がない。気にしない。ガチャガチャと一緒だ。

あとはこの情報をDBから持ってくるから

$ bundle exec rails g model Transition event from to

って感じで適当にモデルでも作っておく。

あと地味にafter_transitionもあるので

$ bundle exec rails g model Hook timing from to do

timingは、beforeかafterかを入れるぐらい。 このあたりがあればきっとなんとか耐えられるだろう。

ってところで

$ bundle exec rails c

とか適当にやってみ……たかったけどTerminalから日本語打つのがなんかダメなので、 "transitions.rb"とかいうファイル名で

# -*- coding: utf-8 -*-
Transition.create!(event: "電源オン",   from: "動いてない",   to: "動いている")
Transition.create!(event: "コイン投入", from: "動いている",   to: "金入ってる!!")
Transition.create!(event: "ボタン押す", from: "金入ってる!!", to: "動いている")
Transition.create!(event: "電源オフ",   from: "all", to: "動いていない")

Hook.create!(timing: "after", from: "金入ってる!!", to: "動いている", do: "sell_out")

とか用意して

$ bundle exec rake db:migrate

しておいて

$ bundle exec rails runner transitions.rb

でTransitionとHookの投入。

それで、次はそれらを元に動的にCoinMachineのあれこれを定義するわけだ。

その中身は大体こんな感じ。

# -*- coding: utf-8 -*-
c = CoinMachine.new
p c
c.send("電源オン")
p c
c.send("コイン投入")
p c
c.send("ボタン押す")
p c
c.send("電源オフ")
p c

で、CoinMachineモデルの方も調整。

# -*- coding: utf-8 -*-
class CoinMachine < ActiveRecord::Base
  attr_accessible :state

  state_machine :initial => "動いてない" do
    Transition.all.each do |tr|
      event tr.event do
        transition (tr.from == "all" ? all : tr.from) => tr.to
      end
    end

    # after_transition
    Hook.find_all_by_timing("after").each do |hook|
      after_transition hook.from => hook.to, :do => hook.do
    end
  end

  def sell_out
    puts "ほらよ"
  end
end

allだけ特別扱いしているけど 基本的にTransitionのレコードからそのまんま動的にeventを書いて、 同じようにHookもやってるって感じ。

まあ https://github.com/pluginaweek/state\_machine/ の中の "Static / Dynamic definitions"の定義がごちゃごちゃしているから 適当に簡略化してみただけ。

でまあ実際に実行してみると

$ rails r state_machine_test.rb
#<CoinMachine id: nil, state: "動いてない", created_at: nil, updated_at: nil>
#<CoinMachine id: 6, state: "動いている", created_at: "2012-08-14 13:50:12", updated_at: "2012-08-14 13:50:12">
#<CoinMachine id: 6, state: "金入ってる!!", created_at: "2012-08-14 13:50:12", updated_at: "2012-08-14 13:50:12">
ほらよ。くれてやる。このいやしんぼめっ
#<CoinMachine id: 6, state: "動いている", created_at: "2012-08-14 13:50:12", updated_at: "2012-08-14 13:50:12">
#<CoinMachine id: 6, state: "動いていない", created_at: "2012-08-14 13:50:12", updated_at: "2012-08-14 13:50:12">

で、ここでDBに入れる利点として 後からeventだの状態だのを追加できるってのがあるよね。 っていうか当初の目的それだった。

ってことでやってみる。

# -*- coding: utf-8 -*-
c = CoinMachine.new
p c
c.send("電源オン")
p c
c.send("コイン投入")
p c
c.send("ボタン押す")
p c
Transition.create!(event: "蹴る", from: "all", to: "壊れた")
c.reload
c.send("蹴る")
p c
c.send("電源オフ")
p c

ちょっとまって。 このコードを毎回実行すると、 CoinMachineが増え続けるのはともかく Transitionのレコードも増え続けるぞ。 それは良くない。 いっそ一旦全部消して、生成から削除までするようなコード書こう。

# -*- coding: utf-8 -*-

ActiveRecord::Base.transaction do
  Transition.create!(event: "電源オン",   from: "動いてない",   to: "動いている")
  Transition.create!(event: "コイン投入", from: "動いている",   to: "金入ってる!!")
  Transition.create!(event: "ボタン押す", from: "金入ってる!!", to: "動いている")

  Transition.create!(event: "電源オフ",   from: "all", to: "動いてない")

  Hook.create!(timing: "after", from: "金入ってる!!", to: "動いている", do: "sell_out")

  c = CoinMachine.new
  p c
  c.send("電源オン")
  p c
  c.send("コイン投入")
  p c
  c.send("ボタン押す")
  p c
  Transition.create!(event: "蹴る", from: "all", to: "壊れた")
  c.reload
  c.send("蹴る")
  p c
  c.send("電源オフ")
  p c

  Transition.delete_all
  Hook.delete_all
  CoinMachine.delete_all
end

はうう。これってもしかしてUnitTestなりRSpecなり書いた方がよくね? まあいっか。実行。 これでイベントと状態が動的に追加できますように!

% rails r state_machine_test.rb
#<CoinMachine id: nil, state: "動いてない", created_at: nil, updated_at: nil>
#<CoinMachine id: 7, state: "動いている", created_at: "2012-08-14 13:51:14", updated_at: "2012-08-14 13:51:14">
#<CoinMachine id: 7, state: "金入ってる!!", created_at: "2012-08-14 13:51:14", updated_at: "2012-08-14 13:51:14">
ほらよ。くれてやる。このいやしんぼめっ
#<CoinMachine id: 8, state: "動いている", created_at: "2012-08-14 13:52:11", updated_at: "2012-08-14 13:52:11">
/Users/mugijiru/.rvm/gems/ruby-1.9.3-p125/gems/activemodel-3.2.6/lib/active_model/attribute_methods.rb:407:in `method_missing': undefined method `蹴る' for #<CoinMachine:0x007fdedbafa728> (NoMethodError
)        from /Users/mugijiru/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.6/lib/active_record/attribute_methods.rb:149:in `method_missing'
        from state_machine_test.rb:19:in `<top (required)>'
        from /Users/mugijiru/.rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.6/lib/rails/commands/runner.rb:51:in `eval'
        from /Users/mugijiru/.rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.6/lib/rails/commands/runner.rb:51:in `<top (required)>'
        from /Users/mugijiru/.rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.6/lib/rails/commands.rb:64:in `require'
        from /Users/mugijiru/.rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.6/lib/rails/commands.rb:64:in `<top (required)>'
        from script/rails:6:in `require'
        from script/rails:6:in `<main>'

うむ。やはり動的追加はできなかった。 そうだよなーRailsってClassは初めで全部読んでおっしまーいだもんなー。 だからGithubの例はあんなに複雑なんだな!

ってことで上のコードを書いて失敗したこともあって、 Githubの例についての理解が深まったので そっちに書き換えてみる。

まずはmachineメソッドを用意。

# -*- coding: utf-8 -*-
class CoinMachine < ActiveRecord::Base
  attr_accessible :state, :machine
  attr_writer :machine

  def machine
    coin_machine = self
    @machine ||= Machine.new(coin_machine, initial: "動いてない") do
      Transition.all.each do |tr|
        event tr.event do
          transition (tr.from == "all" ? all : tr.from) => tr.to
        end
      end

      # after_transition
      Hook.find_all_by_timing("after").each do |hook|
        after_transition hook.from => hook.to, :do => hook.do
      end

      after_transition do
        coin_machine.state = coin_machine.machine.state
        coin_machine.save!
      end
    end
  end
end

適当にGithubの例のと自分のコードをmergeしてみた感じ。

そしてMachineクラスを生成。 これはGithubのほぼそのままで、 hook のメソッドをとりあえずこっちに持ってきた。

class Machine
  def self.new(object, *args, &block)
    machine = Class.new do
      def definition
        self.class.state_machine
      end

      def sell_out
        puts "ほらよ。くれてやる。このいやしんぼめっ"
      end
    end
    machine.state_machine(*args, &block)
    machine.new
  end
end

で、この変更に伴いテスト用のコードも変更。

# -*- coding: utf-8 -*-

ActiveRecord::Base.transaction do
  Transition.create!(event: "電源オン",   from: "動いてない",   to: "動いている")
  Transition.create!(event: "コイン投入", from: "動いている",   to: "金入ってる!!")
  Transition.create!(event: "ボタン押す", from: "金入ってる!!", to: "動いている")

  Transition.create!(event: "電源オフ",   from: "all", to: "動いてない")

  Hook.create!(timing: "after", from: "金入ってる!!", to: "動いている", do: "sell_out")

  c = CoinMachine.new
  p c.state
  c.machine.send("電源オン")
  p c.state
  c.machine.send("コイン投入")
  p c.state
  c.machine.send("ボタン押す")
  p c.state
  Transition.create!(event: "蹴る", from: "all", to: "壊れた")
  c.machine = nil
  c.machine.send("蹴る")
  p c.state
  c.machine.send("電源オフ")
  p c.state

  Transition.delete_all
  Hook.delete_all
  CoinMachine.delete_all
end

ちなみにreloadじゃあダメだったのでこっそりとc.machineにnilを放り込んだりしている。

そして結果。

$ rails r state_machine_test.rb
nil
"動いている"
"金入ってる!!"
ほらよ。くれてやる。このいやしんぼめっ
"動いている"
"壊れた"
"動いてない"

初めにnilって言われるのが若干気にはなるがまあこんなもんでいいや。

posted by 麦汁 at 12:43 | Comment(0) | TrackBack(0) | rails | このブログの読者になる | 更新情報をチェックする

2012年08月02日

Firefoxのタブ幅が狭くてもclose buttonを出しっぱなしにする方法(備忘録)

Firefoxでは ツリー型タブ というアドオンを使用していて そいつはタブが左側(設定によっては右)に来るから 画面があまり狭くならないように タブの方を若干狭めて使用している。

なんだけども、そうすると閉じるボタンが消えてしまって大分悲しい。 幅を取ったら復活するんだけども、タブの幅は広くしたくない。

というわけでそれをどうにかするのを調べた。2回目。 2回目なのに結構手間取った。くっそ。 ということで今日こそ自分のところの記事に残して すぐに見付けられるようにしてやる。 記事データはローカルにも保存しているし。

答えは フォクすけの Firefox 情報局 - すべてのタブに常に「×」ボタンを表示するには? に載ってるんだけども、

  1. about:configを開く
  2. フィルタ欄に"browser.tabs.tabClipWidth"と入力する
  3. 1つに絞られるはずなのでそこの値を 0 に書き換える

以上。

これで次回からはすぐにググって見付けられて幸せになれるはず。

タグ:Firefox 設定
posted by 麦汁 at 21:11 | Comment(0) | TrackBack(0) | Firefox | このブログの読者になる | 更新情報をチェックする