irmen / Pyro4

Pyro 4.x - Python remote objects
http://pyro4.readthedocs.io/
MIT License
715 stars 83 forks source link

Proxy object can be used to invoke methods even after a daemon is shut down #229

Closed msakai closed 4 years ago

msakai commented 4 years ago

I and my colleague @keisuke-nakata noticed that once a proxy object is connected it can be used to invoke methods even after a daemon is shut down.

import Pyro4
import threading
import time

@Pyro4.expose
class GreetingMaker(object):
    def get_fortune(self, name):
        return "Hello, {0}. Here is your fortune message:\n" \
               "Tomorrow's lucky number is 12345678.".format(name)

port = 7766
stop_event = threading.Event()
daemon = Pyro4.Daemon(port=port)

def run_daemon():
    daemon.register(GreetingMaker(), "greeting")
    print("Ready.")
    daemon.requestLoop(loopCondition=lambda: not stop_event.is_set())
    daemon.shutdown()
    print("Shutdown.")

th = threading.Thread(target=run_daemon)
th.start()
time.sleep(1)

obj = Pyro4.Proxy(f'PYRO:greeting@localhost:{port}')
print(obj)
# =>
# <Pyro4.core.Proxy at 0x1097f9278; not connected; for PYRO:greeting@localhost:7766>

print(obj.get_fortune('OK'))
# =>
# Hello, OK. Here is your fortune message:
# Tomorrow's lucky number is 12345678.

print(obj)
# =>
# <Pyro4.core.Proxy at 0x1097f9278; connected IPv4; for PYRO:greeting@localhost:7766>

stop_event.set()
th.join()
time.sleep(1)

print(obj)
# =>
# <Pyro4.core.Proxy at 0x1097f9278; connected IPv4; for PYRO:greeting@localhost:7766>

print(obj.get_fortune('NG'))
# =>
# Hello, NG. Here is your fortune message:
# Tomorrow's lucky number is 12345678.

Is this intended behavior? If so, is there a way to shut down all connections and worker threads? If not, I guess that once a daemon is shut down Daemon.handleRequest should reject further requests and ClientConnectionJob should terminate itself.

irmen commented 4 years ago

I'll have a look, in the meantime, what happens when you use the multiplex servertype instead of the threaded one?

irmen commented 4 years ago

Ah, well yes. This is expected behavior of the threaded server. If you use the multiplex server type, you will see a ConnectionClosedError at the last call.

Why not with the threaded server? Because you shut down the daemon, but keep the proxy connection open to the still-running server thread. The thread won't go away until you close the proxy. You can verify this by trying to create a new proxy and call the method, or by releasing your current one and calling the method again (thereby making Pyro attempt to reconnect). In both cases you will now get a ConnectionClosedError / CommunicationError.

It's not possible to cleanly abort a running thread, so Pyro doesn't try to.