Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebScoket 再接続のバックオフを指定できるようにする #258

Closed
Tracked by #205
MtkN1 opened this issue Jan 12, 2024 · 0 comments · Fixed by #259
Closed
Tracked by #205

WebScoket 再接続のバックオフを指定できるようにする #258

MtkN1 opened this issue Jan 12, 2024 · 0 comments · Fixed by #259

Comments

@MtkN1
Copy link
Member

MtkN1 commented Jan 12, 2024

Summary

Python における素晴らしい WebSocket ライブラリである websockets の再接続実装を参考にして、pybotters の再接続ロジックに同等のバックオフ機能を実装します。

  • 現状の再接続ロジック
    • 前回の接続試行から 60 秒以内の再接続であれば、60 秒から経過時間を引いた秒数の間待機します
  • 新しい再接続ロジック
    • 正常切断であれば待機なしで再接続します
    • ハンドシェイク失敗であればバックオフロジックの結果秒数待機します
      • 初回の接続失敗であれば 0 ~ 5 秒 (BACKOFF_INITIAL) の間のランダムな時間待機します
      • 二回目の接続失敗であれば 1.92 秒 (BACKOFF_MIN) に 1.618 (BACKOFF_FACTOR) を掛けた時間待機します
      • その後の接続失敗であれば前回の待機時間にさらに 1.618 (BACKOFF_FACTOR) を掛けた時間待機します
      • ただし待機時間の上限は 60.0 秒 (BACKOFF_MAX) です
      • 接続に成功した場合はバックオフの計算は初回のステップにリセットされます
    • BACKOFF_INITIAL, BACKOFF_MIN, BACKOFF_FACTOR, BACKOFF_MAX は Client.ws_connect の引数 backoff で指定することができます

Reference from websocketes

https://github.com/python-websockets/websockets/blob/12.0/src/websockets/legacy/client.py#L589-L624

    BACKOFF_MIN = 1.92
    BACKOFF_MAX = 60.0
    BACKOFF_FACTOR = 1.618
    BACKOFF_INITIAL = 5


    async def __aiter__(self) -> AsyncIterator[WebSocketClientProtocol]:
        backoff_delay = self.BACKOFF_MIN
        while True:
            try:
                async with self as protocol:
                    yield protocol
            except Exception:
                # Add a random initial delay between 0 and 5 seconds.
                # See 7.2.3. Recovering from Abnormal Closure in RFC 6544.
                if backoff_delay == self.BACKOFF_MIN:
                    initial_delay = random.random() * self.BACKOFF_INITIAL
                    self.logger.info(
                        "! connect failed; reconnecting in %.1f seconds",
                        initial_delay,
                        exc_info=True,
                    )
                    await asyncio.sleep(initial_delay)
                else:
                    self.logger.info(
                        "! connect failed again; retrying in %d seconds",
                        int(backoff_delay),
                        exc_info=True,
                    )
                    await asyncio.sleep(int(backoff_delay))
                # Increase delay with truncated exponential backoff.
                backoff_delay = backoff_delay * self.BACKOFF_FACTOR
                backoff_delay = min(backoff_delay, self.BACKOFF_MAX)
                continue
            else:
                # Connection succeeded - reset backoff delay
                backoff_delay = self.BACKOFF_MIN
This was referenced Jan 12, 2024
@MtkN1 MtkN1 linked a pull request Jan 13, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant