SOLVED

Unable to access brain deployed in docker using python script

Microsoft

I imported exported brain from azure as Docker image.

Ran the container.

Verified the webservice in postman.  Obtained the response.

URL: http://localhost:5000/v1/prediction
Method: Get/Post
Sample Request body:
{
"x_position": 0.31,
"x_velocity": 0.07,
"angle_position": 11.3,
"angle_velocity": 0.8
}

Sample Response:
{
"command": 1.0
}

 

But on calling the endpoint using python code, the program is stuck with no response. Code as follows:

>>> import requests
>>> endpoint = "http://localhost:5000/v1/prediction"
>>> state = {
... "x_position": 0.31,
... "x_velocity": 0.07,
... "angle_position": 11.3,
... "angle_velocity": 0.8
... }
>>> requests.get(endpoint, json=state)

14 Replies

@smartsubbu Thanks for posting the question. I don't see anything obviously wrong with your Python code, but there must be some relevant difference between the postman query and the Python query.

 

I noticed that the postman query says "Method Get/Post", so I'm not sure which of those two methods was used. Exported brains support both get and post, but "post" is the preferred method, and "get" is deprecated (although still theoretically supported). Could you try changing your Python code to use "post" instead? I recommend restarting your brain container before you try sending it a new request.

 

If the "post" doesn't work, then the next step is to look more deeply at how the postman query differs form the query sent via Python.

 

 -Eric

@erictr Thanks for your suggestions.  I have already tried both get and post, but tried again today.  

1. Restarted the container.

2. Verified again in postman with Post method - Pass

3. Ran a python code with Post method and including a header

 

import requests

url = "http://localhost:5000/v1/prediction"
payload={
"x_position": 0.31,
"x_velocity": 0.07,
"angle_position": 11.3,
"angle_velocity": 0.8
}
headers = {
  'Content-Type': 'application/json'
}
print("B4 request")
response = requests.post(url, json=payload, timeout=5)
print(response.text)
print("End of program")
 
with the timeout attribute, I get the following error

B4 request
Traceback (most recent call last):
File "C:\Users\subkris\Miniconda3\lib\site-packages\urllib3\connectionpool.py", line 426, in _make_request
six.raise_from(e, None)
File "<string>", line 3, in raise_from
File "C:\Users\subkris\Miniconda3\lib\site-packages\urllib3\connectionpool.py", line 421, in _make_request
httplib_response = conn.getresponse()
File "C:\Users\subkris\Miniconda3\lib\http\client.py", line 1332, in getresponse
response.begin()
File "C:\Users\subkris\Miniconda3\lib\http\client.py", line 303, in begin
version, status, reason = self._read_status()
File "C:\Users\subkris\Miniconda3\lib\http\client.py", line 264, in _read_status
line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
File "C:\Users\subkris\Miniconda3\lib\socket.py", line 669, in readinto
return self._sock.recv_into(b)
socket.timeout: timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:\Users\subkris\Miniconda3\lib\site-packages\requests\adapters.py", line 439, in send
resp = conn.urlopen(
File "C:\Users\subkris\Miniconda3\lib\site-packages\urllib3\connectionpool.py", line 726, in urlopen
retries = retries.increment(
File "C:\Users\subkris\Miniconda3\lib\site-packages\urllib3\util\retry.py", line 410, in increment
raise six.reraise(type(error), error, _stacktrace)
File "C:\Users\subkris\Miniconda3\lib\site-packages\urllib3\packages\six.py", line 735, in reraise
raise value
File "C:\Users\subkris\Miniconda3\lib\site-packages\urllib3\connectionpool.py", line 670, in urlopen
httplib_response = self._make_request(
File "C:\Users\subkris\Miniconda3\lib\site-packages\urllib3\connectionpool.py", line 428, in _make_request
self._raise_timeout(err=e, url=url, timeout_value=read_timeout)
File "C:\Users\subkris\Miniconda3\lib\site-packages\urllib3\connectionpool.py", line 335, in _raise_timeout
raise ReadTimeoutError(
urllib3.exceptions.ReadTimeoutError: HTTPConnectionPool(host='localhost', port=5000): Read timed out. (read timeout=5)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:\Users\subkris\Miniconda3\lib\runpy.py", line 194, in _run_module_as_main
return _run_code(code, main_globals, None,
File "C:\Users\subkris\Miniconda3\lib\runpy.py", line 87, in _run_code
exec(code, run_globals)
File "c:\Users\subkris\.vscode\extensions\ms-python.python-2021.1.502429796\pythonFiles\lib\python\debugpy\__main__.py", line 45, in <module>
cli.main()
File "c:\Users\subkris\.vscode\extensions\ms-python.python-2021.1.502429796\pythonFiles\lib\python\debugpy/..\debugpy\server\cli.py", line 444, in main
run()
File "c:\Users\subkris\.vscode\extensions\ms-python.python-2021.1.502429796\pythonFiles\lib\python\debugpy/..\debugpy\server\cli.py", line 285, in run_file runpy.run_path(target_as_str, run_name=compat.force_str("__main__"))
File "C:\Users\subkris\Miniconda3\lib\runpy.py", line 265, in run_path
return _run_module_code(code, init_globals, run_name,
File "C:\Users\subkris\Miniconda3\lib\runpy.py", line 97, in _run_module_code
_run_code(code, mod_globals, init_globals,
File "C:\Users\subkris\Miniconda3\lib\runpy.py", line 87, in _run_code
exec(code, run_globals)
File "c:\Learning\Python_Trials\call_service.py", line 17, in <module>
response = requests.post(url, json=payload, timeout=5)
File "C:\Users\subkris\Miniconda3\lib\site-packages\requests\api.py", line 119, in post
return request('post', url, data=data, json=json, **kwargs)
File "C:\Users\subkris\Miniconda3\lib\site-packages\requests\api.py", line 61, in request
return session.request(method=method, url=url, **kwargs)
File "C:\Users\subkris\Miniconda3\lib\site-packages\requests\sessions.py", line 530, in request
resp = self.send(prep, **send_kwargs)
File "C:\Users\subkris\Miniconda3\lib\site-packages\requests\sessions.py", line 643, in send
r = adapter.send(request, **kwargs)
File "C:\Users\subkris\Miniconda3\lib\site-packages\requests\adapters.py", line 529, in send
raise ReadTimeout(e, request=request)
requests.exceptions.ReadTimeout: HTTPConnectionPool(host='localhost', port=5000): Read timed out. (read timeout=5)

 

Without using timeout attribute, the code gets stuck at the request line.

There's clearly something different about postman and the Python `requests` library are formulating the HTTP query. We need to figure out what's going wrong with the latter.

 

Can you confirm that you added the headers to the request? In your sample below, you define `headers`, but you don't pass it in to post call. I don't think that should matter because the documentation for `requests` says that if you pass an argument to the `json` parameter, the `Content-Type` will be set to `application/json` automatically.

 

Another thought is to include the header _and_ manually encode the json payload to ensure that it's properly formed. That way, you can print it out and examine it before it's sent.

```python

json_payload = json.dumps(payload)

print(json_payload)

response = requests.post(url, data=json_payload, headers=headers)

```

 

Another idea is to modify the URL to "http://localhost:5000/v1/dummy" to see if you receive an error or a hang. That will tell us whether you're reaching the HTTP server within the container.

 

 -Eric

@erictr 

I was making several changes and forgot to include header.  But adding the header made no difference.  I changed the code to try other options you suggested

 

import requests
import json

#url = "http://localhost:5000/v1/prediction"
url = "http://localhost:5000/v1/dummy"

payload={
"x_position": 0.31,
"x_velocity": 0.07,
"angle_position": 11.3,
"angle_velocity": 0.8
}
json_payload = json.dumps(payload)
print(json_payload)

headers = {
  'Content-Type': 'application/json'
}

print("B4 request")

response = requests.post(url, data=json_payload, headers=headers)
print(response.text)
print("End of program")
 
Still stuck at the requests line whether correct url or dummy url is specified.  Looks like its not even hitting the endpoint:port
 
{"x_position": 0.31, "x_velocity": 0.07, "angle_position": 11.3, "angle_velocity": 0.8}
B4 request

@erictr The same python code works if I deploy in cloud in a acr and use the azurewebsites.net/v1/prediction url. 

 

{"x_position": 0.31, "x_velocity": 0.07, "angle_position": 11.3, "angle_velocity": 0.8}
B4 request
{"command":1.0}
End of program

@smartsubbu Here's another suggestion from another engineer on our team.

 

Try running:

```

curl -v http::/localhost:5000/v1/status
```
 
If that works, try:
```
curl -v -H "Content-Type: application/json" -d '{"x_position": 0.31, "x_velocity": 0.07, "angle_position": 11.3, "angle_velocity": 0.8}' http://localhost:5000/v1/prediction
```
best response confirmed by smartsubbu (Microsoft)
Solution

Hi @smartsubbu,

 

Do you see this same freezing behavior with a local container only after trying to run it with postman, or regardless of whether you've run with postman or not?  A quick test would be to restart the export brain container then try to access it with either curl or your python script as it's first request.

 

@erictr I tried the first curl command.  After waiting around 10mins gave up.  Its stuck with this message

 

* Trying 127.0.0.1:5000...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 5000 (#0)
> GET /v1/status HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.68.0
> Accept: */*
>

 

Even tried the second command and waited for 5 mins.  No response after this message

* Trying 127.0.0.1:5000...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 5000 (#0)
> POST /v1/prediction HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.68.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 87
>
* upload completely sent off: 87 out of 87 bytes

@chetand I never thought of this.  As you mentioned, I restarted the container and ran both my python program and curl command in bash without verifying in Postman.  Both worked fine.  

 

Curl output:

> --header 'Content-Type: application/json' \
> --data-raw '{
> "x_position": 0.31,
> "x_velocity": 0.07,
> "angle_position": 7.3,
> "angle_velocity": 0.8
> }'
{"command":1.0}

 

Any idea, why running in postman would be creating an issue.  Is it blocking all other connections?

@smartsubbu That's good news!

 

We've found that postman adds a "keep-alive" header by default, and that's what causes this behavior. IIRC, there's a setting in postman to not specify this header.

 

 

Hi @smartsubbu

 

If you do in postman first, wait for 10 minutes and try the curl does it repro?  

The error messages returned are not trivial.
I'm a bit out of the loop however in the error message we are given some help with the following:
B4 request
Traceback (most recent call last):
File "C:\Users\subkris\Miniconda3\lib\site-packages\urllib3\connectionpool.py", line 426, in _make_request
six.raise_from(e, None)
File "<string>", line 3, in raise_from
File "C:\Users\subkris\Miniconda3\lib\site-packages\urllib3\connectionpool.py", line 421, in _make_request
httplib_response = conn.getresponse()
File "C:\Users\subkris\Miniconda3\lib\http\client.py", line 1332, in getresponse
response.begin()
File "C:\Users\subkris\Miniconda3\lib\http\client.py", line 303, in begin
version, status, reason = self._read_status()
File "C:\Users\subkris\Miniconda3\lib\http\client.py", line 264, in _read_status
line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")

A string represents alphanumeric data. This means that a string can contain many different characters, but they are all considered as if they were text, even if the characters are numbers.

Let's continue...

File "C:\Users\subkris\Miniconda3\lib\socket.py", line 669, in readinto
return self._sock.recv_into(b)
socket.timeout: timed out
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\subkris\Miniconda3\lib\site-packages\requests\adapters.py", line 439, in send
resp = conn.urlopen(
File "C:\Users\subkris\Miniconda3\lib\site-packages\urllib3\connectionpool.py", line 726, in urlopen
retries = retries.increment(
File "C:\Users\subkris\Miniconda3\lib\site-packages\urllib3\util\retry.py", line 410, in increment
raise six.reraise(type(error), error, _stacktrace)

So then the error is of a data type.
It's looking like the data being returned to instruct your program to increment trying the url is not returning the data in the expected type, it recieving a string and it wants an integer... and it is...

Iline = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")

So then its a data type that's of the incorrect form ....

@erictr That's great.  I verified myself, disabling that hidden header and running in postman.  Now python code is also able to access.  Thanks for figuring out the root cause.

@Kinshuman Thanks for your suggestion.  I have tried waiting for 10 mins, but have waited for 5 mins several times.  But by verifying other recommendations/suggestions in this thread, the root cause is postman trying to keep the connection alive after a request.  With that header disabled, it works parallelly in both python and postman.