Hard work by INTERNET

ベンチャーで働くひとりぼっちWEB開発者が頑張るブログ

rubyweekly#482 Ruby2.7

rubyweekly.com 今回は先月リリースされたRuby 2.7.0特集です。

Ruby 2.7.0 Released

英語で書かれた公式サイトのリンク。

Digging Into Ruby 2.7's Changes

2.7の変更を深堀りするような記事名。公式サイトに書いていないような filter_map とかにも言及している。

Introducing Automated Postgres EXPLAIN Visualization & Insights

PostgreSQLのツール、pganalyzeの新機能の紹介みたい。 EXPLAIN Plan Visualizationよさそう。ちなみにMySQLにはworkbenchに Visualization explainがある。 EXPLAIN Insightsは時間のかかったレイヤー毎の時間を出すみたい。これすごくよさそう。 私はMySQL派だけどこれは使ってみたい。

An Update on Ruby's JIT Development Progress

「ruby2.7のJITrailsアプリのパフォーマンス改善に注力したけど、仮説が間違っていた。改善はしなかった」と、要約に書いている。 冒頭を少し読んだ感じだと、リリース日であるクリスマスに合わせるために時間とJITで苦戦している感じが伝わりました。Rubyの実装は一切わからないのですが大変そう。 ありがたくRubyを使わせてもらいますm( )m

Pattern Matching: The Big New Feature in Ruby 2.7

ツジモトさんによるRubyConfの発表動画です。 今度見る。

A Practical Demo of Ruby 2.7's Pattern Matching Features

これは解説動画。今度見る。

Ruby 2.7's New ... Shorthand Syntax for Argument Forwarding

2.7から... operatorという構文が追加されたことを紹介する記事。 メソッド引数を別のメソッドにフォワードするための構文みたい。 使いみちが想像できないけど、引数をそのままフォワードする実装をしたことがある気がする。

What's new in Interactive Ruby Shell (IRB) with Ruby 2.7

  • シンタックスハイライト
  • マルチライン
  • 補完
    • デフォルトでインストールされるRDocを元にTABキー入力で補完するとのこと
  • オートインデント機能
    • 2.7からデフォルトで有効になっている。無効にしたいならirbrcに書くことで無効にできる
  • 入力履歴がデフォルトで有効に
    • これも2.7からデフォで有効になった

所感

2.7の次は3.0なんですね。頑張ってほしい!

railsのactivejobアダプターのAsyncAdapterって何?実装は?本番に使える?実用性は?調べてみました。

はじめに

AsyncAdapterってのは、activejobアダプターの1つでオンメモリで完結するジョブキューワーカー。 config.active_job.queue_adapter = :async 「即時実行」と「指定した時間の経過後に実行」が選べる。 ミドルウェアなしで非同期ジョブを実現できて開発環境やテスト環境での使用が推奨されている。本番で向かない理由は後述する。

実装は?

このオンメモリでのジョブキューは、concurrent-rubyのScheduledTaskで実装されている。

github.com

実装シンプルで、AsyncAdapter内にSchedulerとJobWrapperクラス内でScheduledTaskのメソッドで構成している。

本番で使えるの?実用性は?

結論は本番では使ってはいけない。

メール送信とかログ的な記録が向いている、とAsyncAdapterと同様なアーキテクチャhttps://github.com/brandonhilkert/sucker_punch のREADMEに書いているが、AsyncAdapteのソースコードには本番での使用は非推奨と書いている。なぜなら、オンメモリなのでキューをロストする可能性があり、実行される保証がないからである。

これは僕の経験なんですが、非同期処理およびマルチスレッドはエラートラッキングサービスに送信されずに失敗しているということがあったり、WEBプロセスのスレッドとして実行していると、WEBのログに非同期ジョブのログが混ざるわけなのでエラー発生時の検出が非常に困難。それと、WEBと非同期ジョブが1プロセス上でリソースを共有しているため不具合時の切り分けができない、などの運用時の欠点がある。 9割くらいは成功するだろうけど、残りの1割での失敗が許容されるなら採用してもいいと思う。

運用面ではnotコンテナ運用でのデプロイ時だけにジョブが失敗するとかも可能性もあるし、データストアを使っていないので実行したジョブの一覧を画面から見る事もできない。メールの送信可否を確認することが難しい。

繰り返しになるけど、どうでもいい処理だったら使ってヨシ。

おわり。

MySQL5.6をソースからインストールする

dockerの中で作業します。 docker run -it debian:sid bash

環境

root@c12674db7ecf:/mysql-server/bld_debug# cat /etc/debian_version 
10.0
root@c12674db7ecf:/mysql-server/bld_debug# gcc --version |grep gcc
gcc (Debian 9.2.1-21) 9.2.1 20191130

sidなので、、、。

作業ログ

apt-get update
apt-get install build-essential git cmake cmake-gui libssl-dev bison libncurses5-dev
git clone --branch '5.6' --depth 1 https://github.com/mysql/mysql-server
cd mysql-server

ここからは公式ドキュメントに従って進めます。

dev.mysql.com

https://dev.mysql.com/doc/internals/en/cmake-howto-quick-debug-configuration.html

mkdir bld_debug
cd bld_debug
cmake .. -DCMAKE_BUILD_TYPE=Debug
make

cmakeは成功したんですが、makeでエラーになりました。

root@c12674db7ecf:/mysql-server/bld_debug# make
[  0%] Built target INFO_SRC
[  0%] Built target INFO_BIN
[  0%] Built target abi_check
[  2%] Built target zlib
[  5%] Built target edit
[  6%] Built target event
[  8%] Built target event_extra
[ 10%] Built target event_core
[ 13%] Built target strings
[ 19%] Built target mysys
[ 19%] Built target dbug
[ 20%] Built target mysys_ssl
[ 20%] Built target comp_err
[ 20%] Built target GenError
[ 20%] Building CXX object storage/archive/CMakeFiles/archive_embedded.dir/ha_archive.cc.o
In file included from /mysql-server/sql/table.h:40,
                 from /mysql-server/sql/field.h:27,
                 from /mysql-server/sql/unireg.h:179,
                 from /mysql-server/sql/log.h:26,
                 from /mysql-server/sql/sql_class.h:35,
                 from /mysql-server/storage/archive/ha_archive.cc:27:
/mysql-server/sql/table_id.h: In member function 'Table_id Table_id::operator++(int)':
/mysql-server/sql/table_id.h:64:12: error: implicitly-declared 'constexpr Table_id::Table_id(const Table_id&)' is deprecated [-Werror=deprecated-copy]
   64 |     return id;
      |            ^~
/mysql-server/sql/table_id.h:47:8: note: because 'Table_id' has user-provided 'void Table_id::operator=(const Table_id&)'
   47 |   void operator=(const Table_id &tid) { m_id = tid.m_id; }
      |        ^~~~~~~~
In file included from /mysql-server/sql/unireg.h:179,
                 from /mysql-server/sql/log.h:26,
                 from /mysql-server/sql/sql_class.h:35,
                 from /mysql-server/storage/archive/ha_archive.cc:27:
/mysql-server/sql/field.h: In copy constructor 'constexpr Field_num::Field_num(const Field_num&)':
/mysql-server/sql/field.h:1461:7: error: implicitly-declared 'constexpr Field::Field(const Field&)' is deprecated [-Werror=deprecated-copy]
 1461 | class Field_num :public Field {
      |       ^~~~~~~~~
/mysql-server/sql/field.h:463:8: note: because 'Field' has user-provided 'void Field::operator=(Field&)'
  463 |   void operator=(Field &);
      |        ^~~~~~~~
/mysql-server/sql/field.h: In copy constructor 'constexpr Field_real::Field_real(const Field_real&)':
/mysql-server/sql/field.h:1572:7: note: synthesized method 'constexpr Field_num::Field_num(const Field_num&)' first required here
 1572 | class Field_real :public Field_num {
      |       ^~~~~~~~~~
/mysql-server/sql/field.h: In copy constructor 'constexpr Field_decimal::Field_decimal(const Field_decimal&)':
/mysql-server/sql/field.h:1598:7: note: synthesized method 'constexpr Field_real::Field_real(const Field_real&)' first required here
 1598 | class Field_decimal :public Field_real {
      |       ^~~~~~~~~~~~~
/mysql-server/sql/field.h: In member function 'virtual Field_decimal* Field_decimal::clone(MEM_ROOT*) const':
/mysql-server/sql/field.h:1626:46: note: synthesized method 'constexpr Field_decimal::Field_decimal(const Field_decimal&)' first required here
 1626 |     return new (mem_root) Field_decimal(*this);
      |                                              ^
/mysql-server/sql/field.h: In copy constructor 'constexpr Field_str::Field_str(const Field_str&)':
/mysql-server/sql/field.h:1501:7: error: implicitly-declared 'constexpr Field::Field(const Field&)' is deprecated [-Werror=deprecated-copy]
 1501 | class Field_str :public Field {
      |       ^~~~~~~~~
/mysql-server/sql/field.h:463:8: note: because 'Field' has user-provided 'void Field::operator=(Field&)'
  463 |   void operator=(Field &);
      |        ^~~~~~~~
/mysql-server/sql/field.h: In copy constructor 'constexpr Field_null::Field_null(const Field_null&)':
/mysql-server/sql/field.h:2102:7: note: synthesized method 'constexpr Field_str::Field_str(const Field_str&)' first required here
 2102 | class Field_null :public Field_str {
      |       ^~~~~~~~~~
/mysql-server/sql/field.h: In member function 'virtual Field_null* Field_null::clone(MEM_ROOT*) const':
/mysql-server/sql/field.h:2142:43: note: synthesized method 'constexpr Field_null::Field_null(const Field_null&)' first required here
 2142 |     return new (mem_root) Field_null(*this);
      |                                           ^
/mysql-server/sql/field.h: In copy constructor 'constexpr Field_temporal::Field_temporal(const Field_temporal&)':
/mysql-server/sql/field.h:2155:7: error: implicitly-declared 'constexpr Field::Field(const Field&)' is deprecated [-Werror=deprecated-copy]
 2155 | class Field_temporal :public Field {
      |       ^~~~~~~~~~~~~~
/mysql-server/sql/field.h:463:8: note: because 'Field' has user-provided 'void Field::operator=(Field&)'
  463 |   void operator=(Field &);
      |        ^~~~~~~~
/mysql-server/sql/field.h: In copy constructor 'constexpr Field_temporal_with_date::Field_temporal_with_date(const Field_temporal_with_date&)':
/mysql-server/sql/field.h:2363:7: note: synthesized method 'constexpr Field_temporal::Field_temporal(const Field_temporal&)' first required here
 2363 | class Field_temporal_with_date :public Field_temporal {
      |       ^~~~~~~~~~~~~~~~~~~~~~~~
/mysql-server/sql/field.h: In copy constructor 'constexpr Field_temporal_with_date_and_time::Field_temporal_with_date_and_time(const Field_temporal_with_date_and_time&)':
/mysql-server/sql/field.h:2437:7: note: synthesized method 'constexpr Field_temporal_with_date::Field_temporal_with_date(const Field_temporal_with_date&)' first required here
 2437 | class Field_temporal_with_date_and_time :public Field_temporal_with_date {
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/mysql-server/sql/field.h: In copy constructor 'constexpr Field_timestamp::Field_timestamp(const Field_timestamp&)':
/mysql-server/sql/field.h:2551:7: note: synthesized method 'constexpr Field_temporal_with_date_and_time::Field_temporal_with_date_and_time(const Field_temporal_with_date_and_time&)' first required here
 2551 | class Field_timestamp :public Field_temporal_with_date_and_time {
      |       ^~~~~~~~~~~~~~~
/mysql-server/sql/field.h: In member function 'virtual Field_timestamp* Field_timestamp::clone(MEM_ROOT*) const':
/mysql-server/sql/field.h:2582:48: note: synthesized method 'constexpr Field_timestamp::Field_timestamp(const Field_timestamp&)' first required here
 2582 |     return new (mem_root) Field_timestamp(*this);
      |                                                ^
/mysql-server/sql/field.h: In copy constructor 'constexpr Field_bit::Field_bit(const Field_bit&)':
/mysql-server/sql/field.h:3663:7: error: implicitly-declared 'constexpr Field::Field(const Field&)' is deprecated [-Werror=deprecated-copy]
 3663 | class Field_bit :public Field {
      |       ^~~~~~~~~
/mysql-server/sql/field.h:463:8: note: because 'Field' has user-provided 'void Field::operator=(Field&)'
  463 |   void operator=(Field &);
      |        ^~~~~~~~
/mysql-server/sql/field.h: In member function 'virtual Field_bit* Field_bit::clone(MEM_ROOT*) const':
/mysql-server/sql/field.h:3756:42: note: synthesized method 'constexpr Field_bit::Field_bit(const Field_bit&)' first required here
 3756 |     return new (mem_root) Field_bit(*this);
      |                                          ^
cc1plus: all warnings being treated as errors
make[2]: *** [storage/archive/CMakeFiles/archive_embedded.dir/build.make:76: storage/archive/CMakeFiles/archive_embedded.dir/ha_archive.cc.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:496: storage/archive/CMakeFiles/archive_embedded.dir/all] Error 2
make: *** [Makefile:163: all] Error 2

私はgccコンパイラ事情についてを疎く、 https://github.com/rails/rails/issues/38087 あたりを見るとgcc9特有の出力みたいです。 gcc8にすればmakeが成功するだろうか。

続く。

rails6にしたらTransactionというクラスが見つからなくなったのだが。

github.com

rails6にするまでは動いていたんだけど、Transactionクラスのメソッド呼び出しで undefined method がでるようになったんだけど、 Transactionクラスを持つことはrails6からは許可されていませんか?というissueというか完全なる質問。

これについてコメントが1件ついた。 コメントにはコマンドラインでTransactionモデルを作成するという完結な再現するはずのコードが寄せられた。しかし再現しなかったので、再現コードを提供できますか?という質問がついた。

$ rails new blabbedy --skip-javascript
$ cd blabbedy
$ rails generate scaffold transaction
$ rails db:migrate
$ rails runner 'Transaction.create!'

rails6からクラスロードが変わったので、その Transctionクラスのロードができていないとかだと思うなー。いずれにせよ、英語ネイティブの人はissueをポンポン作るという印象がある。それだけ活気があり、打ち返すだけの意欲のある人々がコミュニティにいるということなので、これはこれですごい。

etagに関するドキュメントの変更

github.com

etagに関するドキュメントで誤りがあって、それを修正プルリクエスト。

  • fresh_when etag: @article # correct
  • fresh_when @article # incorrect

最終的にはマージされたものの、マージした人いわく、このドキュメントを変更したところであまり変わらないだろう、とのこと。 僕はetagの実装がわかっていないので深くは踏み込まないんですが、何か事情ありの実装らしい。

  • After reading through~
    • ~を読んだ後
  • side-effects
    • 副作用
  • subtle
    • 微妙
  • event
    • でさえ

Rails6でadd_referenceすると `null: false` が追加されるのだが

github.com

タイトルの通り、rails g migration AddColumnsToTable name user:references を実行すろと、null: falseオプションが追加される仕様に異議を唱えるissue。 この人が言っていることは2つあって

  • null: falseつくけど、 belongs_toがオプショナルな可能性もあるじゃん?
  • 既存テーブルにadd_referenceのままを適用したら defailt値に nullが入ってしまいPostgreSQLだとエラーになるよ。null: falseいらなくない?

と言っている。

このような振る舞いになったプルリクエストはコメントで貼られてissueはクローズされそうなムード。

github.com

ここからは僕の感想なんですが、DBに適用するのはお前の仕事じゃん。generatorはただのgeneratorなんだからお前の用途に合わせてお前が実行前に修正しろ。

  • as for
    • ~に関して

パーシャルのコレクションレンダリングでnilを渡す

github.com

パーシャルをレンダリングする時ってeachで回すと、N+1クエリ状態ですごく遅いんだよね。そういう時はパーシャルのレンダリングオプションにcollectionをつけることで、 レンダリングのオーバーヘッドを抑えることができる。

render 'books', as: :book, collection: books

で、このissueは render 'books', as: :book, collection: nil だと、エラーが起きていない仕様に対して意義を唱えている。 インスタンス変数って未定義だとnilじゃん。タイポがあるとエラーの発見できないじゃん。だからcollectionにnilが入ってきたらエラーを投げようぜ。ということが書いている。

このissue主はプルリクエストも作っていて、そのプルリクエストには破壊的変更なので非推奨から起こす必要がたぶんあるってコメントをもらっている。

僕自身はこの変更についてはどっちでもいいかなと思う。rubocopで検出できる内容だし。