[Bug] WebSocket Streams: after a connection drops, resubscribing to the same stream on the same client sends nothing
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 82/100
Línea de trabajo
Lee common/src/binance_common/websocket.py, especialmente _discard_connection() y _forget_connection_streams(), y luego ejecuta la reproducción descrita en el issue contra un servidor WebSocket local. Comprueba que, después de que se pierda la conexión, al volver a suscribirse con el mismo cliente se envíe SUBSCRIBE y se entregue la actualización de recuperación. El issue sugiere olvidar los streams de la conexión muerta al final de _discard_connection().
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
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).
- Lenguaje dominante
- Python
- Estrellas
- 2.9k
- Forks
- 708
- Merge medio
- 1 d 5 h
- PR fusionados (30 d)
- 4
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de binance/binance-connector-python
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
binance/binance-connector-python#570 · 2 comentarios ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
binance/binance-connector-python#514 · 2 comentarios ·
-
Dificultad 4/5 3-5 días Aptitud para principiantes 15/100
-
[Bug] Response models declare numeric fields as strict `str`, causing silent fallback of `.data()` to raw dict (simple-earn & staking)Posiblemente ocupada @Tyagiquamar la tomó hace 29 días. Abierto
Dificultad 4/5 3-5 días Aptitud para principiantes 68/100
binance/binance-connector-python#553 · 2 comentarios ·
-
Dificultad 5/5 Más de una semana Aptitud para principiantes 20/100
Todos los issues de binance/binance-connector-python
Issues similares
-
Custom provider API keys collide on one host: env slot keyed on host:port only, not URL pathAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
NousResearch/hermes-agent#140958 ·
Los mantenedores suelen responder en 1 día
-
Bisect issue233186Abiertobisect
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
dtcxzyw/llvm-bisect-service#548 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
sallowayma-git/IELTS-practice#248 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 65/100
anthropics/claude-plugins-official#6763 · 10 comentarios · 10 reacciones ·
Los mantenedores suelen responder en 3 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
Los mantenedores suelen responder en 1 día