Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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