Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ Changelog
- Fix missing teardown for session and module scoped fixtures when fixture teardown fails.
Fixes `#314 <https://github.com/pytest-dev/pytest-rerunfailures/issues/314>`_.

- Fix ``_sock_recv`` infinite loop when the StatusDB TCP connection drops.
``recv(1)`` returning empty bytes (closed connection) was not handled,
causing workers to spin at 100% CPU indefinitely during xdist runs.


16.1 (2025-10-10)
-----------------
Expand Down
2 changes: 2 additions & 0 deletions src/pytest_rerunfailures.py
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,8 @@ def _sock_recv(self, conn) -> str:
buf = b""
while True:
b = conn.recv(1)
if not b:
raise ConnectionError("StatusDB connection closed unexpectedly")
if b == self.delim:
break
buf += b
Expand Down
21 changes: 20 additions & 1 deletion tests/test_pytest_rerunfailures.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import random
import socket
import time
from unittest import mock

import pytest

from pytest_rerunfailures import HAS_PYTEST_HANDLECRASHITEM
from pytest_rerunfailures import HAS_PYTEST_HANDLECRASHITEM, SocketDB

pytest_plugins = "pytester"

Expand Down Expand Up @@ -1407,3 +1408,21 @@ def test_fail():

result = testdir.runpytest("--force-reruns", "3")
assert_outcomes(result, passed=0, failed=1, rerun=3)


def test_sock_recv_raises_on_closed_connection():
"""_sock_recv should raise ConnectionError when recv returns empty bytes
(connection closed), not loop forever.

Previously, _sock_recv had no check for empty bytes from recv(1), causing
an infinite CPU-spinning loop when the server-side connection dropped.
This manifested as indefinite hangs during xdist test runs.
"""
s1, s2 = socket.socketpair()
s2.close() # Close one end — recv on s1 will return b""

db = SocketDB()
with pytest.raises(ConnectionError, match="closed unexpectedly"):
db._sock_recv(s1)

Comment on lines +1424 to +1427
s1.close()
Comment on lines +1422 to +1428
Comment on lines +1425 to +1428
Loading