python-magento icon indicating copy to clipboard operation
python-magento copied to clipboard

SOCK_STREAM Error

Open Bobspadger opened this issue 10 years ago • 7 comments
trafficstars

Occasionally when trying to initiate an API call / or the API (not sure which at present) I get the following:

Traceback (most recent call last):
  File "sales_note_add.py", line 109, in <module>
    main()
  File "sales_note_add.py", line 87, in main
    orderStatus = get_order(orderId)
  File "sales_note_add.py", line 56, in get_order
    order = mage.sales_order.info(order_id)
  File "/Users/mmuser/Documents/magento19-api/magento/__init__.py", line 142, in call_method
    return self._client.call(self._session_id, path, args)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xmlrpclib.py", line 1240, in __call__
    return self.__send(self.__name, args)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xmlrpclib.py", line 1599, in __request
    verbose=self.__verbose
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xmlrpclib.py", line 1280, in request
    return self.single_request(host, handler, request_body, verbose)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xmlrpclib.py", line 1308, in single_request
    self.send_content(h, request_body)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xmlrpclib.py", line 1456, in send_content
    connection.endheaders(request_body)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 1049, in endheaders
    self._send_output(message_body)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 893, in _send_output
    self.send(msg)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 855, in send
    self.connect()
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 1266, in connect
    HTTPConnection.connect(self)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 832, in connect
    self.timeout, self.source_address)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 557, in create_connection
    for res in getaddrinfo(host, port, 0, SOCK_STREAM):
socket.gaierror: [Errno 8] nodename nor servname provided, or not known

I believe this is where our web server has an issue processing the request and throws an error.

It would be good to build into the magento code some form of error handling for broken connections / calls so they are always handled with a retry(?) so its all rolled up in the API call rather than writing it into the functions calling the API (one place for the connection and error handling)

I will try to fix this in the near future but if anyone has noticed this issue and fixed it already then superb!

Bobspadger avatar Jul 29 '15 17:07 Bobspadger

I can replicate these errors by disconnecting from the network and attempting to get a session with magento.

I'm not sure on the best way to handle this exception.

one idea is to enclose each call in a While clause and just keep attempting - example:

while True:
    try:
        orderdetails = magento.sales_order.list(list_info)
    except Exception as e:
        continue
    break

or an example in the actual module

    def __init__(self, host, port, api_user, api_key, path=DEFAULT_XMLRPC_PATH,
                 allow_none=False, verbose=False, proto='http'):
        """Logs the client into Magento's API and discovers methods available
        to it. Throws an exception if logging in fails.
        """

        self._api_user = api_user
        self._api_key = api_key
        self._host = host
        self._port = str(port)
        self._uri = '{}://{}:{}/{}'.format(proto, host, port, path.strip('/'))
        While True:
            try:
                self._client = xmlrpclib.ServerProxy(
                    self._uri, allow_none=allow_none, verbose=verbose)
                self.login()
            except Exception as e:
                print(str(e))
                continue
            break

This example is ok, but could just end up stuck (i've thrown it round one of my own calls for clarity)

Possibly add it into a retry range (attempt it x times?)

Any thoughts appreciated as it would be nice to solve the issue in the module, rather than every time in the different code bases it may be used in.

Alex

Bobspadger avatar Jul 30 '15 19:07 Bobspadger

I would add a class-level variable max_retries, which the user can set on his instance of the api (or on the class if you need it active at the time you initialize the api.) With special cases 0 for no retries and -1 for infinite retries. And I would default this to 0 so as not to change the default behavior as it is now.

Bernard

On 30 July 2015 at 21:35, Bobspadger [email protected] wrote:

I can replicate these errors by disconnecting from the network and attempting to get a session with magento.

I'm not sure on the best way to handle this exception.

one idea is to enclose each call in a While clause and just keep attempting - example:

while True: try: orderdetails = magento.sales_order.list(list_info) except Exception as e: continue break

or an example in the actual module

def __init__(self, host, port, api_user, api_key, path=DEFAULT_XMLRPC_PATH,
             allow_none=False, verbose=False, proto='http'):
    """Logs the client into Magento's API and discovers methods available
    to it. Throws an exception if logging in fails.
    """

    self._api_user = api_user
    self._api_key = api_key
    self._host = host
    self._port = str(port)
    self._uri = '{}://{}:{}/{}'.format(proto, host, port, path.strip('/'))
    While True:
        try:
            self._client = xmlrpclib.ServerProxy(
                self._uri, allow_none=allow_none, verbose=verbose)
            self.login()
        except Exception as e:
            print(str(e))
            continue
        break

This example is ok, but could just end up stuck (i've thrown it round one of my own calls for clarity)

Possibly add it into a retry range (attempt it x times?)

Any thoughts appreciated as it would be nice to solve the issue in the module, rather than every time in the different code bases it may be used in.

Alex

— Reply to this email directly or view it on GitHub https://github.com/bernieke/python-magento/issues/2#issuecomment-126450335 .

bernieke avatar Jul 30 '15 19:07 bernieke

Something like

class MagentoAPI: retries = 0

def init(self): retry = -1 while retry < retries: connect to magento..... retry += 1

crap example but is this what you are anticipating ?

Bobspadger avatar Jul 30 '15 19:07 Bobspadger

hmm I can't add a class level variable and effect it because of the init statement.

(clipped to keep it neat)

class MagentoAPI(object):

    """
    Adding in some ability to deal with errors as they occur in the magento module, rather than each time in any higher code

    max_retries = x where x is number of attempts
    Special cases:
    0 = no retries - first attempt or death
    -1 = infinite , keep going baby!

    """
max_retries = 0 # keep the behaviour of 1 try and then die

    def __init__(self, host, port, api_user, api_key, path=DEFAULT_XMLRPC_PATH,
                 allow_none=False, verbose=False, proto='http'):

if I then attempt

m = MagentoAPI()

I can't create the object as it needs all the credentials.

If I put the max_retries into the __init__ its no longer class level and can not be adjusted later example: m.max_retries=10

or am I confusing myself ?

Bobspadger avatar Jul 30 '15 20:07 Bobspadger

brain freeze evening

magento_api.py

snip:


DEFAULT_XMLRPC_PATH = '/api/xmlrpc'

# Default our max_retries to 0 to keep with the original handling of this module
MAX_RETRIES = 0

snip:

 def __init__(self, host, port, api_user, api_key, path=DEFAULT_XMLRPC_PATH,
                 allow_none=False, verbose=False, proto='http', max_retries=MAX_RETRIES):
        """Logs the client into Magento's API and discovers methods available
        to it. Throws an exception if logging in fails.
        """
        self.max_retries = max_retries

will work on this some more tomorrow

Bobspadger avatar Jul 30 '15 20:07 Bobspadger

I did in fact mean adding it as a class variable (as in your first snippet.)

You then set it either by doing:

m = MagentoAPI(**connection_arguments)
m.max_retries = 3

Or, if you want the max_retries while connecting as well:

MagentoAPI.max_retries = 3
m = MagentoAPI(**connection_arguments)

The reason I'd rather not see max_retries in the init, is because it's not required to setup the connection. (It's not an argument to xmlrpclib.ServerProxy.)

The normal paradigm would be to have the __init__take things like max_retries, and then have a separate connect method which takes the connection arguments. But doing that now would break backwards compatibility, so the second best way to go is to make extraneous things like max_retries class variables.

bernieke avatar Jul 31 '15 05:07 bernieke

Easiest way to replicate is to provide an invalid host name. I was supplying the host as 'http://domainname.com' instead of 'domainname.com'. This triggers the same failure path.

adamlwgriffiths avatar Mar 21 '17 05:03 adamlwgriffiths