Railsでコネクションプール②　初心者→中級者へのSTEP24/25

#Railsでコネクションプール②
##はじめに
[前回](https://qiita.com/kamohicokamo/items/2414248c19e6e2fca7b3)、Mysqlを導入し、軽くconnection_poolについて触れました。
今回は実際にコードと共に確認してみます。


##DB設定
設定ファイルは以下の通りでMySQLを使います。そしてプール数は5、

```yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: 秘密
  host: localhost
  connect_timeout: 3
```

つまり、予想ではDBにアクセスする（クエリを作成する）スレッドを６つ作れば、一つは接続を待たされることになるはず。

##スレッドを６つ作ってみる。

```rb
  def index
    1.upto(6) {|num|
      Thread.new do
        begin
          p User.find(num).name
        rescue
          p 'error' 
        end
      end
    }
  end
```

実行すると

```console
Started GET "/users/" for 127.0.0.1 at 2018-12-24 23:09:02 +0900
   (1.1ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
   (1.7ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
   (0.4ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
   (0.3ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
   (0.4ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
Processing by UsersController#index as HTML
  Rendering users/index.html.haml within layouts/application
  Rendered users/index.html.haml within layouts/application (2.3ms)
Completed 200 OK in 30ms (Views: 23.3ms | ActiveRecord: 0.0ms)


  User Load (11.4ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
  User Load (14.4ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
"Lilly Littel"
  User Load (19.3ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 3 LIMIT 1
"Noemie Kautzer"
  User Load (19.7ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 4 LIMIT 1
"Lonny Bernier"
"Maryam Ankunding"
  User Load (0.4ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 6 LIMIT 1
"Ottis Schuster"
"error"
```
予想どうり、一つのスレッドだけ接続できてないですね。ではプール数を６に増やすとどうなるのでしょう。

```yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 6 } %>
  username: root
  password: yuusuke0476
  host: localhost
  connect_timeout: 3
```
pool数を設定し直しました。実行してみます。予想通りなら６つのスレッド全てに置いてuserの名前を取得してきてくれるはずです。

```console
   (0.7ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
   (0.5ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
   (1.6ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
   (0.4ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
   (1.3ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
  User Load (3.9ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 6 LIMIT 1
"Ottis Schuster"
  User Load (13.8ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 5 LIMIT 1
"Carter Bednar"
  User Load (13.9ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 3 LIMIT 1
  User Load (14.6ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
"Noemie Kautzer"
Maryam Ankunding"
  User Load (11.3ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
"Lilly Littel"

"error"
```
....あれえぇ？エラーが消えない...てかちゃんとメッセージ出力しましょうね。rescueの部分を下記のように修正

```rb
  rescue => e
    p e
  end
```

```console
  User Load (0.6ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 6 LIMIT 1
"Ottis Schuster"
  User Load (10.6ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 4 LIMIT 1
  User Load (11.9ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 5 LIMIT 1
"Lonny Bernier"
  User Load (1.0ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
"Carter Bednar"
Maryam Ankunding"

  User Load (1.1ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
"Lilly Littel"
#<ActiveRecord::ConnectionTimeoutError: could not obtain a connection from the pool within 5.000 seconds (waited 5.004 seconds); all pooled connections were in use>
```
`could not obtain a connection from the pool`？connectionが解放されてないっぽい？

スレッドが生きているのかなと思い、状態をみてみる(スレッドを６つ生成してから10秒後)下記を追加。

```rb
  sleep 10
  pp Thread.list
```

```console
 #<Thread:0x007f98e55778c8@/ほにゃらら~~~/reactor.rb:249 sleep>,
 #<Thread:0x007f98e5577710@/ほにゃらら~~/thread_pool.rb:280 sleep>,
   .
   .
   略
   .
   .
 #<Thread:0x007f98e5577710@/ほにゃらら~~/thread_pool.rb:280 sleep>,
```

ない...つまりスレッドはちゃんと終了している。なのにconnectionが解放されてない。
pool数が反映されない...なぜだ...

〜〜〜〜〜１時間後〜〜〜〜〜

**rails再起動したらなおりました!!**
これでちゃんと同時接続の確認ができました...
ちなみに今回のように１プロセスに複数のスレッドがあるようなことはほぼほぼ無いので、ご注意を、テストしたかったので強引なコード書いちゃいましたかね...



##まとめ
このテーマむずかった...ググってたらRails以外の知識を必要として手こずりました。
ひとまず確認コードがかけてよかったです。connection_poolの実用的なテクニックはもっと知識積んでから勉強します...

明日最後ですね...なにかこ...