-
Notifications
You must be signed in to change notification settings - Fork 119
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
BrokenPipeError (?) when idle for a long time #64
Comments
Duplicate of #31 |
Hello Jörg! I'm aware of #31 and ConnectionErrors. Prove me wrong, but I don't see how this issue is related to that. My script should catch all ConnectionErrors with
Please find the whole script here: https://gist.github.com/speendo/0d9c1a028d045de3f7a6 After a couple of hours of idle time I get a (generic) BrokenPipeError which - as far as I know - is not related to the mpd-specific ConnectionError. I would be glad if you could clarify why this is a duplicate or reopen the issue. Thank you! |
ok. take a look at it. |
Thank you! |
The problem here is, that mpd does not mask any exception thrown at all, which are generated by the layers below. Sorry this was not my invention. The alternative is exception chaining (catching the error and rethrow an MPDError inheriting the original one). Python 2 does not support this. However it is possible to a custom reference in the exeption to its root cause. |
Okay, thank you. Took me some time but I think I understand the problem now. I use Python3 anyway but I understand that this is not a solution you would want to offer only for Python3 users... I would like to avoid catching all Exceptions and do something like
as this is considered as bad style... Is there a way to be more specific - maybe using the custom reference? |
Wouldn't this be a possible solution? [edit] |
Just for testing purposes, I tried to catch every exception and reconnect to the server, if I catch one. Like this:
(find a full example here: https://gist.github.com/speendo/91de6511443e75f18fed) This also didn't work because the client still thinks it is connected. I get this error:
As far as I understand this, this means I would have to close the (broken) connection first before I could reestablish the client's connection, right? This would be a bit akward. I am only a hobby programmer and not an expert, but from my point of view I think that python-mpd2 should catch the BrokenPipeError and do something about it - either set the connection closed or reestablish the connection. If the connection is not reestablished for me it would feel more natural if my script would fire a MPD.ConnectionError instead of a "generic" BrokenPipeError. However, do you know of a way to get the BrokenPipeError more quickly? Because every test I make takes me 4 hours which is quite a lot for someone who can only code in his free time ;-) By the way: Schöne Weihnachten! |
To repro the BrokenPipeError, assuming you have a mpd server running on localhost on port 6600:
As stated above, one cannot call a client.connect(...) to remedy the situation as the client._sock object exists, and mpd thus believes it is still connected. To handle this case I am catching BrokenPipeError and then calling a client._reset(), which sets the _sock object to None. From here I can attempt to reconnect using client.connect(...) |
Hi. I'm running into this issue as well. After some hours, the connection get dropped and get a socket errors all over the place. It only happens after some hours. Sad story: I build a device to play music for my little daughter (4 years) - it worked great for many months until I switched to python-mpd2. She goes to bed and listens to music and as soon she wakes up she like to hear her favorite audio book. So, now she wakes me up at 5am and I need to reboot the device. :( I reworked the connection/re-connection and expectation handling many times (takes one day turn-around for each test) but always ended up with a new exception or fail. I’m going to test this merge request locally in the next day. But could you please revive the discussions around this merge request and drive that forward. I would really appreciate a fix for this. |
Hello TomTom0815 I use this library for my Project FlushFM - a webradio on my toilet that starts playing every time the light goes on. It's working fine for a more than a year now, so chances are that my pull request will work for you too. I wish you (and your daughter) the best :) |
I had the same problem and solved/worked around it by calling I think |
Maybe something like: def disconnect(self):
logger.info("Calling MPD disconnect()")
try:
if (self._rfile is not None
and not isinstance(self._rfile, _NotConnected)):
self._rfile.close()
if (self._wfile is not None
and not isinstance(self._wfile, _NotConnected)):
self._wfile.close()
if self._sock is not None:
self._sock.close()
finally:
self._reset() So it will still raise its exception, but afterwards the mpd instance is able to reconnect. |
I find it quite astonishing, that the library does not handle the The problem is, that I worked around this deficiency by wrapping from mpd import MPDClient
from mpd import ConnectionError as MPDConnectionError
class MPDClientWrapper(object):
def __init__(self, *args, **kwargs):
self.__dict__['_mpd'] = MPDClient(*args, **kwargs)
def __getattr__(self, name):
a = self._mpd.__getattribute__(name)
if not callable(a): return a
def b(*args, **kwargs):
try:
return a(*args, **kwargs)
except (MPDConnectionError, ConnectionError) as e:
cargs, ckwargs = self.__dict__['_connect_args']
self.connect(*cargs, **ckwargs)
return a(*args, **kwargs)
return b
def __setattr__(self, name, value):
self._mpd.__setattr__(name, value)
def connect(self, *args, **kwargs):
self.__dict__['_connect_args'] = args, kwargs
self.disconnect()
self._mpd.connect(*args, **kwargs)
def disconnect(self):
try:
self._mpd.close()
self._mpd.disconnect()
except (MPDConnectionError, ConnectionError) as e:
pass
finally:
self._mpd._reset()
|
Thank you for looking at it! Did you also see my merge request? At least for me it work very robust and it tries to keep the logic of the original library. |
Hi @speendo, I saw it. It might work for your case, but it does not fix the broken Let's assume the connection is broken and In my opinion, |
Nothing? |
Well, @quantenschaum, as far as I get it, I think you simply follow a different approach. While my solution keeps the logic of the original library (not questioning if it makes sense or not), you solve the problem by changing its behavior. When using (my version of) python-mpd2, I do also use a wrapper, because I want my mpd client to stay connected. But this wrapper is implemented in my project not in the library. Nevertheless, your approach also solves the issue and for that I find it much better than the current state of this library. ... however, I guess you wanted @Mic92 to answer your comment, not me... |
Yes, of course, the current behavior is leaving a broken MPDClient when the remote end closes the socket. This is a bug and needs to be fixed = changed. One might make the auto reconnect feature optional, but fixing the broken disconnect method is essential. |
merged in #92 |
Hi and thank you for this project!
When mpd is idle (after calling
client.stop()
) for a couple of hours, I cannot successfully callclient.play()
again. I am aware of ConnectionErrors that can occur so I catch them in my script. In this case, however, I get a BrokenPipeError (sometimes I don't get an error at all, but nevertheless mpd won't start to play reproducibly).I wrote a test script (find it here: https://gist.github.com/speendo/0d9c1a028d045de3f7a6) to track the error down.
I ran this script on my raspberry pi with
nohup python3 test_mpd.py &
.Here's a traceback of the Error (found in nohup.out):
And here's the log:
Can you help me find the source of this problem (or even solve it)?
The text was updated successfully, but these errors were encountered: