うなすけとあれこれ

2022年10月23日

Kaigi on Rails 2022 運営記

Day 2終了時点でのOBS統計情報

ありがとうございました。

Kaigi on Rails 2022に参加していただいた皆様、ありがとうございました。登壇者の皆様、Proposalを出してくださった皆様、協賛してくださった企業の皆様、そして一般参加者の皆様のおかげで、Kaigi on Railsは今年も開催することができました。

Kaigi on Railsが継続的に開催されるためには、もちろん登壇したいとProposalを出してくれる方々、協賛して下さる企業の方々の存在も欠かせませんが、参加者の方々の感想も非常に重要です。楽しかった、学びになったなどのご感想は非常に嬉しいですし、ここはもっとこうだとよかった、などのご意見も、次回開催をより良いものにしていくためにはとても重要なものです。

では今回も雑用1&動画&配信周りを担当した僕からつらつらと振り返った感想を書いていきます。忘れないよう準備期間から書いていることもあり、項目間に繋がりがないですが、そういうものと思って読んでください。

Proposalを出せなかったという個人的な後悔

自分も日々Railsアプリを開発することを生業とするプログラマーの1人なので、もちろんProposalを出したいという気持ちもあり、あたためているネタもありました。また業務委託として関わっている会社においても、Proposalを書く会に参加したり、Slackで迷っている人の背中を押したりしていました。

そんな中、Proposalを書き進めていくうちに、これに本当に価値があるのか?という疑問が浮かんでしまい、とうとう提出できないまま締め切りを迎えてしまいました。Proposalを出してもらう側としては、「価値があるかどうかはこちらが決めるからとにかく出してほしい!」と言う側だっただけに、自分自身がこういう結果になってしまうのは本当にいかがなものかと思います。

あとは実際に開催準備を進めていくなかで、この作業量で登壇するのは無理があったなということもわかりました。ふーがさんはすごい。

スポンサーブースについて

昨年のreBakoの体験が良すぎたので、今年もそのようなものを期待されていた会社さんも多かったのではと思います。しかし裏側の準備が実はとても大変でした。昨年の大倉さんによるレポートでもそのことが伺い知れるかと思います。端的に言ってしまえば、業務として取り組むレベルで作業時間が確保できるのであれば完成度の高い「場」が作れるが、我々はそうではなかった(昨年は無茶をした)ということです。それらの反省を踏まえ、今年はSpatialChatにブースを置くということになりました。スタッフが増えたこともあり、ブース設営に関しては昨年と比較して非常に健全な労力で行われたと感じています(ブースの準備には僕は参加できていませんが、準備期間のSlackの流量が全然違う)。

僕は配信を担当していたということもあり、SpatialChatのほうには顔を出せませんでしたが、他スタッフからの様子の報告であったり、TLを流れていくスポンサー各社様の催しの告知や感想を見ている様子では、reBakoじゃないとやっぱり厳しいかなという気持ちは取り越し苦労だったのかな?と感じました。それぞれのツールにはそれぞれの利点もあり、それぞれのつらみもあるものですが、今年のブースも皆さんに楽しんでいただけたようで何よりです。

登壇動画を集める仕組み

Kaigi on Rails 2022では録画での発表をサポートしています。これまでは、発表内容を録画した動画を提出してもらうのに、Google Formを使っていました。これは手軽な反面、Google Driveの容量を消費してしまいます。現にKaigi on RailsのGoogle Driveの使用率は80%に達しており、何か別の方法を考えたいところでした。もちろん保存容量は購入すれば済む話ではありますが……

そこで、ファイルをアップロードしてもらい、Firebase Storageに保存する2ための簡単なSPAをNext.jsで作成しました3。これはFirebase Authenticationのメールリンク認証によってログインすることでアカウント作成の手間を削減するなど、なるべく簡便に使えるように設計しました。Firebaseって便利だな〜〜というのが実感できました。ただ、アップロードできないケースが1例だけあり、それは申し訳ないと思っています。

自作したファイルアップローダー

同様のものはもちろんActive Storageを使用したRailsアプリでも実現することができます。しかし数ヶ月の使用期間しかないものに対してサーバー(herokuで言うところのDyno)を維持するのもなんだか、ということもあり、Next.jsとFirebase Hostingを選択しました。結果は37GBほどの動画ファイルを受け付け、諸々にかかった費用は2000円弱となりました。

動画編集

今年も昨年同様、提出していただいた登壇動画のレイアウトはめこみや音量などの調整、基調講演の字幕付けを行いました。ここについては特筆することはなく、単純に手を動かすだけ4でした。一番時間を取られる割に特別なことはしていないので、特に書くことがありません。

配信の画作りについて、昨年からのupdate

今年もKaigi on Railsは、ZoomとOBSとYouTubeを組み合わせた配信によって開催しました。ライブでの登壇者にはZoomの部屋に入ってもらい、そこから映像をOBSに流しこんで画作りを行い、YouTubeへ配信する、という構成です。具体的には2020年に書いたKaigi on Rails STAY HOME Edition 配信の裏側に書いたような構成です。

さて、2020年及び2021年は、ZoomのデスクトップアプリとChromeから参加しているZoomの画面を、それぞれ登壇者の共有している画面、登壇者のカメラ映像に割り当て、それぞれの映像をOBSでウィンドウキャプチャしたものを配信レイアウトに流し込んでいました。この方法の欠点は、Zoom側の操作で画面のレイアウトが変化するとレイアウトが崩壊する、画面の切り抜きの領域を細かく調節する必要がある、など、要は登壇者の切り替わりのタイミングの数十秒で細心の注意を払い、なおかつ素早くレイアウト調整を行う必要があるということです。

そこで今回は、NDIを使用するためにZoom Roomsを導入しました。Zoom Roomsでは、NDIによる映像出力が可能です。

Using Network Device Interface (NDI) – Zoom Support

この機能を用いて、まず完全に独立したWindows機5でZooom Roomsをホストします。そのZoom Roomsに入ってもらっている登壇者の共有している画面(発表スライド)、登壇者のカメラ映像のそれぞれを個別にNDIによって出力し、OBS側ではそれらをobs-ndiを用いて受けとることで、安定したレイアウトによる配信を実現できました。この構成は、RubyKaigi Takeoutを参考にしています。

また、配信担当メンバーである僕のメインPCが最近謎のブルースクリーンで再起動をする6という現象がそこそこ発生しており、これが配信中に発生するとしんどいという問題がありました。そこで、OBSからの配信については、Google Cloud上にGPUを追加したインスタンスを起動し、そこから行うようにしました。Google Cloud上のインスタンスへの映像送出については、NDI Bridgeを使用しました。

具体的な配信の構成はこのようになりました。

簡単すぎるアーキテクチャ図

検証を始めるタイミングが少し遅かったせいで、結局僕の家のZoom Roomsが単一障害点となってしまう問題は発生してしまいまいたが、配信中の細かい共有範囲の調整などのトータルの労力は昨年よりは減ったのではないかな、と感じています。

NDIを使用したイベントの配信に関する詳細については、以下の記事が参考になるかと思います。僕も参考にさせていただきました。

Zoom以外の選択肢として、ここ最近、様々な企業が開催する配信イベントでStreamYardが使われているのを観測しています。Kaigi on RailsでもStreamYardは試してみており、とても使いやすいと感じました。しかしStreamYardでは、Kaigi on Railsでやりたい「スポンサー企業のロゴをループでずっと流し続ける」ということができませんでした7

趣味 スティンガートランジション

これはイベント自体の運営には必須でない、趣味の領域でやったことについてです。(イベント運営自体そもそも趣味の領域なのかもしれませんが)

昨年の配信において、場面転換のところでアニメーションがかかっていたのを覚えていらっしゃるでしょうか。あれは配信班のメンバー、yrindaさんが突然持ってきたもので、僕含めスタッフ一同すごい!となったものです。

今年は、あれから僕も高専DJ部で映像を出すためにAfter Effectsを触るなどして少しわかってきたので、トランジション動画を作ってみることにしました。できたのが以下の2つです。

こういうものは、ツールの使い方を習得するのはもちろんですが、そもそもどういう映像を作ろうか、というアイデアを思い付くのも大変でした。一時期は寝る前に布団に入った後、ずっと頭の中で動画の構成を考えていたほどです。

僕がKaigi on Railsにかける想い

熱が冷めないうちに書いておきます。この3年間、決して少なくない時間を割いて、このKaigi on Railsというイベントの運営に関わってきました。僕がなぜそこまでするのか。それは以前「Railsを主戦場としている自分が今後学ぶべき技術について(随筆)」 にて、

学生時代にRubyを触ったのが始まりとなって新卒でRailsを書き始め、そこからキャリアの大部分にRubyとRailsがしっかりと喰らい付いている自分は、Rubyに対してもRailsに対しても結構愛着がある。レガシーとなってほしくはない。採用され続ける選択肢であってほしい。

と書いたように、Railsという技術に対しての愛着や、その周辺に存在するコミュニティへの感謝があるからです。そしてそれだけではなく、Kaigi on Railsが、そのコンセプトとして掲げている、

また、名前の通りRailsを話題の中心に据えるカンファレンスではありますが、広くWebに関すること全般(例えばフロントエンドやプロトコルなど)についてもカバーすることで参加者の知見を深め、また明日からの仕事に役立てていただければと考えています。

にもあるように、「広くWebに関すること全般」を扱うカンファレンスでもあるからです。Railsはもちろん好きですが、それに留まらないWeb技術を広く扱うことのできるカンファレンスというものを続けていきたいのです。例を挙げるならば、2020年のsylph01さんによる、メールに関する各種概念の解説があったセッション「Action Mailbox in Action」や、2021年のohbaryeさんによる、IETF draftとして提出されているIdempotency-Key Headerに関するセッション「Safe Retry with Idempotency-Key Header」や、今年のursmさんによる、ギガバイトクラスの大規模なファイルを扱うためにWeb Workerを駆使したセッション「大量塩基配列登録申請システムができるまで」などです。 RubyKaigiがRubyの話に留まらず、C言語やコンピューターサイエンスの最先端の話題を扱うように、Kaigi on Railsも、Railsというフレームワークに縛られない、Webの最先端の技術であったり、組織論についての話題であったりを受け入れる裾野の広いカンファレンスであっていたい、そんな話題を聞きたい、そのためにオーガナイザーとして今後も関わっていくつもりです。

また、カンファレンスを運営する立場になると、「好きなことができる」というのは、少なくない時間を投入する立場としては嬉しい点でもあります。例を挙げるなら、前述のファイルアップローダーは完成したものをいきなりスタッフ間に公開して「今年はこれを使うぞ!!」ということをしましたし、NDI経由での映像をGCP上のWindows Serverで受けとりそこから配信する、といったチャレンジも僕がやりたい!と言ったからできたものです。

お金をせびる様子

もちろん自分の言い出したことで失敗しないように検証に検証を重ねることは必要ですし、そこで費用が発生するのであれば申請が必要だったりと手間はかかりますが、やはりカンファレンスを内側から好きなように運営できるというのは非常に楽しいことです。

Next

来年もKaigi on Railsは開催される予定です。そしてクロージングでも言及があったように、ようやくリアルに会場を押さえたin-person形式での開催ができそうです(記事公開時点で未確定)。リアル会場での開催となると、今までのようなリモートでの開催とは比にならないほど考えることが増えるでしょう。そういう意味でもスタッフはより増えてほしいですし、お手伝いはしたいが、そんなに時間を割くことはできないという方でも、当日スタッフという形での協力もできるのではないかと思います。

来年も皆さんの、様々なかたちでのご協力をお待ちしております。


  1. cfp-app, sponsor-appの運用、ドメイン設定、議事録など 

  2. アイデア自体は sorah/s3-collect からです。ただしKaigi on Railsは後述するように、主にGoogle Cloudを使用しているので、独自の仕組みを作成することにしました。つくりたかったという気持ちもあります。 

  3. 実は去年から運用に乗せたい気持ちがあったのですが、自分がNext.jsにもFirebaseにもあまり慣れてないので実装に時間がかかり、今年からの運用になってしまいました。それでも最後のほうは募集開始に間に合わせるために勢いで書き上げたので結構汚ないコードになっており、JavaScriptが得意な人に個人的にお金を払ってもいいからレビューしてほしい気持ちがあります。個人的に、ですよ? 

  4. なんだかんだで1日目の夜になっても動画編集をやっていたことについては改善の余地があると思っています。僕の初動が遅かった。 

  5. 家に余っているマシンを初期化してこれに割り当てる予定でしたが、色々あってなぜかPCが1台増えました。どうしてこんなことに? 

  6. イベントビューアーを見ても原因がわからず、対処のしようがない! 

  7. 少なくとも僕が検証した時にはできませんでした。もしできるのであれば教えてください。特定企業が運営するのであればこの要件は不要なので、手軽に配信イベントを開催できるいい時代だと思います。 

2022年10月23日
2022年09月15日

RubyKaigi 2022 参加記

発表について

Do Pure Ruby Dream of Encrypted Binary Protocol?

https://slide.rabbit-shocker.org/authors/unasuke/rubykaigi-2022/ (みんなRabbit使おう!)

昨年の発表から方針を変更し、実装をしていく中で、Rubyだとつらいな~と感じた事について話しました。発表内で、「Ractorをやめた」という表現をしましたが、実際にはRactorに依存しない部分もそれなにり書き直しており、そのためコードの外部から見た振る舞いは、昨年からは微々たる進展しかありませんでした。

発表後、バイナリデータをRubyでそのまま扱うことについて、Samuel氏から IO::Buffer の存在について教えていただきました。

@yu_suke1994 have you looked at IO::Buffer?

— Samuel Williams (@ioquatix) September 9, 2022

これはバイナリを扱うことについては既存のString、Integerよりも適していそうではあるものの、その内容に対して演算したい場合にまだまだ機能が不足しているのではないかと感じました。また、発表で用いたString、Integerでの操作を行うベンチマークを IO::Buffer も対象にして実行してみたところ、3つの中では最も遅いという結果になりました。

https://github.com/unasuke/rubykaigi-2022/commit/1e4470d55217d6c8 (これ、experimentalの警告を消す段階で hello_world_upcase_io_buffer のWarming up、Calculatingの結果が消えていますね……ミスです……)

この結果についても会場でSamuel氏と話したところ、演算する過程で都合上 set_valueget_value をしている部分があるのですが、そこでオブジェクトの正当性のチェック処理が走っている1のが原因ではないか、ということを教えていただきました。

若干の燃え尽きだった

ところで、言ってしまえば前回のRubyKaigiからこれまでの間に、もっと多くのコードが書けたはずでした。しかし、昨年の発表の直後に開催されたKaigi on Rails 2021の運営、さらにその後に控えていたCloudNative Days Tokyo 2021での発表と、立て続けにイベントがあったことで若干燃え尽きてしまいました。しばらくプライベートの時間でQUIC関連のコードを書く気持ちになれない期間が続いていました。そもそも趣味プロジェクトだし、差し迫った締め切りというものも存在しないのも大きな要因でしょう。

締め切りを作っていく

なので今後は、もうちょっと自分を追い込んでいこうかなと思っています2。具体的には、Rubyアソシエーション開発助成金2022に応募しました3。50万円という助成金よりは、成果発表をしなければいけないことによって強制的に手を動かす動機ができること、もしかしたらメンターが付くかもしれないということのほうが、今の僕には魅力に感じました。採択されなかった場合も、別の形で締切を生み出す案がうっすらとあるので、ともかくやっていこうと思います。

こっそりお手伝い

そして、実は今回のRubyKaigi 2022において、会場のインターネット設営の準備をお手伝いしていました4

荷物整理終わった #rubykaigiNOC #rubykaigi pic.twitter.com/j1noLwgUHM

— そらは (@sora_h) September 11, 2022

2018年、2019年とhelperとしてやっていたのが一旦なくなったことで、3年ぶりにケーブルを8の字巻きしたり、ケーブルを這わせに会場を駆け回ったりするのはとても懐かしかったです。 そういう訳で、一般参加者T、登壇者T、スタッフTの三種5を手にすることができました。in-personの嬉しいところは、ちゃんとそれぞれの属性に応じたTシャツを手に入れられることにもあると感じました。

Tシャツ3枚

Ruby Music Mixin

本編終了後には、ピクシブさんの主催するアフターパーティーでDJをさせていただけました。これがめちゃくちゃ楽しかったです。

pixiv Ruby Music Mixin

ちなみにこれを聞いたのがこのタイミングだったのですが、クラブイベントの参加も初めてだったようで、それも楽しかったとおっしゃっていただけたのもとても嬉しかったです。

「初めてでしたけど楽しかったです!」って言ってもらえてめっっちゃ嬉しかったよね #rubykaigi

— うなすけ (@yu_suke1994) September 10, 2022

Next Kaigi

来年のRubyKaigiは松本リベンジということですが、実は7月になぜか松本に行っていました。このときは車で行ったので、来年も車で行こうかな?と思ったりしています。

pic.twitter.com/rt2Q750S1B

— うなすけ (@yu_suke1994) July 1, 2022

でも実はそれより先にKaigi on Railsがあるので、まずはそれに向けてがんばっていきます。


  1. https://github.com/ruby/ruby/blob/v3_1_2/io_buffer.c#L1324 

  2. もちろん壊れない程度に 

  3. 三重で何人かにレビューをしていただきました 

  4. helper登録はしていないのでスタッフ一覧にはいません 載りました (2022-09-17) 

  5. あと一種類ですね、ですけど…… 

2022年09月15日
2022年08月29日

AquaSKKで全角の?や!を入力したい2022

これは自分用備忘録です。

方法

  1. /Library/Input Methods/AquaSKK.app/Contents/Resource/kana-rule.conf~/Library/Application Support/AquaSKK/kana-rule.conf にコピーする
  2. ~/Library/Application Support/AquaSKK/kana-rule.conf の末尾に以下を追記する (EUC-JPである1ことに注意)
!,!,!,!
?,?,?,?

参考

余談 歴史を紐解く

元記事で書かれている ~/Library/AquaSKK/kana-rule-list とは何で、現在はどうなっているのでしょうか。調べてみました。

※ 以下記述はインターネット上の記述から僕が理解した内容で、憶測を含むため間違いが含まれている可能性が大です。当時を知っていて間違いに気付いた方は正しい歴史を教えてください……

まず当初、AquaSKKはText Services Manager2を利用したソフトウェアで、この時点での設定ファイルは ~/Library/AquaSKK に置く3ようになっていました。

後にMac OS X 10.5 (Leopard)で導入されたInputMethodKit4 (以下IMK)を使った実装では、設定ファイルは ~/Library/Application Support/AquaSKK/ に置く5ようになりました。

冒頭で言及した記事が書かれたのは2008年11月12日ですが、AquaSKKのIMK対応が開始されたのが2007年12月15日、IMK対応のコードがSVNリポジトリにコミットされたのが2008年6月26日です。(以下ChangeLogより)

https://ja.osdn.net/projects/aquaskk/scm/svn/blobs/head/aquaskk/trunk/ChangeLog

そして、IMK版対応の中で、2008年8月3日に移行スクリプトが作成され、この内容から ~/Library/AquaSKK/kana-rule-list に書いていた内容は ~/Library/Application Support/AquaSKK/kana-rule.conf に書くようになったことが推測できます。

https://ja.osdn.net/projects/aquaskk/scm/svn/commits/15

この移行スクリプトは2015年に削除されました。

https://github.com/codefirst/aquaskk/commit/da2ad5c264e7d9b91c4c9c4e015cb2db8a2a87c5

https://ja.osdn.net/projects/sourceforge/wiki/potm_0811_AquaSKK

更新履歴


  1. 記載する文字種によって保存する文字コードが EUC-JP 以外になる場合があります。 https://twitter.com/tobetchi/status/1722908547045019681 

  2. https://web.archive.org/web/20040407002805/http://developer.apple.com:80/documentation/Carbon/Conceptual/UnderstandTextInput_TSM/index.html 

  3. https://moch-lite.hatenadiary.org/entry/20090116/p1 の 「TSM版の設定ファイルは以下にあります。」より 

  4. https://developer.apple.com/documentation/inputmethodkit 

  5. https://moch-lite.hatenadiary.org/entry/20090116/p1 の 「Imk版の設定ファイルは以下になります。」より 

2022年08月29日
2022年07月04日

Itamaeの次回リリースに含まれる非互換な挙動について

Itamaeとは

Itamaeというのは、構成管理ツールです。Ruby DSLで構成を定義することができます。Rubyで書けるAnsible1と言ってしまうのがわかりやすいかもしれません。

local_ruby_block が実行ディレクトリの指定を考慮していなかった、という問題

さて、タイトルにもある「非互換な挙動」について説明します。

まず、Itamaeにはresourceというものがあります。これはdirectory resourceであればディレクトリの存在を定義でき、execute resourceであれば与えられたコマンドが実行されることを定義できます。resourceの一覧は以下Wikiにまとまっています。

https://github.com/itamae-kitchen/itamae/wiki/Resources

それらresourceのなかに local_ruby_block というものがあります。これは与えられたRubyのコードブロックを実行するものです。これにより、単にfile resourceでファイルを作成する場合と比較して、より柔軟にファイルの中身を制御するなどの様々なことが可能になります。

そしてresourceは、いくつかの属性を設定することができ、そのひとつに cwd という、そのresourceがどこで実行されるか(current working directory)というものがあります。

この cwd が、 local_ruby_block で機能していない、というのがissueとして報告されました。

cwd does not work in local_ruby_block · Issue #353 · itamae-kitchen/itamae

この問題の原因は、local_ruby_block を実行するItamaeのプロセスのworking directoryが cwd で指定されたものに移動していないからだ、と自分は考えました。

よって、この挙動を修正し、 cwd に移動した状態で local_ruby_block を実行するようにしたItamaeが、v1.14.0としてリリースされる予定です。mitamae側も、itamae側とタイミングを合わせてリリースします。

この挙動は2015年から存在していた

さて、このような挙動になっていたのはいつからでしょうか。これは、調べてみると cwd の属性が全てのresource typeで使用できるようになった、 2015年にリリースされた v1.4.0 からであることがわかりました。

Make cwd a common attribute. (idea by @tacahilo ) by ryotarai · Pull Request #146 · itamae-kitchen/itamae

2015年から今までの間にこの問題が報告されなかったということは、local_ruby_blockcwd つきで使用する人が今まで居なかったのか、それとも現在の挙動で問題無いと考える人しかいなかったのか……どちらなのかはわかりません。しかし、GitHubに存在するコードを検索した結果、 local_ruby_blockcwd の組み合わせが使われているコードは見当たりませんでした。

https://github.com/search?q=language%3Aruby+local_ruby_block&type=code

よってこの挙動の変更による影響はそこまで大きくないと見積もることができます。

問題はあなたの手元にある公開されていないコード

さて、Itamaeは構成管理ツールです。そのことを考えると、公開されていないItamaeのrecipe(構成を定義したコードのことをItamaeではこう呼びます)のほうが、遥かに多いはずです。それなりに長い歴史のある挙動を変更するので、既存のrecipeがこの挙動に依存しているかもしれません。

そのため、お手元のrecipeが以前の挙動に依存していて、かつ変更されると困る場合は、Itamae側に報告してください。この記事がその周知となれば幸いです。


  1. この手のツールはすっかりAnsible一強となってしまった感じがありますが、Itamaeもなかなかいいものなので使ってみてほしいです。これは我々のドキュメントや広報不足などでの努力不足な面もあるとは思いますが。 

2022年07月04日
2022年06月30日

TechFeed Conference 2022でRubyについてのLTをし、公認エキスパートになりました

TechFeed Conference 2022とは何か

株式会社テックフィードが運営しているITエンジニア向け情報サービス “TechFeed” が2022年5月14日に開催した、LTを主コンテンツとしたイベントです。

前代未聞、日本を代表するテックエキスパート50名による大LT大会、全セッション書き起こし! コロナ禍でもエンジニアコミュニティを元気にすべく、TechFeedが総力を上げて実現する「エンジニアの祭典」、ここに開催! https://techfeed.io/events/techfeed-conference-2022

【TechFeed Conference後夜祭】Rubyエキスパート、 @yu_suke1994 さんの講演書き起こし記事をアップしました🎉

Ruby 最新動向https://t.co/mjJ1hYmgAT
動画やスライドへのリンクもバッチリ。一読&シェアよろしくお願いします!

— TechFeed / ハイレベルなエンジニア向けの技術情報プラットフォーム (@techfeedapp) June 28, 2022

このたび僕の発表「Ruby最新動向」の文字起こしが公開されたので、これを書いています。

経緯

TechFeedというサービスは知っていましたが、リリースされたくらいのときにアカウントを作ったきりで特に使用してはいませんでした。

そんなときある方から「TechFeed ConferenceでRubyについてのLTをしてくれないか」という打診がありました。その時点でイベントページを見ると、確かにRubyの枠は2つとも未定でした。

そしてそもそも、Rubyの公認エキスパートがMatzしかいないという状況にも気づきました。

同じく打診を受けた大倉さんとの雑談もとい打ち合わせのなかで、もし公認エキスパートへのお誘いが来たら受けよう、来なくてもさせてもらえないか聞いてみようということになりました。

そしたらTechFeed側の担当の方とのやりとりのなかで、公認エキスパートどうですかという打診があったので、二つ返事で承諾し、Rubyの公認エキスパートになることができました。

意気込み

という訳でRuby公認エキスパートとなりました。今後は、Ruby及びRailsに関する情報をシェアできていければと思っています。あまり積極的に(例えば毎日)活動できてはいませんが、何か面白い、興味深い記事があればシェアしていきます。

あと、自分のほうがRubyの最新情報に詳しいんだが?という自負のある方、是非とも認定エキスパートになってください。荷が買ちすぎてる気がしているので……何らかの手段で僕に声をかけてくれればTechFeedさんに繋ぎます。

2022年06月30日
2022年05月09日

RailsアプリをHerokuから移行するならどれがいいのか比較する

今回つくったweb appのスクリーンショット

Herokuの移行先を考える

今運用しているアプリ達をすぐにHeroku以外に移すということはしないまでも、競合となるプロダクトの調査をしておくことは(特に後発のものについては)機能面で実はこんなに便利なものがあったのか、と気づくことにもなったりするので、やっておいて損はないかと思いました。

比較対象について

比較する対象としては、インターネットで最近見かけるPaaSを選定しました。同様のことができるIaaSのコンポーネントとして、AWS FargateやGoogle Cloud Runがありますが、そのようなIaaSの一部として提供されるものについては今回は比較対象とはしません。

今回の比較対象は以下3つです。

deployするRailsアプリについて

HerokuにdeployするようなRailsアプリに必要な要素とは何かを考えたとき、まずDBが必要なのは当たり前として、Active Job(Sidekiq)やAction Cableを使いたいからRedisも使えてほしいです。もともとHeroku上にファイルはアップロードできないのでオブジェクトストレージは不要としました。

そこで、簡単なチャット(?)アプリを作りました。GitHubアカウントでログインすると100文字以内の文字列を投稿できます。ログイン状態に関わらず、投稿は自動的に更新されます。この仕組みは勉強も兼ねてTurbo Streamsで構築しました。

Render

公式にもHeroku対抗を謳っているだけあり、とてもHerokuに似たサービスです。僕自身、以前の記事で採用したことがあります。

Migrate from Heroku to Render | Render

実際、使い勝手としても、DBを作成すると環境変数 DATABASE_URL が自動的に追加されたりなどの挙動がHerokuと似ていて、新しく流儀を覚えなおす手間が少なくてよかったです。ただ、リソースは全てが一覧に出てきてアプリごとに管理するようなものではなかったです。deployはGitHubにpushすると自動で行われる感じでした。

Renderのダッシュボード

Herokuにおける app.json と似たようなものとして、Blueprintという仕組みがあります。これによって、アプリで使用するリソース、接続情報などの環境変数、さらには接続を許可するIPアドレスなどをコードで管理できる(かつ、更新されたら自動で適用してくれる)のが便利でした。欲を言えばこのrender.yamlの書式が間違っている場合のエラーメッセージの親切さがもうちょっと欲しい1ところでした。

価格ですが、DBにHeroku Postgresのような無料プランがなく、自動的に3ヶ月後から月$7になってしまいます。RailsとRedisは稼動している時間が制限内であれば無料のまま動かせるようなので、HerokuのHobbyプランを使っていると考えれば、まあ……というところでしょうか。

Renderの課金画面

また、今回deployしたアプリでは使いませんでしたが、Diskとminioを組み合わせたオブジェクトストレージを用意できるのは便利そうです。

Railway

サービスとしてはコンテナやbuildpackによってビルドしたサービスをdeployできるPaaSです。

Herokuみたいな"Deploy on Railway"ボタンが作れるのもいいですね。

https://railway.app/button

また、公式及びコミュニティから提供されているStarterがかなり豊富です。

https://railway.app/starters

使い勝手としては、UIはすごくよくできてて操作が快適なのはよかったです。様々な言語、フレームワークに対応しているというか汎用的で、反面Herokuと比較すると自分で設定しないといけないことが多いように感じました。リソースもprojectごとにまとめて管理できるのがHerokuっぽくて良いです。deployはGitHubにpushすると自動で行われる感じでした。regionは現時点で選択できず、US-Westのみです。"We plan to add additional regions.“ と公式FAQにはあります。

Railwayのダッシュボード

公式CLIが、npmやyarn経由でインストールしても実行可能なバイナリが配置されず、GitHub releaseからダウンロードしないといけなかったりちょっと不安ですが……

UIがすごくよくできている、というかよくできすぎていて、DBの中身が見れちゃうのは凄いと思います、がそんなに気軽に見れちゃていいの……?

DBの中身がカジュアルに見れる様子

価格体系がpricingページからはちょっとわかりづらいです。

https://railway.app/pricing

dashboradのbilingを見るとどのくらいのコストになるかが予測で表示されるのが嬉しいです。

Railwayの課金画面

サービスの使い勝手とは関係ないですが、内部の実装はJob descriptionを見るとBorgとMesosの論文から独自に開発しているようでアツいです。

GoogleのBorgとSpanner、FacebookのTwineにインスパイアされて作ったPaaS基盤らしい。KubernetesではなくBorgとMesos論文もとにした独自のオーケストレーションエンジンを開発してるってJDに書いてあった。こりゃ面白いかもしれんね。 / “Railway” https://t.co/oWvwG73xQ8

— inductor (@inductor) May 1, 2022

上記ツイートにぶら下げられているJob descriptionは今は見れません、以下に移動したようです。

https://www.notion.so/Open-Jobs-bdc641c4b72947f2ab1e09bea5362363

Fly.io

mizchiさんのこのブログ記事で聞いたことのあるという方は多いんじゃないでしょうか。僕もそのうちの一人です。

Edge Worker PaaS の fly.io が面白い - mizchi’s blog

現在は公式サイトに "Run your full stack apps (and databases!) all over the world. No ops required.” とあるように、マネージドなPostgreSQLも使えるようになっています。公式ドキュメントにもRailsをdeployする方法についての記載があります。

https://fly.io/docs/getting-started/rails/

感想としては、CLI (flyctl) から操作するのがメインだなという印象です。環境変数の追加も閲覧もWebからではできず、CLIからしか行うことができません。DBとしてPostgreSQLを追加するのはそんなに苦労しませんでしたが、Redisを追加するのに結構手間取りました(接続情報を自分でRails側に渡してあげないといけない)。deployも手元で flyctl deploy をするフローです。

fly.ioのダッシュボード

Herokuと比較した場合、東京リージョン(nrt)があるのが嬉しさでしょうか。

価格はこのようになっています。Herokuと比較してどうなるのかというのは一見ではわかりません。Usageを見ると現時点でのリソース消費量がわかります。

https://fly.io/docs/about/pricing/

fly.ioの課金画面

また、これはサービスの使い勝手とは関係ありませんが、アプリケーションがFirecracker上で動くのはアツいですね。メトリクスにもFirecrackerの状態が出ています。

https://fly.io/docs/reference/architecture/

fly.ioのFirecrackerに関するメトリクス

総評

自分がHerokuに慣れているというのもあるせいか、どうしても、どれもHerokuより多少なりとも複雑だなあという印象です。これらで、僕が移行するなら以下の順で検討すると思います。

  1. Railway
    • サービス毎にリソースをまとめて見られる、UIが快適なのが1番として選んだ理由
  2. Render
  3. Fly.io

また今回、Herokuから移行するなら、という点でサービスを選定しましたが、これは複数人で管理していく2ことも考慮しています。要するに、本気でお金をかけたくないのであれば複数のサービスを組み合わせて運用するのも選択肢としてあると思います。

個人開発のサービスをVPSからVercelとCloud Runに移行した話

今回deployしたアプリは今後数ヶ月ほどはそのまま動かしておいて価格がどうなるかを見たいと思います。その後は落とすかもしれませんし、データもバックアップはしません。

参考URL


  1. 僕の場合、不足しているkeyがない場合は何が不足しているかは教えてくれるものの、valueに明かに不正な値、例としてregionをtypoしている場合は全体がinvalidとなりどこがおかしかったのかがわかりませんでした。 

  2. 具体的にはKaigi on Railsとして運用しているHeroku appがいくつか存在しています。 

2022年05月09日
2022年04月30日

msh3(MsQuic)版のcurlに任意のポート番号を渡せるようにした話

msh3によるcurlでのnghttp2.org:4433へのリクエストが成功する様子

msh3 as the third h3 backend……って何?

プログラマーの皆さんなら一度は使ったことのあるであろうcurlは、HTTP/3でリクエストを送ることができます。しかし、一般的に手に入るcurl、いわゆるOSのパッケージマネージャーから入手できるものでは不可能で、独自にビルドする必要があります。

(もし必要であれば、ここからHTTP/3が使えるcurl入りのdocker imageを入手できます https://github.com/unasuke/curl-http3 )

そのとき、外部のライブラリを組み込む必要があるのですが、これまではcloudflare/quicheか、nghttp3のどちらかを選ぶことができました。

2022年4月11日、その選択肢にMicrosoftの開発しているQUICプロトコル実装であるMsQuicが加わりました。

I had a great time working with Daniel and the rest of the curl community to add msh3 support! I’ll be happy to continue doing so! https://t.co/p9Dz4kGuGL

— Nick Banks (@gamernb) April 10, 2022

このツイートをしたNickさんはMsQuicの主要コントリビューターで、それを使いやすくするための薄いラッパーライブラリであるmsh3の作者であり、引用されているDanielさんはcurlの作者です。

じゃあビルドしてみよう

発表されたタイミングで、公式サイトのHTTP/3対応版のビルド方法についての記載が更新され、"msh3 (msquic) version" が追加されていました。

https://curl.se/docs/http3.html#msh3-msquic-version

それに従い、このようなDockerfileでビルドに成功しました。

FROM ubuntu:22.04 as base-fetch
RUN apt-get update && apt-get install -y git

FROM ubuntu:22.04 as base-build
RUN apt-get update && DEBIAN_FRONTEND="noninteractive" apt-get install -y build-essential pkg-config tzdata cmake

FROM base-fetch as fetch-msh3
WORKDIR /root
RUN git clone --recursive --depth 1 https://github.com/nibanks/msh3

FROM base-build as build-msh3
WORKDIR /root
COPY --from=fetch-msh3 /root/msh3 /root/msh3
WORKDIR /root/msh3/build
RUN cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE=RelWithDebInfo .. \
  && cmake --build . \
  && cmake --install .

FROM base-fetch as fetch-curl
WORKDIR /root
RUN git clone --depth 1 https://github.com/curl/curl

FROM base-build as build-curl
RUN apt-get update && DEBIAN_FRONTEND="noninteractive" apt-get install -y autoconf libtool libssl-dev
COPY --from=build-msh3 /usr/local /usr/local
COPY --from=fetch-curl /root/curl /root/curl
WORKDIR /root/curl
RUN autoreconf -fi
RUN ./configure LDFLAGS="-Wl,-rpath,/usr/local/lib" --with-msh3=/usr/local --with-openssl
RUN make -j`nproc`
RUN make install

FROM ubuntu:22.04 as executor
RUN apt update && apt install -y --no-install-recommends ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=build-curl /etc/ld.so.conf.d/libc.conf /etc/ld.so.conf.d/libcurl.conf
COPY --from=build-curl /usr/local/lib/libcurl.so.4 /usr/local/lib/libcurl.so.4
COPY --from=build-curl /usr/local/lib/libmsh3.so /usr/local/lib/libmsh3.so
COPY --from=build-curl /usr/local/lib/libmsquic.so /usr/local/lib/libmsquic.so
COPY --from=build-curl /usr/local/bin/curl /usr/local/bin/curl
RUN ldconfig
CMD ["bash"]

https://github.com/unasuke/curl-http3/blob/53287f3b1f08b41b11067a27d787272ce566c2a7/msh3/Dockerfile

さて、出来上がったcurlでHTTP/3なサーバーに対してリクエストをしてみると、なんだかうまくいきません。具体的には、www.google.com にはHTTP/3でアクセスできるのですが、nghttp2.org:4433 にはアクセスできません。他にも、msh3のREADMEに記載のある outlook.office.comwww.cloudflare.com にはアクセスできるものの、quic.tech:8443quic.rocks:4433にはアクセスできません。

curlでwww.google.comへのリクエストが成功する様子

curlでnghttp2.org:4433へのリクエストが失敗する様子

きいてみよう

よくわからなかったので、msh3の作者であるNickさんに聞いてみました(というか、Nickさんが僕のツイートに反応してくれました。大感謝です)

I think it might not support h3 on that port.

— Nick Banks (@gamernb) April 25, 2022

うーん、nghttp2.org:4433がHTTP/3をサポートしていないなんてことがあるのでしょうか?quiche版やnghttp3版ではリクエストができるので、調べてみることにしました。

切り分けてみよう

問題がどこにあるのか切り分けることにします。READMEによると、msh3には msh3app という試しにリクエストを送るためのプログラムがあります。これで nghttp2.org:4433へのリクエストができれば、僕がcurlを正しくビルドできていないことになります。

msh3appをビルドするには、以下のようなコマンドを実行します。

$ # msh3/build 以下で実行
$ cmake -G 'Unix Makefiles' -DMSH3_TOOL=on ..
$ cmake --build .

これで build/tool/msh3appが生成されます。試しにwww.google.comnghttp2.org:4433にリクエストを送ってみると、やはりnghttp2.org:4433へのリクエストは失敗しました。

msh3appでwww.google.comへのリクエストが成功する様子

msh3appでnghttp2.org:4433へのリクエストが失敗する様子

では次に、MsQuicではどうでしょうか?MsQuicは、APIを使ったサンプルを用意してくれています。

https://github.com/microsoft/msquic/blob/main/src/tools/sample/sample.c

これをビルドする方法ですが、公式ドキュメントとしてビルドガイドがありました。

https://github.com/microsoft/msquic/blob/main/docs/BUILD.md

ここで、"Building with CMake" にあるような camke --build . ではこのサンプルコードはビルドされませんでした。恐らくCMakeの設定をいじらなければならないようですが、僕にはできそうにありません。なので、ビルドに使っていたUbuntu上にPowerShellをインストールし、 ./scripts/build.ps1 を実行することでビルドすることにしました。

さて、結果ですが、www.google.comnghttp2.org:4433 のどちらもHTTP/3でのリクエストは成功しました!ということは、msh3のどこかに何かの問題がありそうです。

msquicのサンプルコードでwww.google.comへのリクエストが成功し、nghttp2.org:4433へのリクエストが失敗する様子

msh3を探索してみよう

全部で87行と小さいので、msh3appの元となる tool/msh3_app.cpp の処理を追いかけてみることにします。

https://github.com/nibanks/msh3/blob/v0.2.0/tool/msh3_app.cpp

コマンドラインから受け取ったHostを使用してConnectionを作成している、という処理をしていそうな72行目、 MsH3ConnectionOpen の実装はどうなっているでしょうか。

auto Connection = MsH3ConnectionOpen(Api, Host, Unsecure);

MsH3ConnectionOpen の定義は lib/msh3.cpp の65行目からです。

https://github.com/nibanks/msh3/blob/v0.2.0/lib/msh3.cpp#L65-L81

extern "C"
MSH3_CONNECTION*
MSH3_CALL
MsH3ConnectionOpen(
    MSH3_API* Handle,
    const char* ServerName,
    bool Unsecure
    )
{
    auto Reg = (MsQuicRegistration*)Handle;
    auto H3 = new(std::nothrow) MsH3Connection(*Reg, ServerName, 443, Unsecure);
    if (!H3 || QUIC_FAILED(H3->GetInitStatus())) {
        delete H3;
        return nullptr;
    }
    return (MSH3_CONNECTION*)H3;
}

ここで、 MsH3Connectionの引数として443を渡しています。ここが怪しいです。

さらに追いかけていくと、MsH3Connection は uint16_t でPortを受け取り、それを174行目でStartに渡しています。このStartの実体はわかりませんが、ともかくPortとして443を決め打ちで渡しているために、443番ポート以外でHTTP/3をホストしているアドレスにはリクエストできなかったのでしょう。

msh3を直してみよう

では、直してみることにします。

lib/msh3.cppのほうは簡単で、MsH3ConnectionOpenがPortを引数として受け取れるようにし、それをMsH3Connectionに渡すだけです。

問題は/tool/msh3_app.cpp のほうで、コマンドライン引数として受け取ったアドレスからhostとportを分離、portがなければ443として扱う、という処理を行う必要があります。Rubyであれば String#splitやString#rpartitionで簡単にできるのですが、C言語となるとそうはいきません。

まず、以下のように sscanf を用いて分割しようとしましたが、ホストとポートの区切りである :%sの対象になってしまいうまく分割できません。

https://wandbox.org/permlink/2PC5Qqsesd6avigW

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char *str = "nghttp2.org:4433";
    char *givenHost = NULL;
    int Port = 443;

    int len = strlen(str);
    givenHost = (char *)calloc(len + sizeof(char), sizeof(char));
    if (givenHost == NULL) {
        printf("failed to allocate memory!\n");
        return -1;
    }
    int count = sscanf(str, "%s:%d", givenHost, &Port);
    printf("givenHost :%s, port: %d, count: %d\n", givenHost, Port, count);
    return 0;
}

悩んでいたところ、@castaneaさんに以下のStack Overflowを教えていただき、 %[^:] を使うことでhostとportを分割することができました。

scanf - C - sscanf not working - Stack Overflow https://stackoverflow.com/questions/7887003

https://wandbox.org/permlink/q16ugMxasUhgzdWJ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char *str = "nghttp2.org:4433";
    char *givenHost = NULL;
    int Port = 443;

    int len = strlen(str);
    givenHost = (char *)calloc(len + sizeof(char), sizeof(char));
    if (givenHost == NULL) {
        printf("failed to allocate memory!\n");
        return -1;
    }
    int count = sscanf(str, "%[^:]:%d", givenHost, &Port);
    printf("givenHost :%s, port: %d, count: %d\n", givenHost, Port, count);
    return 0;
}

しかし、これでは不十分でした。というのも、MSVCでは安全性の観点からsscanfの使用は推奨されておらず、sscanf_s を使用しないと警告でWindows環境向けのコンパイルが失敗してしまいます。

よって、さらに #ifdef _WIN32 などしてWindows上とそれ以外の環境でsscanf_ssscanfかを使い分けるようにしないといけません。

上記の過程を経て、msh3に対して作成したpull requestがこちらです。

Enable to connect to the host that hosting on non 443 port by unasuke · Pull Request #37 · nibanks/msh3

curl側を直してみよう

先ほどmsh3のAPIを変更したので、curl側にも修正が必要になります。

(実際には上で行ったmsh3への変更と同時並行で進めていました)

curl側でmsh3のAPIを使用しているのはlib/vquic/msh3.cになります。

https://github.com/curl/curl/blob/curl-7_83_0/lib/vquic/msh3.c

ここで、APIに変更を加えた MsH3ConnectionOpen を呼び出しているのは124行目です。

qs->conn = MsH3ConnectionOpen(qs->api, conn->host.name, unsecure);

なので、ここでport番号を渡してやればいいのですが……どこにリクエスト先のport番号があるのでしょうか? これは #define DEBUG_HTTP3 1 などで色々な値を試し、conn->remote_port がそれだということがわかりました。なので、それを渡すだけでよさそうです!

- qs->conn = MsH3ConnectionOpen(qs->api, conn->host.name, unsecure);
+ qs->conn = MsH3ConnectionOpen(qs->api, conn->host.name, (uint16_t)conn->remote_port, unsecure);

Pass remote_port to MsH3ConnectionOpen by unasuke · Pull Request #8762 · curl/curl

という訳で、これもmergeされたことにより、msh3(MsQuic)版のcurlに任意のポート番号を渡してHTTP/3による通信ができるようになりました。

おわりに

C言語って難しいですね……

2022年04月30日
2022年03月30日

omniauth-twitter2 gem - How to authenticate twitter account by OAuth 2.0 on your Rails app?

twitter oauth2.0 setting

日本語版はこちら

tl;dr

I made this gem.

https://github.com/unasuke/omniauth-twitter2

This gem is one of the OmniAuth strategies for Twitter, using OAuth 2.0 for the authentication protocol.

We have omniauth-twitter gem. Why this gem?

Yes, the omniauth-twitter gem is a well-maintained, widely-used gem.

https://github.com/arunagw/omniauth-twitter

But, omniauth-twitter uses OAuth 1.0a.

Twitter OAuth 2.0 GA from 2021-12-15

When 2021-12-15, Twitter announced OAuth 2.0 General Availability.

We can hardly believe it either, but It’s finally here! ⌛

Today, OAuth 2.0 and new fine-grained permission scopes are available to all developers. Thank you to our developer community who worked alongside us in the beta, and helped us get this right. https://t.co/jVJeDuF7rm

— Twitter Dev (@TwitterDev) December 14, 2021

And we can use “new fine-grained permission scopes” at the release.

We could choose those three kinds of scopes in the older permission scope. That’s too rough.

But now, We can choose enough permissions from the list on OAuth 2.0 (through Twitter API V2)

https://developer.twitter.com/en/docs/authentication/oauth-2-0/authorization-code

tweet.read, tweet.write, tweet.moderate.write, users.read, follows.read, follows.write, offline.access, space.read, mute.read, mute.write, like.read, like.write, list.read, list.write, block.read, block.write

OK, how to use twitter with OAuth 2.0 with my rails app?

I created a gem, “omniauth-twitter2”.

https://github.com/unasuke/omniauth-twitter2

This is one of the omniauth strategies, so it’s easy to integrate your rails app if you use omniauth (or devise?)

(“2” means OAuth 2.0, not means successor of “omniauth-twitter” gem. because the gem still working everywhare!)

And I have created a sample application that uses omniauth and omniauth-twitter2.

This app only signs in with twitter, but it’s enough to show how to implement “sign in with Twitter”.

Attention

If you want to use OAuth 2.0 API in your twitter app, you should move your app to under “Project”. You can’t use OAuth 2.0 in your app if the app is still a “Standalone app”.

twitter developer portal

…And I’m not a specialist in the authentication. Please give me a pull request or issue if you found a bug.

2022年03月30日
2022年02月28日

TwitterにOAuth 2.0でログインできるomniauth-twitter2 gemを作りました

twitter oauth2.0 setting

tl;dr

unasuke/omniauth-twitter2: omniauth strategy for authenticating with twitter oauth2

↑ これをつくりました

Twitter認証、要求される権限がデカい問題

Twitter認証でログインできるWebアプリというものは色々あり、便利なので日々使っているという方は多いことでしょう。

しかしTwitter loginで要求される権限の粒度はこれまで以下の3つしかありませんでした。

これはあまりにも大雑把で、「要求される権限が広すぎる!」「いやいやこういう事情で……」というやりとりを見掛けたことは何度もあります。

このように解説する記事も多く存在します。

TwitterがOAuth 2.0をサポートした

さて2021年12月15日、TwitterはOAuth 2.0のサポートをGeneral Availabilityとしました。

Announcing OAuth 2.0 General Availability - Announcements - Twitter Developers

本日、OAuth 2.0と新しい詳細な権限機能を全ての開発者に提供開始しました。私たちとともにベータ版の開発をサポートしていただいたコミュニティの皆さん、ありがとうございました。

詳細は以下の英語フォーラムをご覧ください👇 https://t.co/pNxzNqqfig

— Twitter Dev Japan (@TwitterDevJP) December 15, 2021

このタイミングで、

all developers can implement OAuth 2.0 and new fine-grained permission scopes in the Twitter developer porta

とあるように、"fine-grained" な、つまり適切な粒度での権限要求が可能となりました。

具体的にどのようなscopeで要求できるかというのは、記事作成時点で以下のようになっています。

https://developer.twitter.com/en/docs/authentication/oauth-2-0/authorization-code

tweet.read, tweet.write, tweet.moderate.write, users.read, follows.read, follows.write, offline.access, space.read, mute.read, mute.write, like.read, like.write, list.read, list.write, block.read, block.write

これまでと比較してとても細かく指定できることがわかります。

omniauth-twitter2 gem

さて、こうなるとOAuth 2.0でTwitter loginしたくなってきますね。Ruby及びRailsにおいてWebアプリでのSocial Accountによるログインといえば、OmniAuthがそのデファクトスタンダートと言えます。

https://github.com/omniauth/omniauth

ということで、OmniAuthのいちstrategyとして、omniauth-twitter2というgemを作りました。

unasuke/omniauth-twitter2: omniauth strategy for authenticating with twitter oauth2

使い方はよくあるOmniAuthのstrategyの導入と同様です。具体的にどのような挙動になるかはサンプルアプリを用意しました。

Client IDとClient Secret、その他OAuth 2.0の有効化については developer.twitter.comで行う必要があります。

twitter oauth2.0 setting

気をつけないといけないのは、OAuth 2.0 を有効にするためにはProjectを作成し、その下にAppを作成する必要があるという点です。Standalone AppsでもOauth 2.0 は有効にできそうなUIになっていますが、実際にはProjectに属していないといけないようです。

twitter developer portal

https://developer.twitter.com/en/docs/twitter-api/getting-started/about-twitter-api

そして、現時点で無料プランの最高となれるElevated1においては、Projectは1つ、その下に3つのAppを所属させることができますが、それ以上は Elevated+ にアップグレードしないとダメで、おそらく有料です。そしてまだcoming soonとなっています。

僕は認証、認可、OAuth 2.0の専門家ではないので、実装には誤りが含まれる可能性が高いです。皆さんのPull Requestをお待ちしています。

余談 Render.com について

今回サンプルアプリをホスティングする先として、render.comを選択しました。

公式WebサイトにHerokuとの比較を記載しているあたり、Herokuの立場を狙っているような感じがあります。今回renderを採用した最大の理由として、HTTP/2をサポートしていることです。

Heroku serves all content over HTTP/1.1. However, major browsers have supported HTTP/2 since 2015. Render serves all requests over HTTP/2 (and HTTP/3 where available), falling back to HTTP/1.1 for older clients. This minimizes simultaneous connections to your Render apps and reduces page load times for all your users. https://render.com/render-vs-heroku-comparison

ただ一点、Free planにおいて、PostgreSQLが使用できるのですが、作成後90日経過すると停止するので再度作成しないといけない(ように見える、実際dashboard上でもpaid planへのupgradeを要求される)というのがネックです。

Render’s free database plan allows you to run a PostgreSQL database that automatically expires 90 days after creation. https://render.com/docs/free

今回のサンプルアプリでは、DatabaseだけはHeroku Postgresを使うことにしました。


  1. Academic Research planもありますが、ProjectとAppの制限はEssentialと同様になっています。 

2022年02月28日
2022年01月09日

ruby-jpでwebsocket-client-simpleというgemの開発を引き取った経緯

ただdeployしたかっただけなのに

僕のお手伝いしている、とある会社ではdeployをSlack botから行っていましたが、ある日そのbotが動かなくなっていました。Twitterでも少し話題になったので覚えていらっしゃる方もいると思います。

Rubotyで動いてた煉獄さんがSlack RTM周りの変更で動かなくなってしまったためGitHub Actionsに載せ替えました。通知の責務に関しては、炭治郎が受け継ぎました pic.twitter.com/nM4hvc5oTL

— 黒曜@Leaner Technologies (@kokuyouwind) December 7, 2021

このとき何が起こっていたのか。前述したとある会社では、Slack bot frameworkとしてRubotyを、Slackとの通信にはruboty-slack_rtm gemを使っていました。

ではまず、こちらのSlack APIのChangelogをご覧ください。

If you still use rtm.connect or rtm.start to connect to Slack, you’ll notice that all WebSocket URLs now begin with wss://wss-primary.slack.com.

https://api.slack.com/changelog#changelogdate2021-11

以前はどのようなURLだったのかというのはわかりませんが、これに関連して、ruboty-slack_rtm gem側で以下のissueに記載のあるような問題が発生するようになりました。

OpenSSL::SSL::SSLError: SSLwrite at Heroku · Issue #46 · rosylilly/ruboty-slackrtm

どうやらSlackがWebSocketに使用するURLにて、TLS証明書にSNIが導入されたようです。そして、ruboty-slack_rtm gemがWebSocketでの通信のために使用しているwebsocket-client-simple gemがSNIを考慮できていないため、WebSocketでの通信が行えなくなってしまっている、ということのようでした。

一旦はslack-ruby-client gemを使うことで凌ぐことができましたが、websocket-client-simple gemにSNI対応が入ってくれると助かります。

さて、そのようなPull requrstは複数作成されていましたが、ownerであるところのshokaiさんの反応はありませんでした。

そこで思い切って聞いてみました。

@shokai 突然すみません、このpatchが取り込まれてほしいのですが、これをmergeするのに何か障害になっていることはあるのでしょうか?https://t.co/LPxcKEHizh

— うなすけ (@yu_suke1994) December 24, 2021

すると、移管について前向きに検討していただけるとのことだったので、同様にRubotyを使っているruby-jp slackのGitHub organization下で管理するということになりました。

他の人が管理してくれるなら全部移管したいです

— Sho Hashimoto (@shokai) December 24, 2021

それについて、ruby-jpで行った会話の流れ1が以下になります。

やったこと

さて、そんなこんなでruby-jp以下に shokai/websocket-client-simple をforkし、gemをpublishする権限をいただいてから行ったことを以下にまとめました。

https://github.com/ruby-jp/websocket-client-simple

READMEの更新

まずは既存のrepositoryのREADMEを更新します。websocket-client-simple gemは歴史のあるrepositoryですから、 shokai/websocket-client-simple であるという共通認識があることでしょう。

そのため、「開発は ruby-jp/websocket-client-simple に移動したよ」ということをREADMEの上部、すぐ目に入る部分に記載するべきでしょう。(これは元々の shokai/websocket-client-simple に出す必要があります)

Update README (repo moved notice) by unasuke · Pull Request #42 · shokai/websocket-client-simple

merge後、既存のissue及びpull requestに対して「まだこの変更が必用なら ruby-jp/websocket-client-simple 側にお願いします」とコメントしました。

CIをGitHub Actionsに & 定期的に実行されるように

次に、CIが長期間実行されていないので、テストが通るかどうかを確認する必要があります。テストはGitHub Actionsで実行することにしました。

GitHub Actions by unasuke · Pull Request #1 · ruby-jp/websocket-client-simple

そして、CIが定期的に実行されるように設定しておきます。これにより、依存している別のgemの破壊的変更にすばやく気づくことができるようになります。

コードは変更せずにリリース

CIは整備しましたが、ここまでロジックは変更していません。最低限必要とするRubyのバージョンも変更していません。この状態で「開発は ruby-jp/websocket-client-simple に移動したよ」というメッセージをgemのinstall時に出すような変更を行い patch releaseを行いました。

Update gem metadata by unasuke · Pull Request #2 · ruby-jp/websocket-client-simple

このメッセージはそろそろ消そうかなと思います。homepage_urlsource_code_url で事足りるためです。

Ruby 2.6.5以上を必須としてリリース

このリリースまでが、いわゆるmigration pathとしてのリリースです。リリース時点でメンテナンスされている、EOLになっていないRuby versionを下限とする制限を行ったリリースをしました。

Set minimum requied ruby version to 2.6.9 by unasuke · Pull Request #3 · ruby-jp/websocket-client-simple

SNI対応を行ってリリース

さて本題のSNI対応です。これは元々のrepositoryにpull requestを出している方が2人いらっしゃいました。その変更を見て僕がコードを編集して出すということもできますが、それはお二人にリスペクトがないと感じたため、その二人からpull requestが来るのを待つことにしました。

そしたらそのうちの一人であるfuyutonさんからpull reqを頂いたので、これを無事mergeしてリリースを行いました。やった!!!

Added to use SNI by fuyuton · Pull Request #6 · ruby-jp/websocket-client-simple

このあたりの変更を大晦日から年明けにかけてやっていました。いい年越しでした。

ruboty-slack_rtm側でwebsocket-client-simpleの最新版を使うように変更してもらう

ここでめでたしめでたし……とはいかず、ruboty-slack_rtm gem側が要求しているwebsocket-client-simpleが低いままなので問題は解決していません。

そのため、ruboty-slack_rtm側でSNI対応を行ったバージョンである0.5.0以上に依存するように変更を行ない、これをmergeしていただきました。

Use websocket-client-simple gem v0.5.0 or greater by unasuke · Pull Request #47 · rosylilly/ruboty-slack_rtm

これにて職場でのSlack botもmonkey patchなしで動くようになり、chatopsが無事にできるようになりました。めでたしめでたし。

余談 gemのowner権限について

さてこの度、Twitterでコミュニケーションしてgemの権限を頂くということを行いました。ところで、このような「owner権限のリクエスト」という機能がrubygems.orgに入っています。この機能では、作者がownerを引き受けてくれる人の募集、もしくはあるgemに対してのowner権限のリクエスト(こっちはgemのdownload数などに制限がある)を行うことができます。

ただ、まだリリースアナウンスはされていないようです。

追記 2022-01-10

shokaiさんの視点からの記事が出ているのでリンクを貼ります。

websocket-client-simpleをruby-jpに移管した - 橋本商会

追記 2022-05-01

Rubygems Adopationsについて公式の発表があったので更新しました。


  1. 発言の掲載については許可を得ています 

2022年01月09日
新しい投稿
古い投稿