pythonerror-handlingproxympd

How to deal with an unavailable host (ConnectionRefusedError) in a proxy class


I have a very basic proxy class (a friend who helped me coding it insists it's a decorator class instead) for python-mpd2.

The class looks like this

import mpd

class MPDProxy:
    def __init__(self, host="localhost", port=6600, timeout=10):
        self.client = mpd.MPDClient()
        self.host = host
        self.port = port

        self.client.timeout = timeout
        self.connect(host, port)

    def __getattr__(self, name):
        return self._call_with_reconnect(getattr(self.client, name))

    def connect(self, host, port):
        self.client.connect(host, port)

    def _call_with_reconnect(self, func):
        def wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except mpd.ConnectionError:
                self.connect(self.host, self.port)
                return func(*args, **kwargs)
        return wrapper

mpd_proxy = MPDProxy()

This works well so far, as long as there is an mpd host available to connect to. If there is no mpd server, I get

ConnectionRefusedError: [Errno 111] Connection refused

I'm looking for good patterns to deal with this Exception


Solution

  • Can you think of an elegant way to prevent the program to crash, when there is no host available?

    try ... except ;)


    Should I catch the exception within the proxy or outside, whenever the proxy is called?

    The question you should ask yourself is "who is *able* to deal with that exception?"


    Obviously, the proxy can't to anything sensible to "fix" ConnectionRefusedError. So it has to be handled at upper levels.


    Is a string "Host not available" (or similar) as a return value a good idea or can a method/function calling the proxy be informed in a better way?

    Bad idea. The normal way of informing "upper levels" than an exception has occurred is to raise an exception. Or to let a raised exception propagate up.


    Concretely:

    class MPDProxy:
        def _call_with_reconnect(self, func):
            def wrapper(*args, **kwargs):
                try:
                    return func(*args, **kwargs)
                except mpd.ConnectionError:
                    self.connect(self.host, self.port)
                    # ^^^^^^ This lime might raise `ConnectionRefusedError`
                    # as there is no `except` block around, this exception
                    # is automatically propagated     
    
                    return func(*args, **kwargs)
            return wrapper
    
    try:
        mpd_proxy = MPDProxy()
        r = mdp_proxy._call_with_reconnect(whatever)
    except ConnectionRefusedError:
        do_somesible_sensible()