4

Is there a more Pythonic (2.7) way to check the server for a good status_code (200) that doesn't include using while True? My code snippet is as follows - and it's called many times:

    import time
    import json
    from datetime import datetime
    import requests

    while True:
        response = requests.get('http://example.com')
        if response.status_code != 200:
            print 'sleeping:',str(datetime.now()),response.status_code
            print 'sleeping:',str(datetime.now()),response.headers
            time.sleep(5.0)
        else: break
    if "x-mashery-error-code" in response.headers:
        return None
    return response.json()

edit: I included the 'if' loop with the header errors.

5
  • is the utility of this code to check the health of a server? Commented Feb 26, 2014 at 8:47
  • @praveen No, I need the data in response.json(). But the server has a throttle limit and also may send non-200 codes. Commented Feb 26, 2014 at 8:49
  • Use while 1: That is the obvious solution if while True: is the problem. But what is the real problem? Can you write more about that? Commented Feb 26, 2014 at 8:54
  • 'while True' isn't the problem, but I am asking if there is a better practice these days in python Commented Feb 26, 2014 at 8:55
  • 1
    Also have a look at this: stackoverflow.com/questions/14236426/… There is a retry counter that might be in your way in case of throtteling Commented Feb 27, 2014 at 9:37

3 Answers 3

4

You can use Event Hooks

requests.get('http://example.com', hooks=dict(response=check_status))
def check_status(response):
    if response.status_code != 200:
        print 'not yet'
Sign up to request clarification or add additional context in comments.

2 Comments

very nice. the sleep statement could also come inside the 'if' loop?
Well i don't think you really need a sleep... you dispatch a request async this way. If you want to wait until the request has finished you could simply cal another method for the next url when it reaches status 200. You should try to think different ;)
3

I would like this solution:

response = requests.get('http://example.com')
while response.status_code != 200:
    print 'sleeping:',str(datetime.now()),response.status_code
    print 'sleeping:',str(datetime.now()),response.headers
    time.sleep(5.0)
    response = requests.get('http://example.com')

Because:

>>> import this
...
Explicit is better than implicit.
Simple is better than complex.
...
Flat is better than nested.
...
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
...
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
...

Because I read it and understand it right away. With event hooks this is not the case. Do they open a thread to retrieve bytes in parallel? When are they called? Do I need to retrieve the data myself?

5 Comments

I like it, but doesn't that double the number of requests to the server?
This solution has the major disadvantage of doubling your code. If the URL later changes, chances are good that you forget to adjust it in two places (consider these are further apart).
@philshem It does exactly what your code does. @ Alfe I guess you can refactor that into a variable. Or you cen refactor the whole request into a function. You can do it.
@user Ah yes, I see it.
I accepted (and used) this solution because it allows future modification for people that aren't hardcore coders. Also for my purposes, it was easy to add a counter that exits the program after N tries.
1

I'm using aspect-oriented programming by applying decorators for things like doing retries. If my function for getting the value I want looks like this:

def getValue():
  return requests.get('http://example.com')

Then I'm decorating this function to apply the retry mechanism without interfering with the original (naive) code:

def retryUntilCondition(condition):
  def decorate(function):
    def f(*args, **kwargs):
      while True:
        result = function(*args, **kwargs)
        if condition(result):
          return result
        time.sleep(5.0)
    return f
  return decorate

def responseIs200(response):
  return response.status_code == 200

The above is the preparation (part of a utility library), below follows the usage:

@retryUntilCondition(responseIs200)
def getValue():
  return requests.get('http://example.com')

This way the while loop is completely hidden from the application code and does not complicate reading it. The aspect of retrying is added by prepending a simple decorator which can even be reused in other situations.

If later you decide that you only want to retry for a specific number of times, have different delays etc., all this can be implemented in the retry decorator alone.

1 Comment

This is a very elegant solution but I need something that others can later modify.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.