socket.IOにおけるサーバダウン時の再接続イベントの順序

# サーバが復旧したら自動的に再接続したい

* イベントたくさんあるんだけど...
    * Event: ‘connect_error’
    * Event: ‘connect_timeout’
    * Event: ‘reconnect’
    * Event: ‘reconnect_attempt’
    * Event: ‘reconnecting’
    * Event: ‘reconnect_error’
    * Event: ‘reconnect_failed’
* 実は、**自動で再接続してくれる**
    * これらのエラーハンドラに何も書く必要なし
    * connectイベントに実際の接続処理を書いておくだけで良い
    * io.connect()を呼び出して、socketが割り当てられると、
        * クライアントにはconnect()
        * サーバにはconnection()が発生

```javascript
    // 先に接続者にIDを割り当てておく
    this.pid    = Math.floor(Math.random()*100)
    this.userID = this.username+"_"+ this.pid
    socket.on("connect", ()=>{
      const msg = [new Date().toRFC2822(), "client", this.username,
                   "[" + this.pid, "user.info]:", "CONN (" + this.target +")", this.host].join(" ")      
      socket.emit("connected", this.username, this.pid, this.target);
    });
    //こんな感じ
```

---
# せっかく調べたので書き記しておく

## イベントの発生順序

* 最終的に失敗する場合
    1. connect_error
    2. reconnect_attempt
    3. reconnecting
    4. connect_error
    5. reconnect_error
    6. reconnect_attempt
    7. reconnecting
    8. connect_error
    9. reconnect_error
    10. ... 以下2.から5.をreconnectionAttempts回数繰り返し
    11. reconnect_failed
* 途中で再接続に成功する場合
    1. connect_error
    2. reconnect_attempt ... 1
    3. reconnecting
    4. connect_error
    5. reconnect_error
    6. reconnect_attempt ... 2
    7. reconnecting
    8. reconnect
    9. connect

---
# 得られた知見

* connect_errorとreconnect_errorが一対で出る
    * どういう場合で有用？
* reconnect_attemptとreconnectingの間の時間はパラメータで指定
    * reconnectionDelay: ミリ秒
* デフォルトでは、無限に再接続を試みる
    * 有限回でやめたい時はパラメータで指定
    * reconnection: true; 
    * reconnectionAttempts: 回数
* connect_timeoutとの関係は、、、?
    * 誰か調べて
    * タイムアウトまでの間に試行し続けるので永遠にタイムアウトしない様子


---
# クリーンアーキテクチャにおけるチャットクライアント

* チャットクライアントとControllerは**位置付けが同じ**
    * View上のイベントをusecaseに中継するのがController
    * サーバ上のイベントをusecaseに中継するのがチャットクライアント
* チャットサーバは外部インターフェース
    * チャットクライアントはAdapterの一種    
    * io.connect()でsocketが割り当て、usecaseを束縛しておくと良いようだ
    * サーバから受け取るイベント、そのイベントハンドラ内でusecaseを呼ぶ
* 従ってinitializer部で、io.connect()を開始すること
   
```javascript
class WebChat {
  constructor(driver){
    this.driver = driver
  }
  open(usecase){
    this.socket = io.connect(this.driver.host, this.driver.opts)
    this.socket.on('connect', function(socket){
       // 接続処理
       usecase.addMessage({value: "CONNECT successfully"})
    })
    return this
  }
}
```
 
---
# まとめ

* socket.IOではサーバダウン時の再接続はデフォルトで有効になっている
    * デフォルトでは無限に(**毎秒**)再接続を試みるので、それはそれで要注意   
* 再接続を有限回繰り返す場合は、io.connect(host,{                                                                                            
                                 'reconnection': true,                                                                      
                                 'reconnectionDelay': 1000,                                                                 
                                 'reconnectionDelayMax' : 5000,                                                             
                                 'reconnectionAttempts': 5                                                                  
                               })
                                                                                    

# 参考情報
* [なんにも知らなかったsocket.io](http://d.hatena.ne.jp/factory-g/20150217/1424159795)
* [Socket.IO/Client API](https://socket.io/docs/client-api/)
* [from scratch/socket.io が提供してくれているものは何か](https://yosuke-furukawa.hatenablog.com/entry/2016/08/27/105400)