petervizi / python-eeml

A python package for generating eeml documents.
http://petervizi.github.com/python-eeml
GNU General Public License v3.0
43 stars 11 forks source link

Exception: Service Unavailable #19

Closed dazzag24 closed 11 years ago

dazzag24 commented 11 years ago

Traceback (most recent call last): File "./adafruit-cosm-temp.py", line 106, in pac.put() File "/usr/local/lib/python2.7/dist-packages/Python_EEML-0.1-py2.7.egg/eeml/datastream.py", line 66, in put raise Exception(resp.reason) Exception: Service Unavailable

petervizi commented 11 years ago

Hey dazzag24,

Can you give a little more info? What is the address you are trying to connect to? A code snippet from your script would be great!

Thanks

dazzag24 commented 11 years ago

Hi,

I followed the instructions on Adafruit that allow you to use Python eeml library on a Raspberry Pi.

http://learn.adafruit.com/send-raspberry-pi-data-to-cosm/python-script

This works fine, but every few hours you get an exception. such as the one that I raised.

I notice that you have wrapped the HTTP Code in try/except block, so it shouldn't exit like this?

Thanks

petervizi commented 11 years ago

That's a pretty old version of eeml you're using, you might want to get the latest version, it has better error reporting.

Anyways, as the error message states: "Service Unavailable" - http://www.checkupdown.com/status/E503.html -, so you probably have some problem with your network connection. People have experienced this as you can read in this thread: http://community.cosm.com/node/114 . There is not much I can do on my end.

Let me know is anything is unclear.

Cheers!

dazzag24 commented 11 years ago

I've upgraded to the latest code from: https://github.com/petervizi/python-eeml.git

I've changed the sample adafuit code to use the Cosm method instead of the old Panchube one.

My connection is OK, but regardless I would hope that the code would not throw an exception that make the script exit.

dazzag24 commented 11 years ago

Ooops within a few minutes its crashed again:

pi@livingpi ~/code/adafruit-cosm-temp $ sudo ./adafruit-cosm-temp.py ./adafruit-cosm-temp.py:54: RuntimeWarning: This channel is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings. GPIO.setup(SPIMOSI, GPIO.OUT) ./adafruit-cosm-temp.py:56: RuntimeWarning: This channel is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings. GPIO.setup(SPICLK, GPIO.OUT) ./adafruit-cosm-temp.py:57: RuntimeWarning: This channel is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings. GPIO.setup(SPICS, GPIO.OUT) read_adc0: 215 millivolts: 692 temp_C: 19.3

read_adc0: 215 millivolts: 692 temp_C: 19.3

read_adc0: 215 millivolts: 692 temp_C: 19.3

read_adc0: 216 millivolts: 696 temp_C: 19.6

read_adc0: 215 millivolts: 692 temp_C: 19.3

Traceback (most recent call last): File "./adafruit-cosm-temp.py", line 98, in pac.put() File "/usr/local/lib/python2.7/dist-packages/python_eeml-3.0.0-py2.7.egg/eeml/datastream.py", line 74, in put raise CosmError(msg) eeml.datastream.CosmError: Bad Gateway

dazzag24 commented 11 years ago

Should I be adding my own exception handling code around the pac.put() ?

If so, do you have an example of this?

Thanks

petervizi commented 11 years ago
try:
  pac.put()
except CosmError, e:
  print('There was an error but I dont care about it: {}'.format(e))
petervizi commented 11 years ago

Or better yet, have a quick look at this documentation: http://docs.python.org/2/tutorial/errors.html if that is not clear.

dazzag24 commented 11 years ago

Thanks.... I've added a try/except around the pac/put(). Perhaps you could include this idea in your examples?

I'd imagine most people using this would want it to continue running despite the occasional network outage?

dazzag24 commented 11 years ago

Any ideas?

Traceback (most recent call last): File "./adafruit-cosm-temp.py", line 100, in except CosmError, e:

NameError: name 'CosmError' is not defined

send data to cosm

try: pac.put() except CosmError, e: print('Error in pac.put(): {}'.format(e))

petervizi commented 11 years ago

Well, I don't want to sound rude or anything, but exception handling or exception handling in Python is not really a core topic of this library. Maybe you should raise this issue with the people at adafruit.com?

re NameError: put this in the beginning of the script:

from eeml import CosmError
dazzag24 commented 11 years ago

Hi,

Sorry to keep on about this. I am not that familiar with exception handling in python modules e.g Should exceptions being handled low down in the module or higher up in the app?

I see that you are already doing some try/except in datastream.py. However in my case I seem to be getting exceptions from the conn.getresponse() call which are not currently wrapped:

Traceback (most recent call last): File "./adafruit-cosm-temp.py", line 101, in pac.put() File "/usr/local/lib/python2.7/dist-packages/python_eeml-3.0.0-py2.7.egg/eeml/datastream.py", line 67, in put resp = conn.getresponse() File "/usr/lib/python2.7/httplib.py", line 1034, in getresponse response.begin() File "/usr/lib/python2.7/httplib.py", line 407, in begin version, status, reason = self._read_status() File "/usr/lib/python2.7/httplib.py", line 365, in _read_status line = self.fp.readline() File "/usr/lib/python2.7/socket.py", line 430, in readline data = recv(1) File "/usr/lib/python2.7/ssl.py", line 241, in recv return self.read(buflen) File "/usr/lib/python2.7/ssl.py", line 160, in read return self._sslobj.read(len) ssl.SSLError: The read operation timed out

I can see that some users of the httplib API do wrap their calls in a try/except block. See this Wikipedia wedlinkchecker for example:

https://en.wikipedia.org/wiki/User:JeffGBot/weblinkchecker.py

and another. https://pythonadventures.wordpress.com/2010/10/17/check-if-url-exists/

For now I have handled the exception in the adafruit code thus:

send data to cosm

            try:
                pac.put()
            except CosmError, e:
                print('ERROR: pac.put(): {}'.format(e))
            except StandardError:
                print('ERROR: StandardError')
            except:
                 print('ERROR: Unexpected error: %s' % sys.exc_info()[0])

and it seems that I do have StandardError being caught from time to time.

read_adc0: 214 millivolts: 689 temp_C: 19.0

ERROR: StandardError read_adc0: 214 millivolts: 689 temp_C: 19.0

ERROR: StandardError read_adc0: 214 millivolts: 689 temp_C: 19.0

The main thing is that the script now continues running.

I see you point about contacting the Adafruit people as their instructions should be updated to use the new version of your module. But currently they could still see issues with the script exiting unless the exception is handled somewhere. I am simply trying to determine where the most appropriate place to handle the exception is.

Many thanks for all your help and patience.

petervizi commented 11 years ago

Hey there! The best way I can say is that any exception should be handled wherever there is enough information to do so. It's kind of obvious if you think of an exception as if the programmer said "Brah, you can't divide by zero! Ain't nobody can divide by zero, except for Chuck Norris. Are you Chuck Norris?" or "Man, I really tried my best to contact this server you wanted me, but for some reason I wasn't able to. You'll have to deal with this situation yourself". My point is that at that point in time when the programmer implemented that piece of functionality she did not know how to recover from a certain situation, so she let the user of that functionality know by the means of an exception.

One could use the analogy of a contract. The puat() method of the Cosm object of this library is a contract between me - the developer - and You - the user -. It states that I guarantee that the data you trusted me with will be delivered to the Cosm server except something goes south.

At the time of writing this library I am unable to handle all the multitude of reasons why something may go south: if their server is down I can not go over there and restart it; if the user has given invalid credentials I can't tell her the correct password; if the underlying http lib could not connect I don't have the means to figure out if the user has unplugged her Ethernet cable or she doesn't have Internet subscription at all. So instead of trying to anticipate all that I'll raise an exception with as many information I can and say: Yo User, I wasn't able to deliver your data to Cosm, what do you want to do now?

And at this point the control is in the user's hand. One might want to ignore my exception and let the application exit with error, so she knows that there's a problem needing attention - maybe she has to correct her API key - . An other user might want to give it an other try: catch the first exception, call the put() method again and if that also fails exit. The third user, like yourself, doesn't want the application to exit if the Cosm server is unreachable, just wants to continue with the iteration after 30 seconds. You see, I can't make this decision at the time of writing this library, I have to let the user decide, because she has the information on how to decide. The best I can do is collect as much information as possible: if you look at how the response is handle then there's a part where the response of the server is parsed: this is how the Cosm server reports back if they xml is invalid or the API is incorrect. If there is a problem during connect, well I can't really do anything about it, I don't even catch it and wrap it into CosmError, because there is nothing much information I can add to that exception. And there are an infinite amount of other kinds of exceptions I don't catch either, the information in them is the responsibility of whoever created them, and dealing with them is the responsibility of the user, You.

And that's kids the story of why I don't handle exceptions in the put() method.

Makes any sense?

dazzag24 commented 11 years ago

Thanks.

Yes it makes perfect sense, thanks for taking time to explain your view.

My script is working well now that I am handling the exceptions.

My last polite request would be: Would it make sense to add a new example use case that demonstrates how you would handle exceptions around the put() function?

It would be very useful for people who use your library but find that the script they write keeps exiting due to periodic HTTP issues. In many cases people don't care if they lose a few data points as they want the general trend.

I have given my feedback to adafuit and asked them to upgrade the version of EEML and made them aware of the notion of wrapping put() with try/except.

Thanks again

petervizi commented 11 years ago

If you think such an example would add value to this library you are more than welcome to submit a patch with it. Maybe a section in README.rst would be a good place or a new script in the example/ directory with a reference in the README, your choice. Are you familiar with github's pull request feature?

https://help.github.com/articles/using-pull-requests

dazzag24 commented 11 years ago

I am getting up to speed with github, so will give it a go. Thanks