sideshowcoder / canned

Server to respond with fake API responses, by using a directory of files for finding out what to say!
213 stars 46 forks source link

Canned server crashed when I try to run a Python script using subprocess module #47

Closed kavithabhaskaran closed 9 years ago

kavithabhaskaran commented 9 years ago

Hi Phil:

I have 2 scenarios here:

Scenario #1 (Works fine).

When I start canned API server on Python >> (Python CLI prompt)

>>> subprocess.Popen(["./startAPIServer"],stdout=subprocess.PIPE)                               
<subprocess.Popen object at 0x7f48c5825b10>

and run the "python add.py" (which does a curl POST) on regular $ prompt, everything works fine and dandy as expected.

$ python add.py
IP is 192.168.1.15
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   165  100   132  100    33   1848    462 --:--:-- --:--:-- --:--:--  1859

Values of Controller IDs and Controller Names that were successfully added.


Scenario #2.(Canned Server crashes and js error)

When I run both startServer script and add.py from python interactive mode,

>>> subprocess.Popen(["./startAPIServer"],stdout=subprocess.PIPE)
<subprocess.Popen object at 0x7f48c5825b10>
>>> subprocess.call("python add.py", shell=True,stderr=subprocess.PIPE)
IP is 192.168.1.15

Values of Controller IDs and Controller Names that were successfully added.

>>> 
events.js:72
        throw er; // Unhandled 'error' event
              ^
Error: write EPIPE
    at errnoException (net.js:901:11)
    at Object.afterWrite (net.js:718:19)

As you have seen, Scenario #2 also works but after 4-5 seconds, I get the error message (which I presume if from Canned) and the Canned server crashes. Would you know why it would crash??

Just to clarify, the "add.py" does this :

proc = subprocess.Popen(["curl -X POST -i -H \"Content-type: application/json\" -X POST http://localhost:8080/v1/controllers -d '{\"url\": \"http://%s:%d\"}'" % (ip, i)], stdout=subprocess.PIPE, shell=True)
(out, error) = proc.communicate()
kavithabhaskaran commented 9 years ago

Looks like a very popular error https://github.com/Clearskyabove/zurb-foundation.docpad/issues/2 - But I am not able to figure out what is causing it exactly since I am not specifically using Grunt..

kavithabhaskaran commented 9 years ago

I was able to resolve it locally by changing all "Popen()" calls with "call()" but I still do not understand why I would get a JS error..

sideshowcoder commented 9 years ago

I edited your original post to make it more readable.

The reason it crashes, as far as I can think is contention around the descriptors while both the python script and canned want to write to stdout. It seems like node is not failing gracefully in this case by just waiting for the this to become available but dies when it fails to write, it could also be the case that python does not hand over the descriptor correctly. Since call actually blocks for the program to finish there is no contention and everything works. This is just a guess as I don't know how I can verify it but this is what seems to be happening, I don't think there is anything I can do from the canned side I think.

Schmelter commented 9 years ago

In case people are still running into this, here's how I solved it. Basically, if I didn't set a STDIN/STDOUT/STDERR for the Popen call, it seemed to work.

Startup.POPEN_CANNED = subprocess.Popen(['canned -p 3000 %s' % props.mockBase], shell=True, preexec_fn=os.setsid)

The POPEN_CANNED variable is just a static class variable to the returned Popen so that I can shutdown canned later with:

Startup.POPEN_CANNED.terminate()
Startup.POPEN_CANNED.wait()

Hope that helps.

sideshowcoder commented 9 years ago

Awesome thanks for the tip! I added it to the wiki.