fix(media): Circuit-Breaker für D-Bus-Connect-Fehler
Nach dem ersten fehlgeschlagenen Bus-Connect wird der Controller dauerhaft deaktiviert, statt bei jedem Hotkey-Druck einen neuen Connect-Versuch zu starten. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -173,3 +173,27 @@ async def test_pause_is_noop_when_bus_unreachable(monkeypatch, caplog):
|
|||||||
assert controller._paused == []
|
assert controller._paused == []
|
||||||
assert any("D-Bus" in r.message or "bus" in r.message.lower()
|
assert any("D-Bus" in r.message or "bus" in r.message.lower()
|
||||||
for r in caplog.records)
|
for r in caplog.records)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_pause_skips_reconnect_after_bus_failure(monkeypatch):
|
||||||
|
"""Bus-Connect-Fehler darf nicht bei jedem Aufruf erneut versucht werden."""
|
||||||
|
from whisper_local.media._mpris import MprisController
|
||||||
|
|
||||||
|
connect_calls = 0
|
||||||
|
|
||||||
|
async def failing_connect(self):
|
||||||
|
nonlocal connect_calls
|
||||||
|
connect_calls += 1
|
||||||
|
raise RuntimeError("no session bus")
|
||||||
|
|
||||||
|
monkeypatch.setattr(
|
||||||
|
"dbus_next.aio.MessageBus.connect", failing_connect, raising=False
|
||||||
|
)
|
||||||
|
controller = MprisController()
|
||||||
|
|
||||||
|
await controller.pause()
|
||||||
|
await controller.pause()
|
||||||
|
await controller.pause()
|
||||||
|
|
||||||
|
assert connect_calls == 1
|
||||||
|
|||||||
@@ -18,8 +18,11 @@ class MprisController:
|
|||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self._paused: list[str] = []
|
self._paused: list[str] = []
|
||||||
self._bus: Any = None
|
self._bus: Any = None
|
||||||
|
self._bus_broken: bool = False
|
||||||
|
|
||||||
async def _ensure_bus(self) -> Any:
|
async def _ensure_bus(self) -> Any:
|
||||||
|
if self._bus_broken:
|
||||||
|
raise RuntimeError("D-Bus session bus is unavailable")
|
||||||
if self._bus is None:
|
if self._bus is None:
|
||||||
from dbus_next.aio import MessageBus
|
from dbus_next.aio import MessageBus
|
||||||
self._bus = await MessageBus().connect()
|
self._bus = await MessageBus().connect()
|
||||||
@@ -65,7 +68,11 @@ class MprisController:
|
|||||||
try:
|
try:
|
||||||
names = await self._list_player_names()
|
names = await self._list_player_names()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("D-Bus nicht erreichbar, überspringe Media-Pause: %s", e)
|
if not self._bus_broken:
|
||||||
|
logger.warning(
|
||||||
|
"D-Bus nicht erreichbar, Media-Pause dauerhaft deaktiviert: %s", e
|
||||||
|
)
|
||||||
|
self._bus_broken = True
|
||||||
self._paused = []
|
self._paused = []
|
||||||
return
|
return
|
||||||
results = await asyncio.gather(
|
results = await asyncio.gather(
|
||||||
|
|||||||
Reference in New Issue
Block a user