Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

27
Crafting Rails4 Applications 7. Managing Application Events with Mountable Engines morimorihoge

description

身内向けにやったCrafting Rails 4 Applicationsの読み会資料です

Transcript of Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

Page 1: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

Crafting Rails4 Applications

7. Managing Application Events with Mountable Engines

morimorihoge

Page 2: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

この章で解説すること• 大きなテーマは三つ– Mountable Engineによって汎用性の高い機能をmountする様なコードを書く• Chap. 5でやったのは Engineそのものを extendしていたが,もっとうまくやれるぜ

– ActiveSupport::Notificationによる Railsの提供する pub/sub event API

– Rack middlewareの仕組みと内部構造• Railsのバックエンドを覗いてmiddlewareを作りつつ動きを見るぜ

Page 3: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

Mountable/Isolated Engines

• 独自に Engineを Extendすると・・・– Routing namespace等が共有されるため,名前の衝突が怖い• rake routesしたときに, Engine拡張して作った plugin routesなのか,アプリ用に作った routesなのか分からなくなる

• HelperやらModelも同様• Mountable Engineを使うと– アプリ側の routerと別々の名前空間で routingが使える

• Isolated Engineを使うと– model/controller/view/assets/helperを pluginの名前空間内に閉じ込められる

Page 4: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

とりあえず rails plugin new• --mountableオプションを付ける

--mountableあり

--mountableなし

Rails.application.routesを直接拡張しないようになる

Mountable engine

Page 5: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

アプリ側で mountする

これで /mongo_metrics以下にmountable engineの routesが組み込まれる

Mountable engine

Routing的にも別々( Engine別)に表示される

Page 6: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

mountの内部• routingの内部的には get/post/put/delete/

resources/resource等は全てmatch()のwrapper• mount()はそもそも挙動が全く別物で, Engineを指定 URL以下に指定し,処理をブン投げる

pp.142env[“SCRIPT_NAME”]/env[“PATH_INFO”]から /mongo_metricsを削除してEngineに投げることで,MongoMetrics::Engine内部ではそもそも/mongo_metrics部分は見えない(元アプリ側の参照はmain_app()で取得可能)

Mountable engine

Page 7: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

Namespace IsolationIsolated engine

Pluginの Engine側に isolate_namespaceを記述することで, Engine内で使うクラスが自動的に namespaceを補完する様になる

pp.133

Page 8: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

ActiveSupport::Notifications API• よくある pub/sub式の event API

– Publish : ActiveSupport::Notifications.instrument(event_name, payload)• Blockを渡すと Block部分の時間が subscriberに通知される

– Subscribe: ActiveSupport::Notifications.subscribe(event_name)

pp.133

pp.134※instrumentは全ての subscriberに通知されるLoggerなんかで使われることを想定

Notifications API

Page 9: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

MongoDB/Mongoid gem

• MongoidはMongoDBを楽に使うためのGem

• Mongoid::Documentをincludeし, store!を実装すれば良いよ!

MongoDB/Mongoid

Page 10: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

MongoMetrics::Engineの実装MongoMetrics::Engine

普通の Railsアプリの様に実装して良いが,MongoMetrics moduleに入れる必要があることに注意( Isolated Engine)

(以下略)

Routingは普通の Railsアプリの様に書ける

Page 11: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

テストコードMongoMetrics::Engine

適当な Routing呼び出しをさせれば Notificationが飛ぶので, test/dummy以下で$ rails new controller Home foo bar bazしておく

main_appでアプリ側を参照できる

Page 12: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

Rack BasicsRack

Rackの基本・リクエストを call()に投げる・ callの返値は [STATUS_CODE, HEADER, RESPONSE_BODY]・ RESPONSE_BODYは eachを実装していること

config.ru

pp.141

config.ruがあるディレクトリで$ rackupすれば Rack serverが起動する( -sでWeb serverを選べる)

Page 13: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

Rack on RailsRack

Railsの config.ru

Page 14: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

Rails Routerと RackのカンケイRack

Config/routes.rbはこんな書き方ができる

Rackの call(env)メソッドそのもの

toが文字列の場合,自動的に呼び出し先を変換している.”post#index”なら以下の Controller.action()を返す( action()の戻り値は call()を実装している)

Page 15: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

Rack middlewareRack middleware stack

Page 16: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

rake middlewareRack middleware stack

インストールされたミドルウェア一覧を取得できる rakeコマンド

この順序を眺めながらメシが食える(上に行くほど先に適用される)

Page 17: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

rake middlewares (1)Rack middleware stack

Page 18: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

rake middlewares (2)Rack middleware stack

Page 19: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

Adding Rack Middlewares

Rack middleware stack

Controllerで任意のmiddlewareを使うには, useすれば良いだけ

Page 20: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

MuteMiddleware

Rack middleware stack

MongoMetricsはそのままだと全てのアクセスに対してログを記録してうるさいので,それを黙らせるmiddlewareを作る

こんな感じでブロックでmuteさせたい

Page 21: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

MuteMiddleware

Rack middleware stack

特に何事も無い感じの実装

Page 22: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

MuteMiddlewareをどこに入れるか?Rack middleware stack

Page 23: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

MuteMiddlewareをインストールするRack middleware stack

MongoMetricsの Engineではデフォルトmute

アプリケーション側ではMuteしたいもので個別にmute

Page 24: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

必要の無い dependencyを減らすGem optimization

Gemspecに railsの dependencyを書くと, ActionMailerや ActiveRecordなど, pluginに本来必要無い gemも dependしてしまう

Dependencyを個別に書くことで, pluginの依存関係はすっきりする# ただし,これをやると dummyアプリケーションの方で ActionMailerや ActiveRecord# に依存する部分の定義を外さないとテストが通らなくなるので注意

pp.149

Page 25: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

Streaming plugin

Another sample of plugin development

MongoMetricsのデータを CSV streamingで出すぜ

Content-Lengthを削除することで streamingになる

詳細は pp.151辺りを参照.見ればわかります

Page 26: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

Rack-level v.s. Rails-level

Another sample of plugin development

Streaming的なことは, Rack middlewareレベルで書くこともできる

Rackアプリとして #eachを streamingぽく返す様に作れば streamingで返せる

Rack-levelで実装した方がmiddlewareの読み込み数が減るのでオーバーヘッドは小さいが, Rails-levelで実装した方がデータサイズに応じた処理などがやりやすい.どっちで実装すべきかは実装時に考えましょう

Page 27: Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines

まとめ• Mountable/Isolated Engineの説明をして,

Mountableな Engineを含むMongoMetricsプラグインを作成したよ!

• Rack middlewareの挙動を追いかけてmiddleware chainを覗いたよ

• 使わない gem dependencyを削って最適化したよ!やったね!