Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

[Bug] WebSocket Streams: after a connection drops, resubscribing to the same stream on the same client sends nothing

Đang mở Phù hợp với người mới
#576 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Đánh giá

Độ khó
2/5
Thời gian dự kiến
1-3 giờ
Mức phù hợp với người mới
82/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
python
Lĩnh vực
api, backend

Hướng nghiên cứu

Đọc common/src/binance_common/websocket.py, đặc biệt là _discard_connection() và _forget_connection_streams(), sau đó chạy cách tái hiện được mô tả trong issue với một máy chủ WebSocket cục bộ. Kiểm tra rằng sau khi kết nối bị ngắt, việc đăng ký lại bằng cùng một client sẽ gửi SUBSCRIBE và chuyển giao bản cập nhật khôi phục. Issue đề xuất quên các stream của kết nối đã chết ở cuối _discard_connection().

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Follow-up to #570, which common v4.6.0 fixed for two clients in one process. With a single client, one case from the same stream map remains: after a stream connection drops unexpectedly, subscribing to the same stream again on a new connection does nothing. No SUBSCRIBE is sent, nothing is raised, nothing is logged about the skipped stream, and no messages arrive, so the stream looks like a quiet market. Recovering through a new Spot client works in 4.6.0.

When the server closes the connection or the TCP connection drops, the receive loop fires close and calls _discard_connection() (lines 414, 421 and 428), which removes the connection from the pool (line 497). The client's stream_connections still maps the stream to the dead connection, because _forget_connection_streams() runs only after a failed planned reconnect (line 907) and on a user-initiated close (line 1138). On the next subscribe, subscribe() filters the stream out as already registered (lines 1288-1292), and on() attaches the callback to the dead connection (lines 1361-1367). Spot.websocket_streams is cached, and create_connection() on it returns the same instance, so the new connection shares the stale map. Line numbers are from common/src/binance_common/websocket.py at a54ec0b, which matches the 4.6.0 release.

Reproduce

binance-sdk-spot==13.2.0, binance-common==4.6.0, aiohttp==3.14.5, Python 3.14.8. A local aiohttp server drops the first connection's TCP without a close frame. The client then opens a new connection on the same Spot client and subscribes to the same stream again. A close frame (1001) in place of the TCP drop gives the same result.

Reproduction script and output
import asyncio, json, logging
from aiohttp import web
from binance_common.configuration import ConfigurationWebSocketStreams
from binance_sdk_spot.spot import Spot
logging.disable(logging.CRITICAL)
conns, subs = [], []
async def handler(request):
    ws = web.WebSocketResponse(); await ws.prepare(request)
    conns.append(request); conn = len(conns)
    async for msg in ws:
        d = json.loads(msg.data)
        if d["method"] == "SUBSCRIBE":
            subs.append((conn, d["params"]))
            await ws.send_json({"id": d["id"], "result": None})
            for s in d["params"]:
                await ws.send_json({"stream": s, "data": {"e": "depthUpdate", "E": 1, "s": "BNBUSDT", "U": conn, "u": conn, "b": [], "a": []}})
            if conn == 1:
                await asyncio.sleep(0.2)
                request.transport.abort()  # the TCP connection drops, no close frame
    return ws
async def main():
    app = web.Application(); app.router.add_get("/stream", handler)
    r = web.AppRunner(app); await r.setup(); await web.TCPSite(r, "127.0.0.1", 18767).start()
    client = Spot(config_ws_streams=ConfigurationWebSocketStreams(stream_url="ws://127.0.0.1:18767/stream"))
    got, events = [], []
    ws = await client.websocket_streams.create_connection()
    ws.on_connection("close", lambda *a: events.append("close"))
    (await ws.diff_book_depth(symbol="bnbusdt")).on("message", lambda m: got.append(("first", m.U)))
    await asyncio.sleep(0.5)
    # recover: a new connection on the same client, same stream
    ws2 = await client.websocket_streams.create_connection()
    (await ws2.diff_book_depth(symbol="bnbusdt")).on("message", lambda m: got.append(("recovery", m.U)))
    await asyncio.sleep(0.5)
    print("same instance:", ws2 is ws)
    print("connections accepted by the server:", len(conns))
    print("connection events:", events)
    print("SUBSCRIBE frames received (connection, params):", subs)
    print("messages delivered:", got)
    await ws2.close_connection(close_session=True); await r.cleanup()
asyncio.run(main())

Output:

same instance: True
connections accepted by the server: 2
connection events: ['close']
SUBSCRIBE frames received (connection, params): [(1, ['bnbusdt@depth'])]
messages delivered: [('first', 1)]

Expected

The second connection sends SUBSCRIBE for bnbusdt@depth, and the recovery callback receives the second connection's update.

Suggested fix

Call self._forget_connection_streams(connection) at the end of _discard_connection(), after its early return for planned reconnects. Its docstring already describes this case: "A connection that is gone for good must not be left in the stream maps, or a later subscribe would treat its streams as still live and silently skip them." With that call patched in, the script above shows one SUBSCRIBE per connection and delivers ('recovery', 2).

Ngôn ngữ chính
Python
Star
2.9k
Fork
708
Merge trung bình
1 ngày 5 giờ
Pull request đã merge (30 ngày)
4

Chuẩn bị môi trường

Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của binance/binance-connector-python

Tất cả issue của binance/binance-connector-python

Issue tương tự

Thêm issue về Python

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.