CLionでCRubyのコードを読む

  • CLionでCRubyのコードをただ開いただけだとうまくコードジャンプが効かない
  • どうやったらええんや…となっていた
  • Makefileを開くと↓のように、「Makefileプロジェクトのロード」が表示されるのでロードするとそれっぽいジャンプができるようになった
  • これでCRubyのコード読みやすくなりそう

RubyがもっとCoWフレンドリーになりそう

  • Implement Process.warmup by byroot · Pull Request #7662 · ruby/ruby
  • Feature #18885: End of boot advisory API for RubyVM - Ruby master - Ruby Issue Tracking System
  • Ruby本体にProcess.warmupというメソッドが追加される
  • アプリケーション側でbootが終わったぞ、というときに使う
  • unicornやpumaなどのpreforkするタイプのアプリケーションはforkするので、そのタイミングでいい感じにCoWフレンドリーになるようにしたい
    • 例えば ko1/nakayoshi_fork を使うとforkの時点でGCを4回実行*1して、すべてのオブジェクトを古い世代にすることでCoWフレンドリーにする
      • オブジェクトが何回GCを生き延びたか、というフラグを持っているのでなにもしないとGCのタイミングでオブジェクトが書き換わり、親プロセスと子プロセスで差分ができてしまう
    • nakayoshi_fork自体は単純に4回GCを実行している
    • けど、Rubyの内部に「いまいるオブジェクトを全部古い世代にする」APIがあればそれ使ったほうが効率的ですよね
    • あと「複数のワーカプロセスをforkで生成する」ケースだとforkにフックをかけるやり方だとforkする回数分同じ処理が実行されるので効率が悪い
    • そこでアプリケーションの起動が終わったタイミングでおもむろにProcess.warmupを実行し、そこでもろもろいい感じにCoWフレンドリーにしてやると良い
    • とりあえず上記PRではGC、GC.compact、いまいるオブジェクトを古い世代にするということをProcess.warmupのタイミングでやっている
    • 他にもメソッドや定数のインラインキャッシュをキャッシュに載せておく、とかもっと最適化の余地がある模様
  • Ruby3.3だとpumaやunicornのメモリ消費量が減る、といいう未来がありそう
  • Rubyの最適化、もうあらかた実施済みなのかな、と思ってたけどまだやる余地あるんですね…

*1:3回GCを生き延びたら古い世代になる認識なんだけどなんで4回なんでしょうね…?

searchkickを使ったテストをするときに気をつけること

  • RSpecでsearchkickを使うときにどう設定するかがREADMEに書かれている
  • ↑を見ると、searchタグを付けたときだけsearchkickが有効になるように読める
  • が、これは間違い
  • searchkickの提供するコールバックのオンオフをするためのフラグはThread.currentで提供されている
  • つまりテストのスレッドで該当のモデルを作ったときにはsearchkickのコールバックは発火しないが、system specでpumaがモデルを作ったときにはsearchkickのコールバックは発火する
    • これ直感的じゃないのでグローバルにコールバックのオンオフを設定できると嬉しい気もするが、system specでサーバ側の挙動をテストに合わせるのもどうなんだろう、となったのでいったんこういう挙動である、という認識のもとやっていくことにした

CIでopensearchコンテナの起動を待つ

  • CIで時々opensearchへのアクセスに失敗してテストが失敗していた
  • (ちゃんと調べたわけではないけど)opensearchの起動が終わるより前にアクセスしにいって失敗している風
    • Faraday::ConnectionFailed: end of file reached
  • opensearchコンテナ、毎回Dockerfileからビルドをしているので時間がかかっていた
  • そこでdocker compose -f docker-compose.ci.yml up -d --buildのようにして、ビルドしてからupするようにした
  • が、これでもまだ失敗する
  • 次の手として vishnubob/wait-for-it: Pure bash script to test and wait on the availability of a TCP host and port を利用して、9200番ポートが空くまで待つようにした
  • が、これでもまだ失敗する
  • opensearchのログを見ると、9200番ポートを開けてからまだ少し何かをしているので、そのタイミングでアクセスしてしまっている模様
  • 結局↓のようなメソッドを定義して、テスト起動時のopensearchへのアクセスでエラーが起きたら時間を空けてリトライするようにしたところ解決した
def retry_on_error(times: 3)  
  try = 0  
  begin  
    try += 1  
    yield  
  rescue Faraday::ConnectionFailed  
    sleep 5  
    retry if try < times  
    raise  
  end  
end

リスコフの置換原則のWikipedia日本語版の説明が一部間違えている気がするがどうなおしたらいいかわからない

リスコフの置換原則 - Wikipedia

(直感的な考えでは、「サブタイプ」のオブジェクトは別の型(「スーパータイプ」)のオブジェクトのすべての振る舞いと、更に別の何かを備えたものである。 ここで必要とされるものは、以下に示す置換の性質のようなものだろう:型 S の各オブジェクト o1 に対し、型 T のオブジェクト o2 が存在し、T に関して定義されたすべてのプログラム P が o1 を o2 で置き換えても動作を変えない場合、S は T のサブタイプである。)

とある。だけど自分の理解だと、「o2(スーパータイプのオブジェクト)をo1(サブタイプのオブジェクト)で置き換えても動作を変えない」じゃないとおかしい。

英語版のWikipeaid Liskov substitution principle - Wikipedia だと自分の理解と同じ。

Liskov's notion of a behavioural subtype defines a notion of substitutability for objects; that is, if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program

日本語版のは英語の文章の翻訳が間違っているのだろう、wikipediaを編集しなきゃ、と思ってwikipeaidのアカウントを作ったはいいけどの↓の箇所をDeepLにいれるとo1をo2で置き換える、と出てくるのでどうしたもんか…となっている

the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T.

jsのArray.prototype.sort()は引数を渡さないと、要素を文字列に変換して比較する

タイトルがすべて。

rubyだと

elements = [100, 99]
elements.sort #=> [99, 100]

のようになるのでjsでも同じ挙動を期待するけど、タイトルの通りの仕様なので次のようになる。

const elements = [100, 99]
elements.sort() #=> [100, 99]

sortの引数に次のように関数を渡すと期待通り動く。

const elements = [100, 99]
elements.sort((a, b) => a - b) #=> [99, 100]

参考: Array.prototype.sort() - JavaScript | MDN

herokuの無料dyno/addon有料化で無料のままでいるDBやredisは削除される(が、サポートの人に頼むと復旧してもらえる)

タイトルがすべて。

For non-Enterprise users, hobby-dev databases will be deleted in accordance with the Heroku Documentation starting November 28, 2022.

Removal of Heroku Free Product Plans FAQ - Heroku Help

ちゃんと書いているのに見逃していました…><

DBの中身がなくなると困るのでサポートに連絡すると、すぐにレスポンスが来て対象アプリケーションやDB名などを聞かれ、返したらシュッと復旧してもらえました。30分くらいで解決してすごい!