rubyのBatchLoaderを使ってみた
私はrubyでGraphQLを何度か触れていたけれども、以前からN+1問題に何度か手を焼いていて、ちょうど仕事でそれの対応がてらBatchLoaderを使うことがあった。
ただ調べた感じ日本語の記事はほとんどなくて使い方とかもそんななかったのでここに残しておく
BatchLoaderとは
GitHub - exAspArk/batch-loader: Powerful tool for avoiding N+1 DB or HTTP queries
簡単に言えばN+1問題を対策するためのgem
N+1問題の対策としてよく使われるのはbulletで検知してpreloadするというものだと思うが、こちらはメソッドを指定して明示的に対策できる。
インストール
いつものようにgemfileに
gem 'batch-loader'
もしくは
gem install batch-loader
rails appで使う場合は
config/application.rb に
class Application < Rails::Application config.middleware.use BatchLoader::Middleware end
graphqlの場合は
class GraphQL::Schema use BatchLoader::GraphQL end
簡単な使い方
コードを出すとこんな感じ
class User has_many :posts end class Post belongs_to :user end
みたいな時に
BatchLoader.for(post.user_id).batch do |user_ids, loader| User.where(id: user_ids).each { |user| loader.call(user.id, user) } end
で
SELECT * FROM posts WHERE id IN (1, 2, 3) SELECT * FROM users WHERE id = 1 SELECT * FROM users WHERE id = 2 SELECT * FROM users WHERE id = 3
が対策できる。
また、batchの引数でちょっとした設定を追加できる。
例として
batch(default_value: [])
なら初期値を[]に設定できる。
さらにN+1が起こりうる処理が複数ある場合は
user = User.where(id: [1,2,3]) key ={ hoge: user.hoge, # N+1が起こる処理1 fuga: user.fuga, # N+1が起こる処理2 hide: user.hide # N+1が起こる処理2 } BatchLoader.for(key).batch do |hoges, fugas, hides, loader| loader.call(user.hoges, user) loader.call(user.fugas, user) loader.call(user.hides, user) end
一応このような使い方ができる。
ただ、起こりうるメソッドの内部に埋め込む方がいい感じの形のように思う。
つまり
class User def hoge(post) BatchLoader.for(post.user_id).batch do |user_ids, loader| where(id: user_ids).each { |user| loader.call(user.id, user) } end end end User.hoge(post)
の方がおそらく開発者の意図に沿っていると思う。
オプション
引数* | デフォルト値* | 説明* |
---|---|---|
item | - | バッチ処理に使用されるアイテム。 |
default_value | nil | デフォルト値 |
cache | true | 同実行間のキャッシュを無効にするなら false |
replace_methods | true | バッチング後にメソッドを置き換えるのではなく、#method_missingを使用する場合はfalseを設定します。 |
key | nil | バッチブロックを一意に識別するためのカスタムキーを渡します。 |
items | - | バッチ処理のために収集されたアイテムのリスト |
loader | - | バッチで読み込まれた値をロードするために呼び出されるべきラムダ |
args | {default_value: nil, cache: true, replace_methods: true, key: nil} | バッチメソッドに渡される引数 |
(readmeからdeelp翻訳)
どういう時に使うべきなのか
おそらく基本的にはpreloadしていく方が楽だと思う。例なんてまさにそうで、一文加えてばいいだけの話だろってなるだろう。
ただそれでも複雑に絡み合ったテーブル設計になってしまった場合はpreloadしていくのも辛くなってくる。
その中で、要件上速度を落とせない部分、N+1が起こった場合バグだったりユーザーから大きく不評をえてしまう様な処理を書く際に、
preloadして対策したけど思わぬquery発行があって遅くなってしまったなんてことが起こらないよう
BatchLoaderでこの処理だけは絶対にN+1が起こらない様にすることで安全に作ることが出来る。
参考資料
みんな大好き週間Rails 日本語だとここくらいしか見つからなかった。
techracho.bpsinc.jp
上リンクで書かれていた有名そうな記事(英語)
engineering.universe.com
サポートしてる GitLabで書かれている記事 英文でGraphQL向けだけれども読みやすい
docs.gitlab.com
最後に公式
github.com
ペースメーカーをつけた
私はここ数年心臓の調子が悪く*1、去年は手術して埋め込み型ループレコーダーをつけた
その結果が11/9に出ましたので、それからの経過を自分語りします。
あと、想像力豊かな方にはグロ注意です。
概要とその時の検診とか
11/9の検診で術後一年経ったと言うこともあり、機器のチェックを兼ねてちょっと大掛かりな定期検診を行いました。
埋め込み型ループレコーダーは心停止した瞬間をその機械に記録するだけで、その記録を確認すると言うことはできなかった。今回はその情報を取得する作業でした。
一年間身体に入ってた機械(埋め込み型ループレコーダー)と、比較用のAterm MR05NL pic.twitter.com/6x8lEbukAL
— ぎんさんさんさん (@ImpureSilver11) 2020年12月18日
こういうの体に入れてました。
これで見てみるとこの一年で心停止したのは5回、直近で心停止した時は8/23の9:30くらいだということで。
当時の私は趣味のランニングを終えて一休みしてる時だった。
🍭
— ぎんさんさんさん (@ImpureSilver11) 2020年8月23日
その時のツイート
なにいっとんねんと言う感じだけど、この通り元気なのは確か。
でも実際この状況って結構危ういもので、起きている状態で心停止すると言うのは突然死につながるようです。その時先生に、このままの状態だと死亡率年10%くらいですね。って真面目に言われて、(これ、ドラマとかで見たやつだ!)と思わず笑っちゃいましたね。
手術に関して
手術に関するスケジュールはあらかじめ渡されてて、前日に入院して検査検査で手術自体は2時間ほど、その後は丸一日絶対安静、一週間はお風呂や激しい動きは禁止、退院後は3~6ヶ月ほど左腕を上げる事や重いものを持ち運ぶ作業は禁止と言う流れ
病気や年齢によってはカテーテル*2入れるって言われてたけど私はなかった。個人的には一番安心した瞬間
実際の手術
ペースメーカーの埋め込み手術は局部麻酔で行われるが、基本的に局部麻酔による手術は最初の麻酔注射だけが痛い。それ以降の作業は麻酔が効いてるので痛くない。言えば麻酔を追加してくれるので問題はない。
それでも皮膚が引っ張られたり何か突っ込まれる感覚はあって、今こう言う段階なんだなって言うのは見えなくても理解できた。
今回は長い時間手術するので、呼吸不全で酸素がなくならないよう鼻に管を入れられたが、実際これはとても便利で途中から呼吸が弱くなってきた。加えて麻酔の影響で意識も朦朧としていたので思った以上に体力を持っていかれた。
しかし私は好奇心で動く人間なので、手術中はなにが起こってるんだろう??今なにしてるんだろう?あっ今液体が肩から垂れた!これは消毒液かな?血液かな?みたいなこと想像しながらワクワクしながら見てた。疲れるけど楽しい(?)時間だった。
手術終了したのが18:00くらい。
術後は左肩を上げる行為や力を入れる行為が禁止される。そのため肘をついて身体を上げることができない。そのため、手術してから病室のベッドまで横になって運ばれた。
手術後
手術中は全然わからなかったが、術後は疲労感と尿意に催された。*3
ベッドに戻ったのと夕食の時間が被ったため、そのまま食事をとって用を足して*4そのまま眠った、消灯より1時間以上早い19時か20時あたりだった。21時に点滴が外されたのだけれども、それすら気づかない疲労だった。
手術が3時間、思った以上に体力が取られて食事してすぐ寝てしまった。点滴外されたタイミングも覚えてない。
— ぎんさんさんさん (@ImpureSilver11) 2020年12月17日
昼にようやっと自力でトイレ行っていいって通達きた。夕方には術後24時間なのでめっちゃでっかいテーピングが取れる。着替えとかも出来そう。ようやっと人間に戻れる。
— ぎんさんさんさん (@ImpureSilver11) 2020年12月18日
この間ずっとベッドに拘束で飯食うかツイッター見るかしかできなかった。
手術後1~3日目くらいは患部の痛みが続いていた。看護師さんに言えば痛み止めをもらえるので、辛い時はそれで我慢してた。
術後2日目40時間経過で院内歩行の許可が出るっと
— ぎんさんさんさん (@ImpureSilver11) 2020年12月19日
ベッドとトイレ以外の場所に行けるようになった。
3日目以降は微熱が出てだるみが出る。5日目以降は何もなく暇。そのまま7日目で退院のような流れ
お風呂やシャワーに関しては通常の入浴は基本的にNG、ただし3日目以降は看護師補助の上での洗髪、5日目以降は下半身洗浴は可能でした。
退院後
掛かった費用はこちらになります。
みんなの税金で私は生かされました。すまねぇ、もっとちゃんと生きるよ… pic.twitter.com/tmLpuQQK9c
— ぎんさんさんさん (@ImpureSilver11) 2020年12月24日
実際のところは限度額適用認定証*5を提示したためさらに減額されています。
ただそれでもかなりの額支払う事になるため、予め貯金しといたほうがいいです。
患部に関してですが
しばらくすれば、素肌でも目立たないほど綺麗に埋め込まれるらしい。やったぜ。
— ぎんさんさんさん (@ImpureSilver11) 2020年12月20日
医者がおっしゃるには今年か来年には海行っても気づかれないくらいには綺麗になるよう。やったぜ。
今後について
これからは身体障害者としての申請等行い、これとして生きて行きます。
早ければ4月くらいには身体障害者手帳が交付されると思います。
今のペースメーカーはすごく性能がいいので、ほとんど常人と同じように生活ができます。携帯電話も注意は必要ですが普通に使えます。*6
ただ行動に対して制限がないわけではないので、もしも私含めて同じような状況で困ってる人がいるなら助けていただけると嬉しいです。
*1:房室ブロック - 04. 心血管疾患 - MSDマニュアル プロフェッショナル版
*2:
https://ja.wikipedia.org/wiki/%E5%B0%BF%E9%81%93%E3%82%AB%E3%83%86%E3%83%BC%E3%83%86%E3%83%AB
*3:おそらく局部麻酔の影響
*4:実際トイレに行くのは24時間禁止されていたので尿瓶です…
畔倉重四郎をみてた
はい。
最近落語にハマってました。(でもまぁそれまで寿限無や時そばみたいなのしか知らなかったんで知識はたかが知れてます。)
んで、なんだかちょっと横に逸れて、講談を聞いてたんですが、そんな中で見つけたのが六代目神田伯山
この人よくTVにも出て居るらしいが、私は家にTVがないのでそんなことは全く知らずにタワレコの落語コーナーで最初に見つけた。
https://www.amazon.co.jp/dp/B082157M3K/ref=cm_sw_em_r_mt_dp_n6XrFbN0TMR78
この人、まず最初に声が良い。綺麗な低い声で上手く語る。怪談話なんかその声で持って芯まで伝わる恐ろしさ。
その癖(若手で年が若いせいか)マクラの部分が共感できて面白い。
落語ってなんじゃ?講談てなんじゃ?みたいな私みたいなトーシローにもよーくわかるような解説から入ってくれる。これもまた面白いおかしく笑わせてくれる。
そんな感じでみてて見つけたyoutube channel その中で畦倉重四郎の連続物が全部見れるってことだったんで、ずっとみてた。
いやー面白いね。
この畦倉重四郎の物語、全部見ると時代小説一冊読み終えたみたいなすっきりした感じがする。
畦倉重四郎、元は規律ある侍の家の人間なのに、ひょんなことから博打覚え悪友ができ少しずつ悪の道に染まって、しまいには息を吐くように人を殺めていくような極悪人に成り下がっていく。
江戸版デスノートかといやそんなもんじゃない。全て私利私欲のため、自分がやりたいがために全部やった結果こうなったみたいな奴。
もう同情もしようがない奴だろうが、物語の節々に考えさせられる部分がある。
特に畦倉重四郎の最後の言葉
「俺は好きなことをやってきた、旨い酒があれば酒を飲み、博打をしたければ博打をし、人を殺めたけりゃ殺めてきた。」
「ところがお前たちはどうだ?肝っ玉が小せえばかりに惚れてる女に声をかけることもできず、嫌いな奴にはせいぜい陰口、食いたい物も食わず博打もせず…」
「お前たちは俺が地獄に落ちると思ってるだろうが、俺からみりゃてめえらの方がよっぽど地獄にいらァ!」
私にも結構ぐさっときたよ。長年レールに沿って生きてきたからねぇ。
これは講談だけど、もしも実際にその当時でこんなこと言われちゃたまったもんじゃないだろうな。なんて考えるとなんてこれは面白いんだろうって思うよ。
落語と違って笑いはないけど、とてもとても面白いと感じた19(+1)席だったよ。
しかし調べるとこれ今年の一月にやってたのか。とても面白かったし、来年一月あたりにもう一回あったらチケット買ってるだろうなこりゃ。
電子タバコを試してみた。
探せ!キラッといいところ!ぎんさんです。
ぎんさんはじめての喫煙(CBD) pic.twitter.com/FluZqJ5bMB
— ぎんさん@痩せる (@ImpureSilver11) 2020年8月4日
経緯云々的には、個人的に最近テルペン*2感じ
でちょっと話聞いてみて、ニコチンが入ってないということだったので、じゃあ試しててみようかなーという感じ。
テルペンにはリラックス効果や不眠解消とかも言われてるけど、まぁその辺は体感だしーという興味半分疑い半分の思いではあった。
喫煙関係については、私自身非喫煙者で煙草はむしろ苦手な人間*3
なのだけど、だからと言って嫌煙家というわけでもなく、喫煙者と歩み寄りたいタイプの人間。だからこそ、ちょっと試してみたかったのかもしれない。
で、実際どうなの?
まぁリラックス効果とか不眠解消とか言われてるが…
煙もくもくさせるのは楽しいし、そういう意味だとリラックスにはなってると思う。
私はランニングが趣味だけど、それに対する影響は今のところないかな?と思う
でも吸い方が全くわからずにむせるのを何度かやったから、そう言う意味だと影響あるかも。
喫煙者の振る舞いをするようになるのはどうなの?
元々喫煙文化は日本古来からあるもので、ちょっと昔であれば出世するためには煙草吸って喫煙スペースで上司に媚を売れなんて言われてたくらいなので何か不便が起こることはない。
ただ近年の流れないのか喫煙スペースを探すのは難しいなという印象はうける。
渋谷は路上喫煙が普通に行われてる街で、喫煙禁止のプレートが所狭しと並び、その横で煙草を吸ってる人をよく見かける。
非喫煙者としてはこれはすごく嫌だけど、だからと言って喫煙スペースが少ない小さい人が多い今なら閉鎖してるなんて状況でここで吸うなと言ったって、じゃあどこで吸えば良いんだよってなりそうだなという印象を受けた。
これはすぐやめれるやつだから私はいいけど、なかなか辛い世界だねぇ
これを実際に体験してわかったかもしれない。(私はニコチンフリーなのでもっと辛いのだろうな)
webエンジニア界隈は(ジャパニーズトラディッショナルカンパニーをのぞいて)比較的喫煙者少ない印象で、むしろ嫌う人が多いと思う。*4
でもだからといって絶対喫煙するななんて言ったところで無理だし、愛煙家であれば趣味の一つでもあるだろう、それを否定するのは酷ってもんだ。
じゃあ私のいないところで吸えよって言ったって、だったら吸う場所を用意しろって感じになる。渋谷区はこれ考えられてなくて最悪な印象を私はうける。
でも相手側の立場に立って考えなきゃお互いに理解し合えないもんだよ。
家の本を断裁して外出先でも見れるようにした。
私です。
オタクくんあれやってよwwww いつもみたいにmy new gear… ってやつwwww pic.twitter.com/2uxb8eAI11
— ぎんさん@痩せる (@ImpureSilver11) 2020年6月17日
買いました。
これすごい。2分で一冊スキャンできる。
Q. 切るやつは?
A. 数年前からすでに
断裁機の方も文庫本横山三国志をバッサリ行けるくらいにはパワフル。
https://www.amazon.co.jp/dp/B0041VJB9U/ref=cm_sw_r_cp_api_i_yKSoFbGE90248
結果
※あくまでも個人でしか利用してないです
そんでまぁあとはちょろめのリモートデスクトップ使って携帯からみれるようにして
いえーい
使った総額はざっくり計算で
断裁機2万
スキャナ5万
デスクトップPC 18万
モニタ2万
で27万の出費です。サンザイタノシ‐
まぁPCとかなしにしても、メルカリ出品で儲けようとか考えたってこんなんペイできないんでやるべきじゃないよねって感じはする。
私の目的はそんなのより家のお掃除のためなんだけど…
この量の漫画を全部捨てれると家のスペースめっちゃ開く、これによってさらに本が買える。
私は昔の古い本を一気に買って一気に読むのが好きなのでこれはとても嬉しい
読める本が増える。
家のスペースを考えなくていい。
このタイトル何巻まで買ったっけ?がない
これだけあればPC抜き散財分の幸福度は確保できたと思う。goodです。
しかしまぁ数百冊の漫画を一つ一つ切っていくのはすごく面倒臭い。
今の所500いかないくらいの断裁量だが、それでもまだ100冊ほど残ってて、さらに面倒臭い。
よくもまぁこんなに集めたもんだ。。。。
Rubyのバージョンを上げた
どうもぎんさんです。
最近はコロナの影響でいろいろあって辛い思いをしています。
リアルな勉強会にいけないのはモチベーション管理的に困る
それ以外にも仕事もいろいろ変わり、6月から週2で1プロジェクトの面倒みつつOJTとして新人教育みたいなこともやってます。
そのプロジェクトは開発から2年ほど経っててある程度落ち着いてますが、課題としては多々あります。
まず一つにテストが書かれていないということ
カバレッジにしてみると20%くらい。開発時に忙しかったのかな?と思う。
次に各種Ruby,Railsなどの各種Gemsのバージョンが追従し切れてない点。
アサイン時で2.4.6でした。
とりあえずメインの目的は新人教育で、それはspecを書いてもらって、カバレッジの向上で何とかしようかなと思いつつ、私の方で各バージョンあげて行こうかなとなりまして、いろいろと相談しつつ、とりあえずまずrubyのバージョンあげて行こうかなということでやってきました。
一応環境的には
Ruby 2.4.6
Rails 5.1.4
CI/CD circle ci
deploy先 heroku
でgithubでコード管理しつつ、dockerでどかっと(激うまギャグ)デプロイみたいなよくあるCI/CD環境
やったこと
とりあえずリリースノートとか漁りつつ、変更点とコードを舐めて、まぁいけるやろーって感じだったんで、
dockerfile,gemfile,おまけで.ruby-versionを更新して docker-compose build
カバレッジが低いので不安だが、いったんローカルはこれでうまくいった。
んで次にcircle ci の更新。
ci側も同様にimageの更新
- image: circleci/ruby:2.4.6-node
+ image: circleci/ruby:2.6.6-node
ただこれで一度つまづいて、rubyのバージョンをあげるとnodeのバージョンも一緒に上がる。
nodeのバージョンが上がるとwebpackのバージョン管理が代わり、webpackerの方も代わり、連鎖的に落ちていった。
一応これの解決法としてdockerのmulti stage buildを使って個別に管理するというやり方もあるが、私はそれを知らなかった 脳筋なので気合でいろいろアップデートかけて頑張った。
dockerfileやpackage.jsonでnodeのバージョンを更新、とりあえず欲しがってるバージョンを指定して対応した。
後ほど、ci側のimageがしれっとnodeのバージョン上げてきてエラー吐かれたので、マイナーバージョンまで指定すると痛い目をみる。
で、いざpushしてみると`.circleci/config.yml`の方でcacheを使ってたので、それが古くて落ちる。
https://circleci.com/docs/ja/2.0/caching/
ここだとv1でやってるが、これをv2,v3を上げていくことで、ひとまず対応、その間新人くんが上げてくれたPRが尽く落ちた。だらしない先輩ですまない
ここまでやってようやっとciが通った。
で、一通り確認してからマージ(私は管理者だ)
するとheroku側で deploy failed何でかと思いみてたらbuild packにnodeが入ってない。
https://jp.heroku.com/elements/buildpacks
古いやつだとなくても動くのかな?とりま追加して対応。これで全てうまくいった。
この間4日(二週間)新人くんの面倒みつつ、rubocopの調教もしつつ(レビュー軽減対応)だったのでなかなか時間がかかった。
ここまでで得た教訓としては
ciミスるとみんなに迷惑かけて人数多ければそれだけプレッシャーかかる。
エラーログ読みにくい。ローカルでうまくいくのに〜って感じで再現しにくい。
その間いろいろ迷惑かけるが、まずは落ち着け。デプロイに失敗しても落ち着け。
有識者がいたらきけ、それが一番早い
ということ。
以上
所要時間1時間くらい