capistranoでrubotyをデプロイするのをよしなに助けてくれるgemを書いた。
デーモン化とPIDファイルの書き出しに対応したruboty v1.3.0が必要になるので要注意。
capistranoでrubotyをデプロイするのをよしなに助けてくれるgemを書いた。
デーモン化とPIDファイルの書き出しに対応したruboty v1.3.0が必要になるので要注意。
Herokuで動かしてたりdockerでデプロイしてたりするとあまり旨味はないのかもしれないけど、普通にcapistranoでデプロイして動かしたいようなときもあるのでやってみた。
下記のスクリプトを例えばyour_ruboty/lib/daemonize.rb
みたいな場所に置いておく。
# nochdir: true - 相対パスでファイルの読み込みをするプラグインがあったときに # 不具合の出ないように # noclose: false - capistranoでデプロイしたときに制御端末を切り離すために Process.daemon(true, false) # killしやすいようにPIDを書き出す require "fileutils" pid = File.expand_path("/tmp/ruboty.pid", __FILE__) FileUtils.mkdir_p(File.dirname(pid)) File.open(pid, "w") { |f| f.write Process.pid }
そして起動時に--load
オプションで上記のスクリプトを指定して読み込んでやればデーモンとして動いてくれる。
$ bundle exec ruboty --dotenv --load lib/daemonize.rb
killしたいときはPIDファイルを見て適当にシグナルを送ってやればいい。
$ kill -TERM $(cat /tmp/ruboty.pid)
PIDファイルとデーモン化のオプションがそれぞれ本体に取り込まれたので、追々上記のようなことは不要になる。
ruboty 1.3.0から--daemon
オプションと--pid <path>
オプションが導入された。
http://aerial.st/archive/...
に来たアクセスを一律にhttp://archive.aerial.st/archive/...
にリダイレクトするようにした。
Rails.application.routes.draw do # (snip) get "archive/*path", to: redirect(subdomain: "archive", path: "/archive/%{path}") end
%{foo}
はparams[:foo]
の値が取れるみたい。
ちなみにデフォルトだと"301 Moved Parmanently"になるらしく、特定のステータスコードを指定する場合はstatus: 302
とかあわせて指定してくれとのこと。
1年ぐらい前に社内ブログにメモしてた内容をまんま転載。 はて、これはduck typingなのか?
Object#acts_like?
を使うとクラスの異なるオブジェクトが同じ振る舞いをするかどうかの判定が手軽にできるようになる。
ActiveSupportではTimeとDateTime、ActiveSupport::TimeWithZoneに共通のメソッドを実装し、それらが入れ替わってもうまく動くようになっている。
これを実装するにあたってにTimeっぽく振る舞うかどうかを判定するためにacts_like?
を使っている。
require "active_support/all" # Timeっぽく動くやつら Time.now.acts_like?(:time) #=> true DateTime.now.acts_like?(:time) #=> true Time.zone.now.acts_like?(:time) #=> true # Timeじゃないやつ Date.today.acts_like?(:time) #=> false
すごく単純で、acts_like_time?
が実装されていればacts_like?(:time)
がtrueになる。
require "active_support/core_ext/object/acts_like" class Bakeneko def acts_like_human? true end end Bakeneko.new.acts_like?(:human) #=> true
ちなみに実装されているかだけを見ているので、その返り値は見られない。 でもわかりやすさのためにもtrueを返すのが良いと思う。
例えばSimpleDelegatorの継承と組み合わせると便利。
通常、SimpleDelegatorを継承したクラスはデリゲート先のクラスとはis_a
の関係にならない。
require "delegate" class Neko; end class Bakeneko < SimpleDelegator; end neko = Neko.new bakeneko = Bakeneko.new(neko) neko.is_a?(Neko) #=> true bakeneko.is_a?(Neko) #=> false
とはいえここでいうbakeneko
はneko
と同じように振る舞うことができるのだから、それを判別したい。
ここでacts_like?
の出番。
require "active_support/core_ext/object/acts_like" class Neko def acts_like_neko? true end end class Bakeneko < SimpleDelegator # SimpleDelegator側がオリジナル側のrespond_to?も見てくれるので # 実際はこのケースでは別途定義する必要はない def acts_like_neko? true end end neko.acts_like?(:neko) #=> true bakeneko.acts_like?(:neko) #=> true
このようにすることで、acts_like?
を使うことで異なるクラスでも同じ振る舞いをするオブジェクトの判定ができるようになる。
ひとつのクラスが複数の振る舞いを持つ場合にも対応できる。 例えばDateTimeはDateのようにもTimeのようにも振る舞える。
DateTime.now.acts_like?(:date) #=> true DateTime.now.acts_like?(:time) #=> true
振る舞いの判定がクラスとは別個に行えるので自由度が増える。 (とはいえ全く違う役割をもたせるのはクラス設計的にどうなのという感じではある)
acts_like_xxx?
を直接呼べばよいのではレシーバに実際にそのメソッドが定義されていない場合にエラーになるのでNG。
require "active_support/all" Date.today.acts_like_time? #=> NoMethodError
一方でacts_like?
は内部的にrespond_to?
を呼んでいるだけなので、上記のような心配をする必要が無い。
knife-solo v0.5.0から
knife solo bootstrap my.host.jp -x root
するsome_user
でknife solo cook my.host.jp -x some_user
するとしたときにエラーが発生するようになった。
原因はknife-solo v0.5.0でSSHのControlMasterがサポートされるようになったことで、これがあると最初にsshしたときのコネクションをホストごとに使いまわし続けてしまうためらしい。
対応方法としては3つあって、
knife-soloを叩くときに指定できる。
$ knife solo cook my.host.jp --ssh-control-master no
ただ毎回は面倒くさいので設定でなんとかしたい。
~/.ssh/config
に次のように記載する。
Host * ControlMaster no
ただ無効にしちゃうとControlMasterの恩恵を受けられなくなるので、それはそれで避けたい。
OpenSSH 5.9から入ったControlPersistでコネクションのタイムアウトを設定できるようになったとのことなので、~/.ssh/config
に次のように記載する。
Host * ControlPersist 10 # 10秒で切る
ちなみに手元のsshのバージョンは次のコマンドで調べられる。
$ ssh -V OpenSSH_6.9p1, LibreSSL 2.1.8
grepして見つけたファイルをパイプしてそのままAtomで開きたいと思って作ってみた。
$ git grep -l Neko | opipe -a Atom
でもよくよく考えてみたら
$ atom $(git grep -l Neko)
でいけるわよね…。
xargsさん
— 高度に発達した技術的な問題 (@fuka_bot_) 2016, 1月 24
あああ、xargs
でいけた…。
$ git grep -l Neko | xargs atom
なんで思いつかなかったんだろう。
http://ws-plan.com/tsukuru/syafutu.html とか。いつも少なめにしか作ってないので、脱気まではやってない。
瓶は無印で売ってるものがお手軽、お手頃。