How different nameko run proccesses share one listen socket?

Hi folks!
I am trying to understand how things work behind the scene.
When I run a service that uses HttpEntrypoint it binds to port 8000 and handles requests.
When I start another process in my opinion it is supposed to try to bind to the same port and fail. But it does not fail and actually starts to receive every second request.
I looked in the code of class WebServer:

def start(self):
if not self._starting:
self._starting = True

So I understand that this code creates a listening socket only once allowing many @http entrypoints. So I understand how this works in one memory space of one process.

But how a completely separate process can also share WebServer’s SharedExtension!?

Thx :slight_smile:

When you say “a completely separate process”, you mean a separate Python process, with its own PID right?

Clearly that should not be possible, but have also noticed this behaviour, and I’m confused by it too. I have assumed it’s some problem with eventlet’s .listen(), but I’ve not spent the time to reproduce it or track it down to specific versions of eventlet/Python.

I did a tiny experiment here and verified that this behaviour is all to do with eventlet’s .listen() implementation.

You can run the following in two identical processes and they’ll both happily listen:

import eventlet
eventlet.monkey_patch()

listen_sock = eventlet.listen(("127.0.0.1", 8001))

print("listening")

try:
    while True:
        sock, addr = listen_sock.accept()
        print("new sock", sock, addr)
except KeyboardInterrupt:
    print("quitting")

listen_sock.close()

On my MacOS machine, the last-started process will receive all of the connections; if you terminate that process, the other starts receiving them.

eventlet.listen() accepts kwargs reuse_addr and reuse_port that set SO_REUSEADDR and SO_REUSEPORT respectively on the listening socket. But because they’re both set, regardless of how you invoke the function, SO_REUSEPORT clobbers the role of SO_REUSEADDR in controlling whether or not there’s an error about the port already being in use. The upshot is that passing reuse_addr=False into eventlet.listen doesn’t actually prevent two processes binding to the same port, but passing reuse_port=False does.

The following Stack Overflow post has a really helpful breakdown of what these two options do: linux - How do SO_REUSEADDR and SO_REUSEPORT differ? - Stack Overflow