jgehrcke / gipc

gevent-cooperative child processes and inter-process communication
https://gehrcke.de/gipc
MIT License
83 stars 13 forks source link

Sockets kept open by child process #22

Open jgehrcke opened 8 years ago

jgehrcke commented 8 years ago

Originally reported by: eurleif (Bitbucket: eurleif, GitHub: Unknown)


Here's a toy example which accepts TCP connections on port 12345. For each connection, it spawns a child process, which sleeps for 5 seconds before exiting. It does not pass the socket into the child process. In the parent process, it sends a message to the client, and closes the socket.

My expected behavior when connecting to this server is for it to send me the message, then immediately close the connection. In reality, it sends me the message, then waits 5 seconds before closing the connection. It seems as though the socket is being kept open by the child process, even though the socket was not passed to it.

I've tested this with Python 2.7 and 3.5, with gevent 1.1.2 and gipc 0.6.0, on Ubuntu 16.04.

Is this intended behavior? I certainly find it unexpected, since the docs mention closing handles.

#!python

from gevent import sleep, spawn
from gevent.server import StreamServer
import gipc

def child():
    sleep(5)

def handle(socket, address):
    gipc.start_process(target=child)
    socket.sendall(b'Spawned a child process. Good bye!\r\n')
    socket.close()

if __name__ == '__main__':
    server = StreamServer(('127.0.0.1', 12345), handle)
    server.serve_forever()

jgehrcke commented 8 years ago

Original comment by eurleif (Bitbucket: eurleif, GitHub: Unknown):


Thanks, that does make sense -- but I think the docs should mention it. I almost pushed broken code to my project since I thought gipc would close all handles.

Great work on gipc, btw. Very useful.

jgehrcke commented 8 years ago

Original comment by Jan-Philip Gehrcke (Bitbucket: jgehrcke, GitHub: jgehrcke):


Thanks for reporting that. Only gipc-related handles that are not explicitly passed to children are automatically closed in children, i.e. those of type gipc._GIPCHandle. Regarding all other file descriptors inherited during a fork, there is no magic approach that tries to automatically infer which ones the application wants to retain and which ones it does not (that's an ill-posed problem). You have to take care of these yourself.

Does that make sense?

Thanks for using gipc!

On a related note, now that gevent 1.1.x has equilibrated (a lot changed under the hood recently), I will also take care of gipc again in the near future and see if anything needs to change (and take care of processing the open issues).