- Ruby / Rails関連
週刊Railsウォッチ: YJITがRuby 3.1向けにマージ、ripperのドキュメント化、crontabの罠ほか(20211026後編)
こんにちは、hachi8833です。
🔗Ruby
🔗 YJITリーダーによるYJIT紹介記事
つっつきボイス:「以下↓はYJITリーダーであるMaxime ChevalierさんによるYJIT紹介記事ですが、翻訳リクエストを受けてひとまず一次翻訳終えました: リクエストありがとうございます🙏」「お〜翻訳楽しみ」「Ruby 3.1でYJITがマージする流れになっていますね: YJITはデフォルトでオフのはずなので、使わないときは意識せずに済むはず」「お〜YJIT楽しみ」
TechRachoさんで翻訳して欲しい #RubyKaigi_SmartHR https://t.co/DVx1tnuNeg
— シロ (@shiroemons) October 16, 2021
「続編記事としてNoah GibbsさんによるYJITお試し方法の紹介記事も出ていました↓」
We've been working on, YJIT, a new JIT implementation on top of CRuby that's already showing very promising speed improvements in our benchmarks.
Want to try it for yourself? @Codefolio has a new rundown on our blog 👇https://t.co/y2UgX6uhNg
— Shopify Engineering (@ShopifyEng) October 20, 2021
以下はYJITのベンチマークサイトです。
🔗 YJITがマージされた
「ちなみについさっき(注: つっつき時点の10/21夜)YJITがマージされたというツイート↓を見かけたんですが、YJITがでかくてコミット数が多かったせいかdev環境のSlackボットや通知周りがエラーになって、いったんcloseされていました」「ありゃ残念」「ドンマイ」「分解するのは大変そう」
YJIT has been merged. https://t.co/EeSR7atzMr #ruby
— Hiroshi SHIBATA (@hsbt) October 20, 2021
つっつきの後、無事YJITがmasterにマージされました🎉
参考: ruby-trunk-changes 2021-10-21 - ruby trunk changes
その後、OpenBSDでYJITを無効にするコミットや、JITでMJITを有効にするオプションを追加するコミットも追加されていました(YJITとMJITは同時には利用できないそうです)。
- Force disable yjit on OpenBSD · ruby/ruby@119626d
- Fix TestRubyOptions#test_enable for -DMJIT_FORCE_ENABLE · ruby/ruby@6469038
🔗 safe_regexp: 正規表現をタイムアウト
# 同リポジトリより
# normal
/a/.match?('a') # -> true in 0.0001ms
SafeRegexp.execute(/a/, :match?, 'a') # -> true in 0.13568ms
# bomb
require "safe_regexp"
regex = /aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?aa?/
value = "a" * 46
regex.match? value # false in ~60s
SafeRegexp.execute(regex, :match?, value) # -> SafeRegexp::RegexpTimeout
# methods without arguments
regex = "^(The '(?<first_group>.*)' parameter of the (?<second_group>.*))$"
SafeRegexp.execute(regex, :names) # -> ["first_group", "second_group"]
つっつきボイス:「以下のregular-expressions.infoというサイトで知りました↓: サイトの人がこのgemを試したかどうかまではわかりませんでしたが」「今日のBPS Webチーム内発表で触れていたgemですね」「SafeRegexp
を使うことで、正規表現がデフォルトで1秒以上かかるとタイムアウトしてエラーをraiseするそうです」
参考: Preventing Regular Expression Denial of Service (ReDoS)
「今Ruby本家でも正規表現にタイムアウトを入れようかという話が出ていましたね」「はい、RubyKaigi Takeout 2021のMartin先生の発表↓で触れていた#17837などですね」「これは?」「最近流行りのcatastrophic backtracking攻撃に対してRubyが対抗策を議論しているissueのひとつです」
参考: Regular Expressions: Amazing and Dangerous by Martin J. Dürst - RubyKaigi Takeout 2021
「READMEではThread
やTimeout
を使わずに作ったとありました」「同じくREADMEによると、正規表現用に別プロセスを立ち上げて、タイムアウトしたらkill -9
で止めるということをやってるらしい: 正規表現エンジンの中にタイムアウトを仕込むのではなく、エンジンの外側でやるという戦略かな」「シェルで強制終了するような感じなんですね」
「そういえば手元でsafe_regexpをちょっと試してみたところ、ヤバいパターンを食べさせたらコンソールが固まって、Ctrl-Cでも戻らなくなっちゃいました😢」「kill -9
で止めるしかないでしょうね: 別プロセスにしないとRubyのメインプロセスがCPUタイムを食い尽くしてしまうので、OSのことも考えて正規表現用のプロセスを分けたんでしょうね」「なるほど」
「重たい別プロセスをRubyで立ち上げるのは泥臭いですが、ひとつの方法でしょうね」「テスト環境で使うとか、特定の正規表現を手元で検証するときにはよさそう👍」
🔗 ripperのドキュメント化が進行中
Dumped even more information into https://t.co/yYmavYUY4M. Added a section for the `lineno` and `column` methods which can be very confusing. And got up through the Bs for parser/scanner events. We'll get there eventually!
— Kevin Newton (@kddnewton) October 15, 2021
つっつきボイス:「RubyのパーサーライブラリであるRipperは以前からドキュメントがないと言われていましたが、この方が頑張ってコードを読んでドキュメントを書き進めているそうです」「お〜すごい!」「READMEの内部リンクがまだ切れてるのでファイルを直接開いてください」
参考: class Ripper (Ruby 3.0.0 リファレンスマニュアル)
「RuboCopの作者の@bbatsovさんも、ドキュメントがないなどもろもろの理由でRipperを使うのをやめたそうです↓」「ドキュメントがなくても使う人はいるでしょうけど、やっぱりドキュメント大事」「動きがだいたいわかってても、ドキュメントがないと不安になりますよね」「RuboCopも使えるものならRipper使いたかったでしょうね」「ドキュメント化大変だろうけど頑張って欲しいです🙏」
🔗 Rubyのワンライナーcookbook
つっつきボイス:「Rubyのワンライナー向けオプションはたくさんある分、Perlの-pie
オプションに比べると長めになってしまう傾向がありますけど、Rubyの-ne
オプションあたりなら使いますね」
# 同記事より
$ # sample stdin data
$ printf 'gate\napple\nwhat\nkite\n'
gate
apple
what
kite
$ # print all lines containing 'at'
$ # same as: grep 'at' and sed -n '/at/p' and awk '/at/'
$ printf 'gate\napple\nwhat\nkite\n' | ruby -ne 'print if /at/'
gate
what
$ # print all lines NOT containing 'e'
$ # same as: grep -v 'e' and sed -n '/e/!p' and awk '!/e/'
$ printf 'gate\napple\nwhat\nkite\n' | ruby -ne 'print if !/e/'
what
参考: Perlのワンライナーでテキストの一括置換 - console.lealog();
「Rubyは標準機能が強力だし普段からRuby書いてるので、ワンライナーにもいいですよね」「いいっす」「ただ自分がRubyであまりワンライナー書かないのは、カスタマイズできない作業環境でRubyが使えるとは限らないからというのもあるんですよ」「その意味ではPerl強いですよね」「Perlはたいていの環境で最初から使えますね」
「Pythonも入っているとは限らない」「あってもPython 2系か3系かという罠があったりしますし」「さすがに新しい環境でPython 2は減ったと思いますけど、古い環境だと油断できない」
参考: Python 2.7.x と 3.x の決定的な違いを例とともに | POSTD
「macOSだとRubyが入っているけど、バージョンが古いんですよね」「1.8とかだったらどうしよう」「1.8はもう別物😆」
後でBig Sur備え付けのRubyバージョンを調べてみました。Ruby 2.6は2022年3月にEOL(end-of-line)を迎えますが、果たしてmacOSはちゃんとバージョン上げてくれるでしょうか?
参考: Ruby Maintenance Branches
$ /usr/bin/ruby -v
ruby 2.6.3p62 (2019-04-16 revision 67580) [universal.x86_64-darwin20]
🔗CSS/HTML/フロントエンド/テスト/デザイン
🔗 セキュリティヘッダークイックリファレンス(StatusCode Weeklyより)
つっつきボイス:「HTTPのヘッダーのうち、セキュリティ関連のヘッダーのクイックリファレンスだそうです」「▼をクリックすると詳細が表示されるのね」
「X-Content-Type-Options
はたしかに使う」「X-Frame-Options
もそういえばあった」
# 同サイトより
X-Content-Type-Options: nosniff
# 同サイトより
X-Frame-Options: DENY
「クロスオリジン関連のヘッダーにCross-Origin-Opener-Policy
(COOP)やCross-Origin-Embedder-Policy
(COEP)というのもあるんだ、へ〜細かい」「たしかに細かい」
# 同サイトより
Cross-Origin-Opener-Policy: same-origin-allow-popups
# 同サイトより
Cross-Origin-Embedder-Policy: require-corp
「CORSはよく聞くヤツですね」「知ってるものが出てきた」「ちなみにCORSのヘッダーは、ない状態が最もセキュア」
# 同サイトより
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true
参考: Rails アプリケーションのセキュリティ対策(CORS/CSP/HSTS)
「こうしたセキュリティ関連ヘッダーは適切に設定すべきですね: 特にSPAは1つのページ内であらゆるデータを読み書きするようになるので、一箇所でも不備があると他の部分にも影響しがち」「たしかに」「セキュリティヘッダーのリファレンスとして便利そうなサイト👍」「ヘッダーが多すぎないのが嬉しいです😂」
参考: シングルページアプリケーション - Wikipedia -- SPA
🔗 Priority Hintsによるリソース読み込み最適化
つっつきボイス:「Priority HintsはWebページ内の要素の読み込みで優先度を指定できる新しめの仕様ですね」「以下の記事は2018年の時点でPriority Hintsをチェックしていました↓」
「お〜、Blink(Chromeなどで使われているレンダリングエンジン)ではこれらに優先順位を設定できるのね↓」「『Priority Hintsはヒントであってディレクティブ(指示)ではない』、なるほど」
参考: Blink (レンダリングエンジン) - Wikipedia
「具体的には以下のようにタグでimportance="low"
のように指定する↓と、ブラウザ側で優先順位を割り当てる」「"low"
と"high"
と"auto"
の3つか」「画像のimg
にも指定できるんですね」「その場合CSSで画像サイズをきちんと指定しておく方がいいかも」
<!-- 同記事より -->
<!-- include trial token in the <head> -->
<meta http-equiv="origin-trial" content="{Replace with origin trial token}">
<!-- Lower the priority of script file -->
<script src="script.js" importance="low"></script>
<!-- Alter the priority of images -->
<img src="Background.jpg" width="400" importance="low">
<img src="Sunset.jpg" width="400" importance="high">
<!-- Note that importance="auto" is the default based on the spec if not specified -->
<img src="Flower.jpg">
「優先順位の仕様↓は定められているけど、細部の解釈はブラウザ依存になる可能性があるかもしれませんね」「あ〜たしかに」
「importance
を全部High
にしたりするのはダメなのかな?」「無意味だと思いますよ😆 : 上の仕様の上下矢印などを見た感じでは、仮に全部High
にしたとしても優先順位は同じにならないでしょうね」「あ、たとえばHigh
に下向き矢印がある項目は、それより低くなる可能性があるということなんですね」
「Priority Hints指定なし(左)とあり(右)では以下のように変わるんですね↓」「わかりやすい〜」
「優先順位をここまで追い込んで使うことはすぐにはないかもしれないけど、importance="high"
にasync
を指定する↓のは効果高そうな感じなので、これなら書いてもいいかなと思いました」
<!-- 同記事より -->
<script src="async_but_important.js" async importance="high"></script>
🔗言語/ツール/OS/CPU
🔗 Crontab.guru
One great tool for getting started with cron jobs: https://t.co/4tZSq3FB9a, an excellent tool by @cronitorio that lets you test different schedules and see what they do. pic.twitter.com/u6fOBs8p8N
— bit.io (@bitdotioinc) September 16, 2021
つっつきボイス:「なるほど、crontabのスケジューリングの設定を支援するサイトですか」「これ面白いですね」「たしかGitHubのドキュメントでこのCrontab.guruが参考としてリンクされてたのを見たことがありますよ」
後で見つけました。
crontab guru を使うと、クーロン構文の生成および実行時間の確認に役立ちます。 また、クーロン構文の生成を支援するため、crontab guru のサンプルリストもあります。
ワークフローをトリガーするイベント - GitHub Docsよりより
🔗 crontabの罠
「ところでcrontab形式って、実は標準というものがないんですよ」「え?」「そうなんです😢」
「たとえば、Linuxだと曜日は日曜始まりで0-6
が割り当てられていて、さらに7
も利用可能なので、0
と7
が日曜日になる: これなら7
で割った余りで曜日を出すみたいな処理がやりやすい」「なるほど!」
「でもAmazon EventBridge↓(旧Amazon CloudWatch Events)のCrontab形式はかなり特殊で、曜日が日曜始まりの1-7
になってる」「え〜それヤバいじゃないですか!」「きっとハマる自信ある」「誰もが一度はハマります」
参考: ルールのスケジュール式 - Amazon CloudWatch Events
「さらに厄介なのは、EventBridgeではcrontabで指定できる時刻がUTCのみという点」「え〜!JSTとかで書けないんですか?」「ローカルタイムが指定できないので、時刻を指定するたびに変換してあげないといけません」「ややこしい...」
「ちなみにLinuxのcrontabだとTZ=タイムゾーン名
でローカルタイムを指定できます↓(指定し忘れると悲惨ですが)」「そういえばそうですね」「Linuxのcrontabに慣れているほどAWSでハマりがち」
参考: cron - How do you set the timezone for crontab? - Ask Ubuntu
「ところが面白いことに、AWSのマネージメントコンソール経由だとEventBridgeでローカルタイムを指定できるんですよ(↓証拠写真)」「へ〜!」「これについてさんざん調べたんですが、APIレベルではできない😢」「残念...」
「そういったわけで、crontab周りはクラウドの設定をレビューするときの要チェックポイントです」
後編は以上です。
バックナンバー(2021年度第4四半期)
週刊Railsウォッチ: insert_allやupsert_allのタイムスタンプ自動更新、app/contextsにロジックを置くほか(20211025前編)
- 20211019後編 ruby/debugをChromeでリモートデバッグ、Rubyアプリの最適化ほか
- 20211018前編 Railsリポジトリで進行中のPropshaft、inverse_ofを自動推論ほか
- 20211012後編 Ruby 3.1にYJITマージのプロポーザル、Rubyのmagic historyメソッド、JSのPartytownほか
- 20211011前編 ServerTimingミドルウェア追加、paramsで数値キーを許可、Railsで多要素認証ほか
- 20211006後編 ruby/debug 1.2.0リリース、Railsにはthorが入っている、tendejitほか
- 20211004前編 Rails 7でbyebugがruby/debugに変更、GitHub Codespacesをサポートほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。
週刊Railsウォッチについて
TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)