Olumide
Olumide

Reputation: 5829

SimpleXMLRPCServer.shutdown() failure post request

I recently added a RPC backend to an existing single-threaded application as shown below

lock = Lock()

def update_state(address, value):
    with lock:
        state[address] = value

class ExistingClass:
    def __init__(self, *args, **kwargs):
        thread = Thread(target=self.start_listener)
        thread.start()

    def start_listener(self):
        self.server = SimpleXMLRPCServer(("localhost", 8002) , allow_none=True)
        self.server.register_function(update_state, "update_state")
        self.server.serve_forever()

    def read_state(self, address):
        with lock:
            return state[address]

    def write_state(self, address, value):
        with lock:
            return state[address] = value

ec = ExistingClass()
ec.server.shutdown()

The RPC backend is run in a separate thread to allow the application to keep running.

The problem is that shutting down the application requires explicitly stopping the server and the function SimpleXMLRPCServer.shutdown() does not work after a client has called the PRC update_state i.e. the command ps shows that the process is still alive post shutdown.

Initially I thought the problem could be due to the absence of a lock but that didn't resolve the problem.

Upvotes: 0

Views: 107

Answers (2)

Olumide
Olumide

Reputation: 5829

I found the answer. Turns out to be simple but I'm positing this for posterity.

The RPC thread should be flagged as a daemon, i.e.

thread.daemon = True

This allows the thread to terminate when the RPC server stops.

See this post for more discussions about the daemon property.

Upvotes: 0

Guapi-zh
Guapi-zh

Reputation: 417

The issue you're facing is likely due to the fact that the server is blocked waiting for a client request to be completed. You can create a signal or flag that indicates when the server should stop. To gracefully shutdown the server, You can use a threading.Event for this purpose.

from threading import Thread, Event
from xmlrpc.server import SimpleXMLRPCServer
from xmlrpc.server import SimpleXMLRPCRequestHandler

# ...

class ExistingClass:
    def __init__(self, *args, **kwargs):
        self.shutdown_event = Event()
        thread = Thread(target=self.start_listener)
        thread.start()

    def start_listener(self):
        self.server = SimpleXMLRPCServer(("localhost", 8002), allow_none=True, requestHandler=SimpleXMLRPCRequestHandler)
        self.server.register_function(update_state, "update_state")

        while not self.shutdown_event.is_set():
            self.server.handle_request()  # Handle client requests

    def shutdown(self):
        self.shutdown_event.set()  # Set the shutdown event
        self.server.server_close()  # Close the server socket

# ...

ec = ExistingClass()

# To shut down the server gracefully:
ec.shutdown()

Upvotes: 0

Related Questions